diff --git a/jre_emul/android/platform/libcore/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/NoSuchElementExceptionTest.java b/jre_emul/android/platform/libcore/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/NoSuchElementExceptionTest.java index 7727f3f6c3..161dada795 100644 --- a/jre_emul/android/platform/libcore/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/NoSuchElementExceptionTest.java +++ b/jre_emul/android/platform/libcore/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/NoSuchElementExceptionTest.java @@ -1,18 +1,18 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.apache.harmony.tests.java.util; @@ -46,7 +46,7 @@ public void test_ConstructorLjava_lang_String() { // Test for method java.util.NoSuchElementException(java.lang.String) assertNotNull(new NoSuchElementException("String")); - assertNotNull(new NoSuchElementException(null)); + assertNotNull(new NoSuchElementException((String)null)); try { Vector v = new Vector(); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractCollection.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractCollection.java index 6ea9224820..bfefdb338e 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractCollection.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -26,30 +26,30 @@ package java.util; /** - * This class provides a skeletal implementation of the Collection + * This class provides a skeletal implementation of the {@code Collection} * interface, to minimize the effort required to implement this interface.

* * To implement an unmodifiable collection, the programmer needs only to - * extend this class and provide implementations for the iterator and - * size methods. (The iterator returned by the iterator - * method must implement hasNext and next.)

+ * extend this class and provide implementations for the {@code iterator} and + * {@code size} methods. (The iterator returned by the {@code iterator} + * method must implement {@code hasNext} and {@code next}.)

* * To implement a modifiable collection, the programmer must additionally - * override this class's add method (which otherwise throws an - * UnsupportedOperationException), and the iterator returned by the - * iterator method must additionally implement its remove + * override this class's {@code add} method (which otherwise throws an + * {@code UnsupportedOperationException}), and the iterator returned by the + * {@code iterator} method must additionally implement its {@code remove} * method.

* * The programmer should generally provide a void (no argument) and - * Collection constructor, as per the recommendation in the - * Collection interface specification.

+ * {@code Collection} constructor, as per the recommendation in the + * {@code Collection} interface specification.

* * The documentation for each non-abstract method in this class describes its * implementation in detail. Each of these methods may be overridden if * the collection being implemented admits a more efficient implementation.

* * This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -80,7 +80,8 @@ protected AbstractCollection() { /** * {@inheritDoc} * - *

This implementation returns size() == 0. + * @implSpec + * This implementation returns {@code size() == 0}. */ public boolean isEmpty() { return size() == 0; @@ -89,7 +90,8 @@ public boolean isEmpty() { /** * {@inheritDoc} * - *

This implementation iterates over the elements in the collection, + * @implSpec + * This implementation iterates over the elements in the collection, * checking each element in turn for equality with the specified element. * * @throws ClassCastException {@inheritDoc} @@ -112,7 +114,8 @@ public boolean contains(Object o) { /** * {@inheritDoc} * - *

This implementation returns an array containing all the elements + * @implSpec + * This implementation returns an array containing all the elements * returned by this collection's iterator, in the same order, stored in * consecutive elements of the array, starting with index {@code 0}. * The length of the returned array is equal to the number of elements @@ -139,7 +142,8 @@ public native Object[] toArray() /*-[ /** * {@inheritDoc} * - *

This implementation returns an array containing all the elements + * @implSpec + * This implementation returns an array containing all the elements * returned by this collection's iterator in the same order, stored in * consecutive elements of the array, starting with index {@code 0}. * If the number of elements returned by the iterator is too large to @@ -226,8 +230,9 @@ private static int hugeCapacity(int minCapacity) { /** * {@inheritDoc} * - *

This implementation always throws an - * UnsupportedOperationException. + * @implSpec + * This implementation always throws an + * {@code UnsupportedOperationException}. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} @@ -242,13 +247,14 @@ public boolean add(E e) { /** * {@inheritDoc} * - *

This implementation iterates over the collection looking for the + * @implSpec + * This implementation iterates over the collection looking for the * specified element. If it finds the element, it removes the element * from the collection using the iterator's remove method. * *

Note that this implementation throws an - * UnsupportedOperationException if the iterator returned by this - * collection's iterator method does not implement the remove + * {@code UnsupportedOperationException} if the iterator returned by this + * collection's iterator method does not implement the {@code remove} * method and this collection contains the specified object. * * @throws UnsupportedOperationException {@inheritDoc} @@ -281,10 +287,11 @@ public boolean remove(Object o) { /** * {@inheritDoc} * - *

This implementation iterates over the specified collection, + * @implSpec + * This implementation iterates over the specified collection, * checking each element returned by the iterator in turn to see * if it's contained in this collection. If all elements are so - * contained true is returned, otherwise false. + * contained {@code true} is returned, otherwise {@code false}. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} @@ -300,11 +307,12 @@ public boolean containsAll(Collection c) { /** * {@inheritDoc} * - *

This implementation iterates over the specified collection, and adds + * @implSpec + * This implementation iterates over the specified collection, and adds * each object returned by the iterator to this collection, in turn. * *

Note that this implementation will throw an - * UnsupportedOperationException unless add is + * {@code UnsupportedOperationException} unless {@code add} is * overridden (assuming the specified collection is non-empty). * * @throws UnsupportedOperationException {@inheritDoc} @@ -326,14 +334,15 @@ public boolean addAll(Collection c) { /** * {@inheritDoc} * - *

This implementation iterates over this collection, checking each + * @implSpec + * This implementation iterates over this collection, checking each * element returned by the iterator in turn to see if it's contained * in the specified collection. If it's so contained, it's removed from - * this collection with the iterator's remove method. + * this collection with the iterator's {@code remove} method. * *

Note that this implementation will throw an - * UnsupportedOperationException if the iterator returned by the - * iterator method does not implement the remove method + * {@code UnsupportedOperationException} if the iterator returned by the + * {@code iterator} method does not implement the {@code remove} method * and this collection contains one or more elements in common with the * specified collection. * @@ -360,14 +369,15 @@ public boolean removeAll(Collection c) { /** * {@inheritDoc} * - *

This implementation iterates over this collection, checking each + * @implSpec + * This implementation iterates over this collection, checking each * element returned by the iterator in turn to see if it's contained * in the specified collection. If it's not so contained, it's removed - * from this collection with the iterator's remove method. + * from this collection with the iterator's {@code remove} method. * *

Note that this implementation will throw an - * UnsupportedOperationException if the iterator returned by the - * iterator method does not implement the remove method + * {@code UnsupportedOperationException} if the iterator returned by the + * {@code iterator} method does not implement the {@code remove} method * and this collection contains one or more elements not present in the * specified collection. * @@ -394,15 +404,16 @@ public boolean retainAll(Collection c) { /** * {@inheritDoc} * - *

This implementation iterates over this collection, removing each - * element using the Iterator.remove operation. Most + * @implSpec + * This implementation iterates over this collection, removing each + * element using the {@code Iterator.remove} operation. Most * implementations will probably choose to override this method for * efficiency. * *

Note that this implementation will throw an - * UnsupportedOperationException if the iterator returned by this - * collection's iterator method does not implement the - * remove method and this collection is non-empty. + * {@code UnsupportedOperationException} if the iterator returned by this + * collection's {@code iterator} method does not implement the + * {@code remove} method and this collection is non-empty. * * @throws UnsupportedOperationException {@inheritDoc} */ @@ -421,8 +432,8 @@ public void clear() { * Returns a string representation of this collection. The string * representation consists of a list of the collection's elements in the * order they are returned by its iterator, enclosed in square brackets - * ("[]"). Adjacent elements are separated by the characters - * ", " (comma and space). Elements are converted to strings as + * ({@code "[]"}). Adjacent elements are separated by the characters + * {@code ", "} (comma and space). Elements are converted to strings as * by {@link String#valueOf(Object)}. * * @return a string representation of this collection diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractList.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractList.java index 951dc9a493..11925b3162 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractList.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -62,7 +62,7 @@ * collection being implemented admits a more efficient implementation. * *

This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -374,7 +374,7 @@ public E next() { return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); - throw new NoSuchElementException(); + throw new NoSuchElementException(e); } } @@ -418,7 +418,7 @@ public E previous() { return previous; } catch (IndexOutOfBoundsException e) { checkForComodification(); - throw new NoSuchElementException(); + throw new NoSuchElementException(e); } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractMap.java index e275726505..3f4ab5448a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -34,24 +34,24 @@ ]-*/ /** - * This class provides a skeletal implementation of the Map + * This class provides a skeletal implementation of the {@code Map} * interface, to minimize the effort required to implement this interface. * *

To implement an unmodifiable map, the programmer needs only to extend this - * class and provide an implementation for the entrySet method, which + * class and provide an implementation for the {@code entrySet} method, which * returns a set-view of the map's mappings. Typically, the returned set - * will, in turn, be implemented atop AbstractSet. This set should - * not support the add or remove methods, and its iterator - * should not support the remove method. + * will, in turn, be implemented atop {@code AbstractSet}. This set should + * not support the {@code add} or {@code remove} methods, and its iterator + * should not support the {@code remove} method. * *

To implement a modifiable map, the programmer must additionally override - * this class's put method (which otherwise throws an - * UnsupportedOperationException), and the iterator returned by - * entrySet().iterator() must additionally implement its - * remove method. + * this class's {@code put} method (which otherwise throws an + * {@code UnsupportedOperationException}), and the iterator returned by + * {@code entrySet().iterator()} must additionally implement its + * {@code remove} method. * *

The programmer should generally provide a void (no argument) and map - * constructor, as per the recommendation in the Map interface + * constructor, as per the recommendation in the {@code Map} interface * specification. * *

The documentation for each non-abstract method in this class describes its @@ -59,7 +59,7 @@ * map being implemented admits a more efficient implementation. * *

This class is a member of the - * + * * Java Collections Framework. * * @param the type of keys maintained by this map @@ -86,7 +86,7 @@ protected AbstractMap() { * {@inheritDoc} * * @implSpec - * This implementation returns entrySet().size(). + * This implementation returns {@code entrySet().size()}. */ public int size() { return entrySet().size(); @@ -96,7 +96,7 @@ public int size() { * {@inheritDoc} * * @implSpec - * This implementation returns size() == 0. + * This implementation returns {@code size() == 0}. */ public boolean isEmpty() { return size() == 0; @@ -106,10 +106,10 @@ public boolean isEmpty() { * {@inheritDoc} * * @implSpec - * This implementation iterates over entrySet() searching + * This implementation iterates over {@code entrySet()} searching * for an entry with the specified value. If such an entry is found, - * true is returned. If the iteration terminates without - * finding such an entry, false is returned. Note that this + * {@code true} is returned. If the iteration terminates without + * finding such an entry, {@code false} is returned. Note that this * implementation requires linear time in the size of the map. * * @throws ClassCastException {@inheritDoc} @@ -137,10 +137,10 @@ public boolean containsValue(Object value) { * {@inheritDoc} * * @implSpec - * This implementation iterates over entrySet() searching + * This implementation iterates over {@code entrySet()} searching * for an entry with the specified key. If such an entry is found, - * true is returned. If the iteration terminates without - * finding such an entry, false is returned. Note that this + * {@code true} is returned. If the iteration terminates without + * finding such an entry, {@code false} is returned. Note that this * implementation requires linear time in the size of the map; many * implementations will override this method. * @@ -169,10 +169,10 @@ public boolean containsKey(Object key) { * {@inheritDoc} * * @implSpec - * This implementation iterates over entrySet() searching + * This implementation iterates over {@code entrySet()} searching * for an entry with the specified key. If such an entry is found, * the entry's value is returned. If the iteration terminates without - * finding such an entry, null is returned. Note that this + * finding such an entry, {@code null} is returned. Note that this * implementation requires linear time in the size of the map; many * implementations will override this method. * @@ -205,7 +205,7 @@ public V get(Object key) { * * @implSpec * This implementation always throws an - * UnsupportedOperationException. + * {@code UnsupportedOperationException}. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} @@ -220,18 +220,18 @@ public V put(K key, V value) { * {@inheritDoc} * * @implSpec - * This implementation iterates over entrySet() searching for an + * This implementation iterates over {@code entrySet()} searching for an * entry with the specified key. If such an entry is found, its value is - * obtained with its getValue operation, the entry is removed + * obtained with its {@code getValue} operation, the entry is removed * from the collection (and the backing map) with the iterator's - * remove operation, and the saved value is returned. If the - * iteration terminates without finding such an entry, null is + * {@code remove} operation, and the saved value is returned. If the + * iteration terminates without finding such an entry, {@code null} is * returned. Note that this implementation requires linear time in the * size of the map; many implementations will override this method. * *

Note that this implementation throws an - * UnsupportedOperationException if the entrySet - * iterator does not support the remove method and this map + * {@code UnsupportedOperationException} if the {@code entrySet} + * iterator does not support the {@code remove} method and this map * contains a mapping for the specified key. * * @throws UnsupportedOperationException {@inheritDoc} @@ -271,12 +271,12 @@ public V remove(Object key) { * * @implSpec * This implementation iterates over the specified map's - * entrySet() collection, and calls this map's put + * {@code entrySet()} collection, and calls this map's {@code put} * operation once for each entry returned by the iteration. * *

Note that this implementation throws an - * UnsupportedOperationException if this map does not support - * the put operation and the specified map is nonempty. + * {@code UnsupportedOperationException} if this map does not support + * the {@code put} operation and the specified map is nonempty. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} @@ -292,11 +292,11 @@ public void putAll(Map m) { * {@inheritDoc} * * @implSpec - * This implementation calls entrySet().clear(). + * This implementation calls {@code entrySet().clear()}. * *

Note that this implementation throws an - * UnsupportedOperationException if the entrySet - * does not support the clear operation. + * {@code UnsupportedOperationException} if the {@code entrySet} + * does not support the {@code clear} operation. * * @throws UnsupportedOperationException {@inheritDoc} */ @@ -331,8 +331,8 @@ public void clear() { * } *} */ - transient volatile Set keySet = null; - transient volatile Collection values = null; + transient Set keySet; + transient Collection values; /** * {@inheritDoc} @@ -340,10 +340,10 @@ public void clear() { * @implSpec * This implementation returns a set that subclasses {@link AbstractSet}. * The subclass's iterator method returns a "wrapper object" over this - * map's entrySet() iterator. The size method - * delegates to this map's size method and the - * contains method delegates to this map's - * containsKey method. + * map's {@code entrySet()} iterator. The {@code size} method + * delegates to this map's {@code size} method and the + * {@code contains} method delegates to this map's + * {@code containsKey} method. * *

The set is created the first time this method is called, * and returned in response to all subsequent calls. No synchronization @@ -401,10 +401,10 @@ public boolean contains(Object k) { * @implSpec * This implementation returns a collection that subclasses {@link * AbstractCollection}. The subclass's iterator method returns a - * "wrapper object" over this map's entrySet() iterator. - * The size method delegates to this map's size - * method and the contains method delegates to this map's - * containsValue method. + * "wrapper object" over this map's {@code entrySet()} iterator. + * The {@code size} method delegates to this map's {@code size} + * method and the {@code contains} method delegates to this map's + * {@code containsValue} method. * *

The collection is created the first time this method is called, and * returned in response to all subsequent calls. No synchronization is @@ -463,25 +463,25 @@ public boolean contains(Object v) { /** * Compares the specified object with this map for equality. Returns - * true if the given object is also a map and the two maps - * represent the same mappings. More formally, two maps m1 and - * m2 represent the same mappings if - * m1.entrySet().equals(m2.entrySet()). This ensures that the - * equals method works properly across different implementations - * of the Map interface. + * {@code true} if the given object is also a map and the two maps + * represent the same mappings. More formally, two maps {@code m1} and + * {@code m2} represent the same mappings if + * {@code m1.entrySet().equals(m2.entrySet())}. This ensures that the + * {@code equals} method works properly across different implementations + * of the {@code Map} interface. * * @implSpec * This implementation first checks if the specified object is this map; - * if so it returns true. Then, it checks if the specified + * if so it returns {@code true}. Then, it checks if the specified * object is a map whose size is identical to the size of this map; if - * not, it returns false. If so, it iterates over this map's - * entrySet collection, and checks that the specified map + * not, it returns {@code false}. If so, it iterates over this map's + * {@code entrySet} collection, and checks that the specified map * contains each mapping that this map contains. If the specified map - * fails to contain such a mapping, false is returned. If the - * iteration completes, true is returned. + * fails to contain such a mapping, {@code false} is returned. If the + * iteration completes, {@code true} is returned. * * @param o object to be compared for equality with this map - * @return true if the specified object is equal to this map + * @return {@code true} if the specified object is equal to this map */ public boolean equals(Object o) { if (o == this) @@ -494,13 +494,11 @@ public boolean equals(Object o) { return false; try { - Iterator> i = entrySet().iterator(); - while (i.hasNext()) { - Entry e = i.next(); + for (Entry e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { - if (!(m.get(key)==null && m.containsKey(key))) + if (!(m.get(key) == null && m.containsKey(key))) return false; } else { if (!value.equals(m.get(key))) @@ -519,13 +517,13 @@ public boolean equals(Object o) { /** * Returns the hash code value for this map. The hash code of a map is * defined to be the sum of the hash codes of each entry in the map's - * entrySet() view. This ensures that m1.equals(m2) - * implies that m1.hashCode()==m2.hashCode() for any two maps - * m1 and m2, as required by the general contract of + * {@code entrySet()} view. This ensures that {@code m1.equals(m2)} + * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps + * {@code m1} and {@code m2}, as required by the general contract of * {@link Object#hashCode}. * * @implSpec - * This implementation iterates over entrySet(), calling + * This implementation iterates over {@code entrySet()}, calling * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the * set, and adding up the results. * @@ -536,19 +534,18 @@ public boolean equals(Object o) { */ public int hashCode() { int h = 0; - Iterator> i = entrySet().iterator(); - while (i.hasNext()) - h += i.next().hashCode(); + for (Entry entry : entrySet()) + h += entry.hashCode(); return h; } /** * Returns a string representation of this map. The string representation * consists of a list of key-value mappings in the order returned by the - * map's entrySet view's iterator, enclosed in braces - * ("{}"). Adjacent mappings are separated by the characters - * ", " (comma and space). Each key-value mapping is rendered as - * the key followed by an equals sign ("=") followed by the + * map's {@code entrySet} view's iterator, enclosed in braces + * ({@code "{}"}). Adjacent mappings are separated by the characters + * {@code ", "} (comma and space). Each key-value mapping is rendered as + * the key followed by an equals sign ({@code "="}) followed by the * associated value. Keys and values are converted to strings as by * {@link String#valueOf(Object)}. * @@ -575,7 +572,7 @@ public String toString() { } /** - * Returns a shallow copy of this AbstractMap instance: the keys + * Returns a shallow copy of this {@code AbstractMap} instance: the keys * and values themselves are not cloned. * * @return a shallow copy of this map @@ -607,11 +604,11 @@ private static boolean eq(Object o1, Object o2) { /** * An Entry maintaining a key and a value. The value may be - * changed using the setValue method. This class + * changed using the {@code setValue} method. This class * facilitates the process of building custom map * implementations. For example, it may be convenient to return - * arrays of SimpleEntry instances in method - * Map.entrySet().toArray. + * arrays of {@code SimpleEntry} instances in method + * {@code Map.entrySet().toArray}. * * @since 1.6 */ @@ -726,7 +723,7 @@ public int hashCode() { /** * Returns a String representation of this map entry. This * implementation returns the string representation of this - * entry's key followed by the equals character ("=") + * entry's key followed by the equals character ("{@code =}") * followed by the string representation of this entry's value. * * @return a String representation of this map entry @@ -739,7 +736,7 @@ public String toString() { /** * An Entry maintaining an immutable key and value. This class - * does not support method setValue. This class may be + * does not support method {@code setValue}. This class may be * convenient in methods that return thread-safe snapshots of * key-value mappings. * @@ -797,7 +794,7 @@ public V getValue() { /** * Replaces the value corresponding to this entry with the specified * value (optional operation). This implementation simply throws - * UnsupportedOperationException, as this class implements + * {@code UnsupportedOperationException}, as this class implements * an immutable map entry. * * @param value new value to be stored in this entry @@ -857,7 +854,7 @@ public int hashCode() { /** * Returns a String representation of this map entry. This * implementation returns the string representation of this - * entry's key followed by the equals character ("=") + * entry's key followed by the equals character ("{@code =}") * followed by the string representation of this entry's value. * * @return a String representation of this map entry diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSequentialList.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSequentialList.java index 36a91dabaa..91ce740141 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSequentialList.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSequentialList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -26,35 +26,35 @@ package java.util; /** - * This class provides a skeletal implementation of the List + * This class provides a skeletal implementation of the {@code List} * interface to minimize the effort required to implement this interface * backed by a "sequential access" data store (such as a linked list). For - * random access data (such as an array), AbstractList should be used + * random access data (such as an array), {@code AbstractList} should be used * in preference to this class.

* - * This class is the opposite of the AbstractList class in the sense - * that it implements the "random access" methods (get(int index), - * set(int index, E element), add(int index, E element) and - * remove(int index)) on top of the list's list iterator, instead of + * This class is the opposite of the {@code AbstractList} class in the sense + * that it implements the "random access" methods ({@code get(int index)}, + * {@code set(int index, E element)}, {@code add(int index, E element)} and + * {@code remove(int index)}) on top of the list's list iterator, instead of * the other way around.

* * To implement a list the programmer needs only to extend this class and - * provide implementations for the listIterator and size + * provide implementations for the {@code listIterator} and {@code size} * methods. For an unmodifiable list, the programmer need only implement the - * list iterator's hasNext, next, hasPrevious, - * previous and index methods.

+ * list iterator's {@code hasNext}, {@code next}, {@code hasPrevious}, + * {@code previous} and {@code index} methods.

* * For a modifiable list the programmer should additionally implement the list - * iterator's set method. For a variable-size list the programmer - * should additionally implement the list iterator's remove and - * add methods.

+ * iterator's {@code set} method. For a variable-size list the programmer + * should additionally implement the list iterator's {@code remove} and + * {@code add} methods.

* * The programmer should generally provide a void (no argument) and collection - * constructor, as per the recommendation in the Collection interface + * constructor, as per the recommendation in the {@code Collection} interface * specification.

* * This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -78,8 +78,8 @@ protected AbstractSequentialList() { * Returns the element at the specified position in this list. * *

This implementation first gets a list iterator pointing to the - * indexed element (with listIterator(index)). Then, it gets - * the element using ListIterator.next and returns it. + * indexed element (with {@code listIterator(index)}). Then, it gets + * the element using {@code ListIterator.next} and returns it. * * @throws IndexOutOfBoundsException {@inheritDoc} */ @@ -96,13 +96,13 @@ public E get(int index) { * specified element (optional operation). * *

This implementation first gets a list iterator pointing to the - * indexed element (with listIterator(index)). Then, it gets - * the current element using ListIterator.next and replaces it - * with ListIterator.set. + * indexed element (with {@code listIterator(index)}). Then, it gets + * the current element using {@code ListIterator.next} and replaces it + * with {@code ListIterator.set}. * *

Note that this implementation will throw an - * UnsupportedOperationException if the list iterator does not - * implement the set operation. + * {@code UnsupportedOperationException} if the list iterator does not + * implement the {@code set} operation. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} @@ -128,12 +128,12 @@ public E set(int index, E element) { * indices). * *

This implementation first gets a list iterator pointing to the - * indexed element (with listIterator(index)). Then, it - * inserts the specified element with ListIterator.add. + * indexed element (with {@code listIterator(index)}). Then, it + * inserts the specified element with {@code ListIterator.add}. * *

Note that this implementation will throw an - * UnsupportedOperationException if the list iterator does not - * implement the add operation. + * {@code UnsupportedOperationException} if the list iterator does not + * implement the {@code add} operation. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} @@ -156,12 +156,12 @@ public void add(int index, E element) { * list. * *

This implementation first gets a list iterator pointing to the - * indexed element (with listIterator(index)). Then, it removes - * the element with ListIterator.remove. + * indexed element (with {@code listIterator(index)}). Then, it removes + * the element with {@code ListIterator.remove}. * *

Note that this implementation will throw an - * UnsupportedOperationException if the list iterator does not - * implement the remove operation. + * {@code UnsupportedOperationException} if the list iterator does not + * implement the {@code remove} operation. * * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} @@ -193,14 +193,14 @@ public E remove(int index) { * *

This implementation gets an iterator over the specified collection and * a list iterator over this list pointing to the indexed element (with - * listIterator(index)). Then, it iterates over the specified + * {@code listIterator(index)}). Then, it iterates over the specified * collection, inserting the elements obtained from the iterator into this - * list, one at a time, using ListIterator.add followed by - * ListIterator.next (to skip over the added element). + * list, one at a time, using {@code ListIterator.add} followed by + * {@code ListIterator.next} (to skip over the added element). * *

Note that this implementation will throw an - * UnsupportedOperationException if the list iterator returned by - * the listIterator method does not implement the add + * {@code UnsupportedOperationException} if the list iterator returned by + * the {@code listIterator} method does not implement the {@code add} * operation. * * @throws UnsupportedOperationException {@inheritDoc} @@ -213,9 +213,8 @@ public boolean addAll(int index, Collection c) { try { boolean modified = false; ListIterator e1 = listIterator(index); - Iterator e2 = c.iterator(); - while (e2.hasNext()) { - e1.add(e2.next()); + for (E e : c) { + e1.add(e); modified = true; } return modified; @@ -244,7 +243,7 @@ public Iterator iterator() { * sequence). * * @param index index of first element to be returned from the list - * iterator (by a call to the next method) + * iterator (by a call to the {@code next} method) * @return a list iterator over the elements in this list (in proper * sequence) * @throws IndexOutOfBoundsException {@inheritDoc} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSet.java index b3fe0dc0bf..80d4c5e91d 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/AbstractSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -26,23 +26,23 @@ package java.util; /** - * This class provides a skeletal implementation of the Set + * This class provides a skeletal implementation of the {@code Set} * interface to minimize the effort required to implement this * interface.

* * The process of implementing a set by extending this class is identical * to that of implementing a Collection by extending AbstractCollection, * except that all of the methods and constructors in subclasses of this - * class must obey the additional constraints imposed by the Set + * class must obey the additional constraints imposed by the {@code Set} * interface (for instance, the add method must not permit addition of * multiple instances of an object to a set).

* * Note that this class does not override any of the implementations from - * the AbstractCollection class. It merely adds implementations - * for equals and hashCode.

+ * the {@code AbstractCollection} class. It merely adds implementations + * for {@code equals} and {@code hashCode}.

* * This class is a member of the - * + * * Java Collections Framework. * * @param the type of elements maintained by this set @@ -67,20 +67,20 @@ protected AbstractSet() { /** * Compares the specified object with this set for equality. Returns - * true if the given object is also a set, the two sets have + * {@code true} if the given object is also a set, the two sets have * the same size, and every member of the given set is contained in - * this set. This ensures that the equals method works - * properly across different implementations of the Set + * this set. This ensures that the {@code equals} method works + * properly across different implementations of the {@code Set} * interface.

* * This implementation first checks if the specified object is this - * set; if so it returns true. Then, it checks if the + * set; if so it returns {@code true}. Then, it checks if the * specified object is a set whose size is identical to the size of * this set; if not, it returns false. If so, it returns - * containsAll((Collection) o). + * {@code containsAll((Collection) o)}. * * @param o object to be compared for equality with this set - * @return true if the specified object is equal to this set + * @return {@code true} if the specified object is equal to this set */ public boolean equals(Object o) { if (o == this) @@ -93,9 +93,7 @@ public boolean equals(Object o) { return false; try { return containsAll(c); - } catch (ClassCastException unused) { - return false; - } catch (NullPointerException unused) { + } catch (ClassCastException | NullPointerException unused) { return false; } } @@ -103,14 +101,14 @@ public boolean equals(Object o) { /** * Returns the hash code value for this set. The hash code of a set is * defined to be the sum of the hash codes of the elements in the set, - * where the hash code of a null element is defined to be zero. - * This ensures that s1.equals(s2) implies that - * s1.hashCode()==s2.hashCode() for any two sets s1 - * and s2, as required by the general contract of + * where the hash code of a {@code null} element is defined to be zero. + * This ensures that {@code s1.equals(s2)} implies that + * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1} + * and {@code s2}, as required by the general contract of * {@link Object#hashCode}. * *

This implementation iterates over the set, calling the - * hashCode method on each element in the set, and adding up + * {@code hashCode} method on each element in the set, and adding up * the results. * * @return the hash code value for this set @@ -136,24 +134,24 @@ public int hashCode() { * the two sets. * *

This implementation determines which is the smaller of this set - * and the specified collection, by invoking the size + * and the specified collection, by invoking the {@code size} * method on each. If this set has fewer elements, then the * implementation iterates over this set, checking each element * returned by the iterator in turn to see if it is contained in * the specified collection. If it is so contained, it is removed - * from this set with the iterator's remove method. If + * from this set with the iterator's {@code remove} method. If * the specified collection has fewer elements, then the * implementation iterates over the specified collection, removing * from this set each element returned by the iterator, using this - * set's remove method. + * set's {@code remove} method. * *

Note that this implementation will throw an - * UnsupportedOperationException if the iterator returned by the - * iterator method does not implement the remove method. + * {@code UnsupportedOperationException} if the iterator returned by the + * {@code iterator} method does not implement the {@code remove} method. * * @param c collection containing elements to be removed from this set - * @return true if this set changed as a result of the call - * @throws UnsupportedOperationException if the removeAll operation + * @return {@code true} if this set changed as a result of the call + * @throws UnsupportedOperationException if the {@code removeAll} operation * is not supported by this set * @throws ClassCastException if the class of an element of this set * is incompatible with the specified collection @@ -170,8 +168,8 @@ public boolean removeAll(Collection c) { boolean modified = false; if (size() > c.size()) { - for (Iterator i = c.iterator(); i.hasNext(); ) - modified |= remove(i.next()); + for (Object e : c) + modified |= remove(e); } else { for (Iterator i = iterator(); i.hasNext(); ) { if (c.contains(i.next())) { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArrayList.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArrayList.java index 273dfef3c2..d67000e617 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArrayList.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArrayList.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -31,33 +31,33 @@ import java.util.function.UnaryOperator; /** - * Resizable-array implementation of the List interface. Implements + * Resizable-array implementation of the {@code List} interface. Implements * all optional list operations, and permits all elements, including - * null. In addition to implementing the List interface, + * {@code null}. In addition to implementing the {@code List} interface, * this class provides methods to manipulate the size of the array that is * used internally to store the list. (This class is roughly equivalent to - * Vector, except that it is unsynchronized.) + * {@code Vector}, except that it is unsynchronized.) * - *

The size, isEmpty, get, set, - * iterator, and listIterator operations run in constant - * time. The add operation runs in amortized constant time, + *

The {@code size}, {@code isEmpty}, {@code get}, {@code set}, + * {@code iterator}, and {@code listIterator} operations run in constant + * time. The {@code add} operation runs in amortized constant time, * that is, adding n elements requires O(n) time. All of the other operations * run in linear time (roughly speaking). The constant factor is low compared - * to that for the LinkedList implementation. + * to that for the {@code LinkedList} implementation. * - *

Each ArrayList instance has a capacity. The capacity is + *

Each {@code ArrayList} instance has a capacity. The capacity is * the size of the array used to store the elements in the list. It is always * at least as large as the list size. As elements are added to an ArrayList, * its capacity grows automatically. The details of the growth policy are not * specified beyond the fact that adding an element has constant amortized * time cost. * - *

An application can increase the capacity of an ArrayList instance - * before adding a large number of elements using the ensureCapacity + *

An application can increase the capacity of an {@code ArrayList} instance + * before adding a large number of elements using the {@code ensureCapacity} * operation. This may reduce the amount of incremental reallocation. * *

Note that this implementation is not synchronized. - * If multiple threads access an ArrayList instance concurrently, + * If multiple threads access an {@code ArrayList} instance concurrently, * and at least one of the threads modifies the list structurally, it * must be synchronized externally. (A structural modification is * any operation that adds or deletes one or more elements, or explicitly @@ -71,9 +71,9 @@ * unsynchronized access to the list:

  *   List list = Collections.synchronizedList(new ArrayList(...));
* - *

+ *

* The iterators returned by this class's {@link #iterator() iterator} and - * {@link #listIterator(int) listIterator} methods are fail-fast: + * {@link #listIterator(int) listIterator} methods are fail-fast: * if the list is structurally modified at any time after the iterator is * created, in any way except through the iterator's own * {@link ListIterator#remove() remove} or @@ -92,9 +92,11 @@ * should be used only to detect bugs. * *

This class is a member of the - * + * * Java Collections Framework. * + * @param the type of elements in this list + * * @author Josh Bloch * @author Neal Gafter * @see Collection @@ -103,18 +105,10 @@ * @see Vector * @since 1.2 */ -// Android-changed: Inlined methods; CME in iterators; throw AIOOBE when toIndex < fromIndex. +// Android-changed: CME in iterators; /* - * - AOSP commit 3be987f0f18648b3c532c8b89d09505e18594241 - * Inline for improved performance: - * - checkForComodification - * - elementData() - * - rangeCheck() - * - rangeCheckForAdd() * - AOSP commit b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194 * Fix ConcurrentModificationException in ArrayList iterators. - * - AOSP commit a68b1a5ba82ef8cc19aafdce7d9c7f9631943f84 - * Throw AIOOBE when toIndex < fromIndex. */ public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable @@ -188,21 +182,23 @@ public ArrayList() { * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection c) { - elementData = c.toArray(); - if ((size = elementData.length) != 0) { - // c.toArray might (incorrectly) not return Object[] (see 6260652) - if (elementData.getClass() != Object[].class) - elementData = Arrays.copyOf(elementData, size, Object[].class); + Object[] a = c.toArray(); + if ((size = a.length) != 0) { + if (c.getClass() == ArrayList.class) { + elementData = a; + } else { + elementData = Arrays.copyOf(a, size, Object[].class); + } } else { // replace with empty array. - this.elementData = EMPTY_ELEMENTDATA; + elementData = EMPTY_ELEMENTDATA; } } /** - * Trims the capacity of this ArrayList instance to be the + * Trims the capacity of this {@code ArrayList} instance to be the * list's current size. An application can use this operation to minimize - * the storage of an ArrayList instance. + * the storage of an {@code ArrayList} instance. */ public void trimToSize() { modCount++; @@ -214,43 +210,23 @@ public void trimToSize() { } /** - * Increases the capacity of this ArrayList instance, if + * Increases the capacity of this {@code ArrayList} instance, if * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * - * @param minCapacity the desired minimum capacity + * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { - int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) - // any size if not default element table - ? 0 - // larger than default for default empty table. It's already - // supposed to be at default size. - : DEFAULT_CAPACITY; - - if (minCapacity > minExpand) { - ensureExplicitCapacity(minCapacity); - } - } - - private void ensureCapacityInternal(int minCapacity) { - if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { - minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); - } - - ensureExplicitCapacity(minCapacity); - } - - private void ensureExplicitCapacity(int minCapacity) { - modCount++; - - // overflow-conscious code - if (minCapacity - elementData.length > 0) + if (minCapacity > elementData.length + && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA + && minCapacity <= DEFAULT_CAPACITY)) { + modCount++; grow(minCapacity); + } } /** - * The maximum size of array to allocate. + * The maximum size of array to allocate (unless necessary). * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit @@ -262,25 +238,48 @@ private void ensureExplicitCapacity(int minCapacity) { * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if minCapacity is less than zero */ - private void grow(int minCapacity) { + private Object[] grow(int minCapacity) { + return elementData = Arrays.copyOf(elementData, + newCapacity(minCapacity)); + } + + private Object[] grow() { + return grow(size + 1); + } + + /** + * Returns a capacity at least as large as the given minimum capacity. + * Returns the current capacity increased by 50% if that suffices. + * Will not return a capacity greater than MAX_ARRAY_SIZE unless + * the given minimum capacity is greater than MAX_ARRAY_SIZE. + * + * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if minCapacity is less than zero + */ + private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); - if (newCapacity - minCapacity < 0) - newCapacity = minCapacity; - if (newCapacity - MAX_ARRAY_SIZE > 0) - newCapacity = hugeCapacity(minCapacity); - // minCapacity is usually close to size, so this is a win: - elementData = Arrays.copyOf(elementData, newCapacity); + if (newCapacity - minCapacity <= 0) { + if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) + return Math.max(DEFAULT_CAPACITY, minCapacity); + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return minCapacity; + } + return (newCapacity - MAX_ARRAY_SIZE <= 0) + ? newCapacity + : hugeCapacity(minCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); - return (minCapacity > MAX_ARRAY_SIZE) ? - Integer.MAX_VALUE : - MAX_ARRAY_SIZE; + return (minCapacity > MAX_ARRAY_SIZE) + ? Integer.MAX_VALUE + : MAX_ARRAY_SIZE; } /** @@ -293,22 +292,22 @@ public int size() { } /** - * Returns true if this list contains no elements. + * Returns {@code true} if this list contains no elements. * - * @return true if this list contains no elements + * @return {@code true} if this list contains no elements */ public boolean isEmpty() { return size == 0; } /** - * Returns true if this list contains the specified element. - * More formally, returns true if and only if this list contains - * at least one element e such that - * (o==null ? e==null : o.equals(e)). + * Returns {@code true} if this list contains the specified element. + * More formally, returns {@code true} if and only if this list contains + * at least one element {@code e} such that + * {@code Objects.equals(o, e)}. * * @param o element whose presence in this list is to be tested - * @return true if this list contains the specified element + * @return {@code true} if this list contains the specified element */ public boolean contains(Object o) { return indexOf(o) >= 0; @@ -317,19 +316,28 @@ public boolean contains(Object o) { /** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. - * More formally, returns the lowest index i such that - * (o==null ? get(i)==null : o.equals(get(i))), + * More formally, returns the lowest index {@code i} such that + * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. */ public int indexOf(Object o) { + return indexOfRange(o, 0, size); + } + + int indexOfRange(Object o, int start, int end) { + Object[] es = elementData; if (o == null) { - for (int i = 0; i < size; i++) - if (elementData[i]==null) + for (int i = start; i < end; i++) { + if (es[i] == null) { return i; + } + } } else { - for (int i = 0; i < size; i++) - if (o.equals(elementData[i])) + for (int i = start; i < end; i++) { + if (o.equals(es[i])) { return i; + } + } } return -1; } @@ -337,28 +345,37 @@ public int indexOf(Object o) { /** * Returns the index of the last occurrence of the specified element * in this list, or -1 if this list does not contain the element. - * More formally, returns the highest index i such that - * (o==null ? get(i)==null : o.equals(get(i))), + * More formally, returns the highest index {@code i} such that + * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. */ public int lastIndexOf(Object o) { + return lastIndexOfRange(o, 0, size); + } + + int lastIndexOfRange(Object o, int start, int end) { + Object[] es = elementData; if (o == null) { - for (int i = size-1; i >= 0; i--) - if (elementData[i]==null) + for (int i = end - 1; i >= start; i--) { + if (es[i] == null) { return i; + } + } } else { - for (int i = size-1; i >= 0; i--) - if (o.equals(elementData[i])) + for (int i = end - 1; i >= start; i--) { + if (o.equals(es[i])) { return i; + } + } } return -1; } /** - * Returns a shallow copy of this ArrayList instance. (The + * Returns a shallow copy of this {@code ArrayList} instance. (The * elements themselves are not copied.) * - * @return a clone of this ArrayList instance + * @return a clone of this {@code ArrayList} instance */ public Object clone() { try { @@ -401,7 +418,7 @@ public Object[] toArray() { *

If the list fits in the specified array with room to spare * (i.e., the array has more elements than the list), the element in * the array immediately following the end of the collection is set to - * null. (This is useful in determining the length of the + * {@code null}. (This is useful in determining the length of the * list only if the caller knows that the list does not contain * any null elements.) * @@ -425,6 +442,18 @@ public T[] toArray(T[] a) { return a; } + // Positional Access Operations + + @SuppressWarnings("unchecked") + E elementData(int index) { + return (E) elementData[index]; + } + + @SuppressWarnings("unchecked") + static E elementAt(Object[] es, int index) { + return (E) es[index]; + } + /** * Returns the element at the specified position in this list. * @@ -433,10 +462,8 @@ public T[] toArray(T[] a) { * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { - if (index >= size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - - return (E) elementData[index]; + Objects.checkIndex(index, size); + return elementData(index); } /** @@ -449,23 +476,33 @@ public E get(int index) { * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { - if (index >= size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - - E oldValue = (E) elementData[index]; + Objects.checkIndex(index, size); + E oldValue = elementData(index); elementData[index] = element; return oldValue; } + /** + * This helper method split out from add(E) to keep method + * bytecode size under 35 (the -XX:MaxInlineSize default value), + * which helps when add(E) is called in a C1-compiled loop. + */ + private void add(E e, Object[] elementData, int s) { + if (s == elementData.length) + elementData = grow(); + elementData[s] = e; + size = s + 1; + } + /** * Appends the specified element to the end of this list. * * @param e element to be appended to this list - * @return true (as specified by {@link Collection#add}) + * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { - ensureCapacityInternal(size + 1); // Increments modCount!! - elementData[size++] = e; + modCount++; + add(e, elementData, size); return true; } @@ -479,14 +516,17 @@ public boolean add(E e) { * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { - if (index > size || index < 0) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - - ensureCapacityInternal(size + 1); // Increments modCount!! - System.arraycopy(elementData, index, elementData, index + 1, - size - index); + rangeCheckForAdd(index); + modCount++; + final int s; + Object[] elementData; + if ((s = size) == (elementData = this.elementData).length) + elementData = grow(); + System.arraycopy(elementData, index, + elementData, index + 1, + s - index); elementData[index] = element; - size++; + size = s + 1; } /** @@ -499,62 +539,145 @@ public void add(int index, E element) { * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { - if (index >= size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + Objects.checkIndex(index, size); + final Object[] es = elementData; - modCount++; - E oldValue = (E) elementData[index]; - - int numMoved = size - index - 1; - if (numMoved > 0) - System.arraycopy(elementData, index+1, elementData, index, - numMoved); - elementData[--size] = null; // clear to let GC do its work + @SuppressWarnings("unchecked") E oldValue = (E) es[index]; + fastRemove(es, index); return oldValue; } + /** + * {@inheritDoc} + */ + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof List)) { + return false; + } + + final int expectedModCount = modCount; + // ArrayList can be subclassed and given arbitrary behavior, but we can + // still deal with the common case where o is ArrayList precisely + boolean equal = (o.getClass() == ArrayList.class) + ? equalsArrayList((ArrayList) o) + : equalsRange((List) o, 0, size); + + checkForComodification(expectedModCount); + return equal; + } + + boolean equalsRange(List other, int from, int to) { + final Object[] es = elementData; + if (to > es.length) { + throw new ConcurrentModificationException(); + } + var oit = other.iterator(); + for (; from < to; from++) { + if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) { + return false; + } + } + return !oit.hasNext(); + } + + private boolean equalsArrayList(ArrayList other) { + final int otherModCount = other.modCount; + final int s = size; + boolean equal; + if (equal = (s == other.size)) { + final Object[] otherEs = other.elementData; + final Object[] es = elementData; + if (s > es.length || s > otherEs.length) { + throw new ConcurrentModificationException(); + } + for (int i = 0; i < s; i++) { + if (!Objects.equals(es[i], otherEs[i])) { + equal = false; + break; + } + } + } + other.checkForComodification(otherModCount); + return equal; + } + + private void checkForComodification(final int expectedModCount) { + if (modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + /** + * {@inheritDoc} + */ + public int hashCode() { + int expectedModCount = modCount; + int hash = hashCodeRange(0, size); + checkForComodification(expectedModCount); + return hash; + } + + int hashCodeRange(int from, int to) { + final Object[] es = elementData; + if (to > es.length) { + throw new ConcurrentModificationException(); + } + int hashCode = 1; + for (int i = from; i < to; i++) { + Object e = es[i]; + hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); + } + return hashCode; + } + /** * Removes the first occurrence of the specified element from this list, * if it is present. If the list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index - * i such that - * (o==null ? get(i)==null : o.equals(get(i))) - * (if such an element exists). Returns true if this list + * {@code i} such that + * {@code Objects.equals(o, get(i))} + * (if such an element exists). Returns {@code true} if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present - * @return true if this list contained the specified element + * @return {@code true} if this list contained the specified element */ public boolean remove(Object o) { - if (o == null) { - for (int index = 0; index < size; index++) - if (elementData[index] == null) { - fastRemove(index); - return true; - } - } else { - for (int index = 0; index < size; index++) - if (o.equals(elementData[index])) { - fastRemove(index); - return true; - } + final Object[] es = elementData; + final int size = this.size; + int i = 0; + found: { + if (o == null) { + for (; i < size; i++) + if (es[i] == null) + break found; + } else { + for (; i < size; i++) + if (o.equals(es[i])) + break found; + } + return false; } - return false; + fastRemove(es, i); + return true; } - /* + /** * Private remove method that skips bounds checking and does not * return the value removed. */ - private void fastRemove(int index) { + private void fastRemove(Object[] es, int i) { modCount++; - int numMoved = size - index - 1; - if (numMoved > 0) - System.arraycopy(elementData, index+1, elementData, index, - numMoved); - elementData[--size] = null; // clear to let GC do its work + final int newSize; + if ((newSize = size - 1) > i) + System.arraycopy(es, i + 1, es, i, newSize - i); + es[size = newSize] = null; } /** @@ -563,12 +686,9 @@ private void fastRemove(int index) { */ public void clear() { modCount++; - - // clear to let GC do its work - for (int i = 0; i < size; i++) - elementData[i] = null; - - size = 0; + final Object[] es = elementData; + for (int to = size, i = size = 0; i < to; i++) + es[i] = null; } /** @@ -581,16 +701,22 @@ public void clear() { * list is nonempty.) * * @param c collection containing elements to be added to this list - * @return true if this list changed as a result of the call + * @return {@code true} if this list changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean addAll(Collection c) { Object[] a = c.toArray(); + modCount++; int numNew = a.length; - ensureCapacityInternal(size + numNew); // Increments modCount - System.arraycopy(a, 0, elementData, size, numNew); - size += numNew; - return numNew != 0; + if (numNew == 0) + return false; + Object[] elementData; + final int s; + if (numNew > (elementData = this.elementData).length - (s = size)) + elementData = grow(s + numNew); + System.arraycopy(a, 0, elementData, s, numNew); + size = s + numNew; + return true; } /** @@ -604,26 +730,31 @@ public boolean addAll(Collection c) { * @param index index at which to insert the first element from the * specified collection * @param c collection containing elements to be added to this list - * @return true if this list changed as a result of the call + * @return {@code true} if this list changed as a result of the call * @throws IndexOutOfBoundsException {@inheritDoc} * @throws NullPointerException if the specified collection is null */ public boolean addAll(int index, Collection c) { - if (index > size || index < 0) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + rangeCheckForAdd(index); Object[] a = c.toArray(); + modCount++; int numNew = a.length; - ensureCapacityInternal(size + numNew); // Increments modCount + if (numNew == 0) + return false; + Object[] elementData; + final int s; + if (numNew > (elementData = this.elementData).length - (s = size)) + elementData = grow(s + numNew); - int numMoved = size - index; + int numMoved = s - index; if (numMoved > 0) - System.arraycopy(elementData, index, elementData, index + numNew, + System.arraycopy(elementData, index, + elementData, index + numNew, numMoved); - System.arraycopy(a, 0, elementData, index, numNew); - size += numNew; - return numNew != 0; + size = s + numNew; + return true; } /** @@ -636,29 +767,31 @@ public boolean addAll(int index, Collection c) { * @throws IndexOutOfBoundsException if {@code fromIndex} or * {@code toIndex} is out of range * ({@code fromIndex < 0 || - * fromIndex >= size() || * toIndex > size() || * toIndex < fromIndex}) */ protected void removeRange(int fromIndex, int toIndex) { - // Android-changed: Throw an IOOBE if toIndex < fromIndex as documented. - // All the other cases (negative indices, or indices greater than the size - // will be thrown by System#arrayCopy. - if (toIndex < fromIndex) { - throw new IndexOutOfBoundsException("toIndex < fromIndex"); + if (fromIndex > toIndex) { + throw new IndexOutOfBoundsException( + outOfBoundsMsg(fromIndex, toIndex)); } - modCount++; - int numMoved = size - toIndex; - System.arraycopy(elementData, toIndex, elementData, fromIndex, - numMoved); + shiftTailOverGap(elementData, fromIndex, toIndex); + } - // clear to let GC do its work - int newSize = size - (toIndex-fromIndex); - for (int i = newSize; i < size; i++) { - elementData[i] = null; - } - size = newSize; + /** Erases the gap from lo to hi, by sliding down following elements. */ + private void shiftTailOverGap(Object[] es, int lo, int hi) { + System.arraycopy(es, hi, es, lo, size - hi); + for (int to = size, i = (size -= hi - lo); i < to; i++) + es[i] = null; + } + + /** + * A version of rangeCheck used by add and addAll. + */ + private void rangeCheckForAdd(int index) { + if (index > size || index < 0) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** @@ -670,6 +803,13 @@ private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; } + /** + * A version used in checking (fromIndex > toIndex) condition + */ + private static String outOfBoundsMsg(int fromIndex, int toIndex) { + return "From Index: " + fromIndex + " > To Index: " + toIndex; + } + /** * Removes from this list all of its elements that are contained in the * specified collection. @@ -686,8 +826,7 @@ private String outOfBoundsMsg(int index) { * @see Collection#contains(Object) */ public boolean removeAll(Collection c) { - Objects.requireNonNull(c); - return batchRemove(c, false); + return batchRemove(c, false, 0, size); } /** @@ -707,54 +846,56 @@ public boolean removeAll(Collection c) { * @see Collection#contains(Object) */ public boolean retainAll(Collection c) { - Objects.requireNonNull(c); - return batchRemove(c, true); + return batchRemove(c, true, 0, size); } - private boolean batchRemove(Collection c, boolean complement) { - final Object[] elementData = this.elementData; - int r = 0, w = 0; - boolean modified = false; + boolean batchRemove(Collection c, boolean complement, + final int from, final int end) { + Objects.requireNonNull(c); + final Object[] es = elementData; + int r; + // Optimize for initial run of survivors + for (r = from;; r++) { + if (r == end) + return false; + if (c.contains(es[r]) != complement) + break; + } + int w = r++; try { - for (; r < size; r++) - if (c.contains(elementData[r]) == complement) - elementData[w++] = elementData[r]; - } finally { + for (Object e; r < end; r++) + if (c.contains(e = es[r]) == complement) + es[w++] = e; + } catch (Throwable ex) { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. - if (r != size) { - System.arraycopy(elementData, r, - elementData, w, - size - r); - w += size - r; - } - if (w != size) { - // clear to let GC do its work - for (int i = w; i < size; i++) - elementData[i] = null; - modCount += size - w; - size = w; - modified = true; - } + System.arraycopy(es, r, es, w, end - r); + w += end - r; + throw ex; + } finally { + modCount += end - w; + shiftTailOverGap(es, w, end); } - return modified; + return true; } /** - * Save the state of the ArrayList instance to a stream (that - * is, serialize it). + * Saves the state of the {@code ArrayList} instance to a stream + * (that is, serializes it). * - * @serialData The length of the array backing the ArrayList + * @param s the stream + * @throws java.io.IOException if an I/O error occurs + * @serialData The length of the array backing the {@code ArrayList} * instance is emitted (int), followed by all of its elements - * (each an Object) in the proper order. + * (each an {@code Object}) in the proper order. */ private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException{ + throws java.io.IOException { // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); - // Write out size as capacity for behavioural compatibility with clone() + // Write out size as capacity for behavioral compatibility with clone() s.writeInt(size); // Write out all elements in the proper order. @@ -768,12 +909,15 @@ private void writeObject(java.io.ObjectOutputStream s) } /** - * Reconstitute the ArrayList instance from a stream (that is, - * deserialize it). + * Reconstitutes the {@code ArrayList} instance from a stream (that is, + * deserializes it). + * @param s the stream + * @throws ClassNotFoundException if the class of a serialized object + * could not be found + * @throws java.io.IOException if an I/O error occurs */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - elementData = EMPTY_ELEMENTDATA; // Read in size, and any hidden stuff s.defaultReadObject(); @@ -782,14 +926,21 @@ private void readObject(java.io.ObjectInputStream s) s.readInt(); // ignored if (size > 0) { - // be like clone(), allocate array based upon size not capacity - ensureCapacityInternal(size); + // like clone(), allocate array based upon size not capacity + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // sun.misc.SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size); + Object[] elements = new Object[size]; - Object[] a = elementData; // Read in all elements in the proper order. - for (int i=0; i listIterator(int index) { - if (index < 0 || index > size) - throw new IndexOutOfBoundsException("Index: "+index); + rangeCheckForAdd(index); return new ListItr(index); } @@ -850,14 +1000,16 @@ private class Itr implements Iterator { int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; + // prevent creating a synthetic constructor + Itr() {} + public boolean hasNext() { return cursor < limit; } @SuppressWarnings("unchecked") public E next() { - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); + checkForComodification(); int i = cursor; if (i >= limit) throw new NoSuchElementException(); @@ -871,8 +1023,7 @@ public E next() { public void remove() { if (lastRet < 0) throw new IllegalStateException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); + checkForComodification(); try { ArrayList.this.remove(lastRet); @@ -886,25 +1037,24 @@ public void remove() { } @Override - @SuppressWarnings("unchecked") - public void forEachRemaining(Consumer consumer) { - Objects.requireNonNull(consumer); + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); final int size = ArrayList.this.size; int i = cursor; - if (i >= size) { - return; - } - final Object[] elementData = ArrayList.this.elementData; - if (i >= elementData.length) { - throw new ConcurrentModificationException(); - } - while (i != size && modCount == expectedModCount) { - consumer.accept((E) elementData[i++]); + if (i < size) { + final Object[] es = elementData; + if (i >= es.length) + throw new ConcurrentModificationException(); + for (; i < size && modCount == expectedModCount; i++) + action.accept(elementAt(es, i)); + // update once at end to reduce heap write traffic + cursor = i; + lastRet = i - 1; + checkForComodification(); } - // update once at end of iteration to reduce heap write traffic - cursor = i; - lastRet = i - 1; + } + final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } @@ -933,8 +1083,7 @@ public int previousIndex() { @SuppressWarnings("unchecked") public E previous() { - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); + checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); @@ -948,8 +1097,7 @@ public E previous() { public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); + checkForComodification(); try { ArrayList.this.set(lastRet, e); @@ -959,8 +1107,7 @@ public void set(E e) { } public void add(E e) { - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); + checkForComodification(); try { int i = cursor; @@ -1006,86 +1153,75 @@ public void add(E e) { */ public List subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); - return new SubList(this, 0, fromIndex, toIndex); + return new SubList<>(this, fromIndex, toIndex); } - static void subListRangeCheck(int fromIndex, int toIndex, int size) { - if (fromIndex < 0) - throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); - if (toIndex > size) - throw new IndexOutOfBoundsException("toIndex = " + toIndex); - if (fromIndex > toIndex) - throw new IllegalArgumentException("fromIndex(" + fromIndex + - ") > toIndex(" + toIndex + ")"); - } - - private class SubList extends AbstractList implements RandomAccess { - private final AbstractList parent; - private final int parentOffset; + private static class SubList extends AbstractList implements RandomAccess { + private final ArrayList root; + private final SubList parent; private final int offset; - int size; + private int size; + + /** + * Constructs a sublist of an arbitrary ArrayList. + */ + public SubList(ArrayList root, int fromIndex, int toIndex) { + this.root = root; + this.parent = null; + this.offset = fromIndex; + this.size = toIndex - fromIndex; + this.modCount = root.modCount; + } - SubList(AbstractList parent, - int offset, int fromIndex, int toIndex) { + /** + * Constructs a sublist of another SubList. + */ + private SubList(SubList parent, int fromIndex, int toIndex) { + this.root = parent.root; this.parent = parent; - this.parentOffset = fromIndex; - this.offset = offset + fromIndex; + this.offset = parent.offset + fromIndex; this.size = toIndex - fromIndex; - this.modCount = ArrayList.this.modCount; + this.modCount = parent.modCount; } - public E set(int index, E e) { - if (index < 0 || index >= this.size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - E oldValue = (E) ArrayList.this.elementData[offset + index]; - ArrayList.this.elementData[offset + index] = e; + public E set(int index, E element) { + Objects.checkIndex(index, size); + checkForComodification(); + E oldValue = root.elementData(offset + index); + root.elementData[offset + index] = element; return oldValue; } public E get(int index) { - if (index < 0 || index >= this.size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - return (E) ArrayList.this.elementData[offset + index]; + Objects.checkIndex(index, size); + checkForComodification(); + return root.elementData(offset + index); } public int size() { - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - return this.size; + checkForComodification(); + return size; } - public void add(int index, E e) { - if (index < 0 || index > this.size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - parent.add(parentOffset + index, e); - this.modCount = parent.modCount; - this.size++; + public void add(int index, E element) { + rangeCheckForAdd(index); + checkForComodification(); + root.add(offset + index, element); + updateSizeAndModCount(1); } public E remove(int index) { - if (index < 0 || index >= this.size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - E result = parent.remove(parentOffset + index); - this.modCount = parent.modCount; - this.size--; + Objects.checkIndex(index, size); + checkForComodification(); + E result = root.remove(offset + index); + updateSizeAndModCount(-1); return result; } protected void removeRange(int fromIndex, int toIndex) { - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - parent.removeRange(parentOffset + fromIndex, - parentOffset + toIndex); - this.modCount = parent.modCount; - this.size -= toIndex - fromIndex; + checkForComodification(); + root.removeRange(offset + fromIndex, offset + toIndex); + updateSizeAndModCount(fromIndex - toIndex); } public boolean addAll(Collection c) { @@ -1093,35 +1229,112 @@ public boolean addAll(Collection c) { } public boolean addAll(int index, Collection c) { - if (index < 0 || index > this.size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + rangeCheckForAdd(index); int cSize = c.size(); if (cSize==0) return false; - - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - parent.addAll(parentOffset + index, c); - this.modCount = parent.modCount; - this.size += cSize; + checkForComodification(); + root.addAll(offset + index, c); + updateSizeAndModCount(cSize); return true; } + public void replaceAll(UnaryOperator operator) { + root.replaceAllRange(operator, offset, offset + size); + } + + public boolean removeAll(Collection c) { + return batchRemove(c, false); + } + + public boolean retainAll(Collection c) { + return batchRemove(c, true); + } + + private boolean batchRemove(Collection c, boolean complement) { + checkForComodification(); + int oldSize = root.size; + boolean modified = + root.batchRemove(c, complement, offset, offset + size); + if (modified) + updateSizeAndModCount(root.size - oldSize); + return modified; + } + + public boolean removeIf(Predicate filter) { + checkForComodification(); + int oldSize = root.size; + boolean modified = root.removeIf(filter, offset, offset + size); + if (modified) + updateSizeAndModCount(root.size - oldSize); + return modified; + } + + public Object[] toArray() { + checkForComodification(); + return Arrays.copyOfRange(root.elementData, offset, offset + size); + } + + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + checkForComodification(); + if (a.length < size) + return (T[]) Arrays.copyOfRange( + root.elementData, offset, offset + size, a.getClass()); + System.arraycopy(root.elementData, offset, a, 0, size); + if (a.length > size) + a[size] = null; + return a; + } + + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof List)) { + return false; + } + + boolean equal = root.equalsRange((List)o, offset, offset + size); + checkForComodification(); + return equal; + } + + public int hashCode() { + int hash = root.hashCodeRange(offset, offset + size); + checkForComodification(); + return hash; + } + + public int indexOf(Object o) { + int index = root.indexOfRange(o, offset, offset + size); + checkForComodification(); + return index >= 0 ? index - offset : -1; + } + + public int lastIndexOf(Object o) { + int index = root.lastIndexOfRange(o, offset, offset + size); + checkForComodification(); + return index >= 0 ? index - offset : -1; + } + + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + public Iterator iterator() { return listIterator(); } - public ListIterator listIterator(final int index) { - if (ArrayList.this.modCount != this.modCount) - throw new ConcurrentModificationException(); - if (index < 0 || index > this.size) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - final int offset = this.offset; + public ListIterator listIterator(int index) { + checkForComodification(); + rangeCheckForAdd(index); return new ListIterator() { int cursor = index; int lastRet = -1; - int expectedModCount = ArrayList.this.modCount; + int expectedModCount = SubList.this.modCount; public boolean hasNext() { return cursor != SubList.this.size; @@ -1129,12 +1342,11 @@ public boolean hasNext() { @SuppressWarnings("unchecked") public E next() { - if (expectedModCount != ArrayList.this.modCount) - throw new ConcurrentModificationException(); + checkForComodification(); int i = cursor; if (i >= SubList.this.size) throw new NoSuchElementException(); - Object[] elementData = ArrayList.this.elementData; + Object[] elementData = root.elementData; if (offset + i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; @@ -1147,37 +1359,32 @@ public boolean hasPrevious() { @SuppressWarnings("unchecked") public E previous() { - if (expectedModCount != ArrayList.this.modCount) - throw new ConcurrentModificationException(); + checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); - Object[] elementData = ArrayList.this.elementData; + Object[] elementData = root.elementData; if (offset + i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[offset + (lastRet = i)]; } - @SuppressWarnings("unchecked") - public void forEachRemaining(Consumer consumer) { - Objects.requireNonNull(consumer); + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); final int size = SubList.this.size; int i = cursor; - if (i >= size) { - return; - } - final Object[] elementData = ArrayList.this.elementData; - if (offset + i >= elementData.length) { - throw new ConcurrentModificationException(); + if (i < size) { + final Object[] es = root.elementData; + if (offset + i >= es.length) + throw new ConcurrentModificationException(); + for (; i < size && root.modCount == expectedModCount; i++) + action.accept(elementAt(es, offset + i)); + // update once at end to reduce heap write traffic + cursor = i; + lastRet = i - 1; + checkForComodification(); } - while (i != size && modCount == expectedModCount) { - consumer.accept((E) elementData[offset + (i++)]); - } - // update once at end of iteration to reduce heap write traffic - lastRet = cursor = i; - if (expectedModCount != ArrayList.this.modCount) - throw new ConcurrentModificationException(); } public int nextIndex() { @@ -1191,14 +1398,13 @@ public int previousIndex() { public void remove() { if (lastRet < 0) throw new IllegalStateException(); - if (expectedModCount != ArrayList.this.modCount) - throw new ConcurrentModificationException(); + checkForComodification(); try { SubList.this.remove(lastRet); cursor = lastRet; lastRet = -1; - expectedModCount = ArrayList.this.modCount; + expectedModCount = SubList.this.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } @@ -1207,66 +1413,151 @@ public void remove() { public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); - if (expectedModCount != ArrayList.this.modCount) - throw new ConcurrentModificationException(); + checkForComodification(); try { - ArrayList.this.set(offset + lastRet, e); + root.set(offset + lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { - if (expectedModCount != ArrayList.this.modCount) - throw new ConcurrentModificationException(); + checkForComodification(); try { int i = cursor; SubList.this.add(i, e); cursor = i + 1; lastRet = -1; - expectedModCount = ArrayList.this.modCount; + expectedModCount = SubList.this.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } + + final void checkForComodification() { + if (root.modCount != expectedModCount) + throw new ConcurrentModificationException(); + } }; } public List subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); - return new SubList(this, offset, fromIndex, toIndex); + return new SubList<>(this, fromIndex, toIndex); + } + + private void rangeCheckForAdd(int index) { + if (index < 0 || index > this.size) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+this.size; } - public Spliterator spliterator() { - if (modCount != ArrayList.this.modCount) + private void checkForComodification() { + if (root.modCount != modCount) throw new ConcurrentModificationException(); - return new ArrayListSpliterator(ArrayList.this, offset, - offset + this.size, this.modCount); + } + + private void updateSizeAndModCount(int sizeChange) { + SubList slist = this; + do { + slist.size += sizeChange; + slist.modCount = root.modCount; + slist = slist.parent; + } while (slist != null); + } + + public Spliterator spliterator() { + checkForComodification(); + + // ArrayListSpliterator not used here due to late-binding + return new Spliterator() { + private int index = offset; // current index, modified on advance/split + private int fence = -1; // -1 until used; then one past last index + private int expectedModCount; // initialized when fence set + + private int getFence() { // initialize fence to size on first use + int hi; // (a specialized variant appears in method forEach) + if ((hi = fence) < 0) { + expectedModCount = modCount; + hi = fence = offset + size; + } + return hi; + } + + public ArrayList.ArrayListSpliterator trySplit() { + int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + // ArrayListSpliterator can be used here as the source is already bound + return (lo >= mid) ? null : // divide range in half unless too small + root.new ArrayListSpliterator(lo, index = mid, expectedModCount); + } + + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + int hi = getFence(), i = index; + if (i < hi) { + index = i + 1; + @SuppressWarnings("unchecked") E e = (E)root.elementData[i]; + action.accept(e); + if (root.modCount != expectedModCount) + throw new ConcurrentModificationException(); + return true; + } + return false; + } + + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + int i, hi, mc; // hoist accesses and checks from loop + ArrayList lst = root; + Object[] a; + if ((a = lst.elementData) != null) { + if ((hi = fence) < 0) { + mc = modCount; + hi = offset + size; + } + else + mc = expectedModCount; + if ((i = index) >= 0 && (index = hi) <= a.length) { + for (; i < hi; ++i) { + @SuppressWarnings("unchecked") E e = (E) a[i]; + action.accept(e); + } + if (lst.modCount == mc) + return; + } + } + throw new ConcurrentModificationException(); + } + + public long estimateSize() { + return getFence() - index; + } + + public int characteristics() { + return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; + } + }; } } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public void forEach(Consumer action) { Objects.requireNonNull(action); final int expectedModCount = modCount; - @SuppressWarnings("unchecked") - final E[] elementData = (E[]) this.elementData; + final Object[] es = elementData; final int size = this.size; - for (int i=0; modCount == expectedModCount && i < size; i++) { - action.accept(elementData[i]); - } - // Android-note: - // Iterator will not throw a CME if we add something while iterating over the *last* element - // forEach will throw a CME in this case. - if (modCount != expectedModCount) { + for (int i = 0; modCount == expectedModCount && i < size; i++) + action.accept(elementAt(es, i)); + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } } /** @@ -1284,11 +1575,11 @@ public void forEach(Consumer action) { */ @Override public Spliterator spliterator() { - return new ArrayListSpliterator<>(this, 0, -1, 0); + return new ArrayListSpliterator(0, -1, 0); } /** Index-based split-by-two, lazily initialized Spliterator */ - static final class ArrayListSpliterator implements Spliterator { + final class ArrayListSpliterator implements Spliterator { /* * If ArrayLists were immutable, or structurally immutable (no @@ -1322,15 +1613,12 @@ static final class ArrayListSpliterator implements Spliterator { * these streamlinings. */ - private final ArrayList list; private int index; // current index, modified on advance/split private int fence; // -1 until used; then one past last index private int expectedModCount; // initialized when fence set - /** Create new spliterator covering the given range */ - ArrayListSpliterator(ArrayList list, int origin, int fence, - int expectedModCount) { - this.list = list; // OK if null unless traversed + /** Creates new spliterator covering the given range. */ + ArrayListSpliterator(int origin, int fence, int expectedModCount) { this.index = origin; this.fence = fence; this.expectedModCount = expectedModCount; @@ -1338,23 +1626,17 @@ static final class ArrayListSpliterator implements Spliterator { private int getFence() { // initialize fence to size on first use int hi; // (a specialized variant appears in method forEach) - ArrayList lst; if ((hi = fence) < 0) { - if ((lst = list) == null) - hi = fence = 0; - else { - expectedModCount = lst.modCount; - hi = fence = lst.size; - } + expectedModCount = modCount; + hi = fence = size; } return hi; } - public ArrayListSpliterator trySplit() { + public ArrayListSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : // divide range in half unless too small - new ArrayListSpliterator(list, lo, index = mid, - expectedModCount); + new ArrayListSpliterator(lo, index = mid, expectedModCount); } public boolean tryAdvance(Consumer action) { @@ -1363,9 +1645,9 @@ public boolean tryAdvance(Consumer action) { int hi = getFence(), i = index; if (i < hi) { index = i + 1; - @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; + @SuppressWarnings("unchecked") E e = (E)elementData[i]; action.accept(e); - if (list.modCount != expectedModCount) + if (modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } @@ -1374,13 +1656,13 @@ public boolean tryAdvance(Consumer action) { public void forEachRemaining(Consumer action) { int i, hi, mc; // hoist accesses and checks from loop - ArrayList lst; Object[] a; + Object[] a; if (action == null) throw new NullPointerException(); - if ((lst = list) != null && (a = lst.elementData) != null) { + if ((a = elementData) != null) { if ((hi = fence) < 0) { - mc = lst.modCount; - hi = lst.size; + mc = modCount; + hi = size; } else mc = expectedModCount; @@ -1389,7 +1671,7 @@ public void forEachRemaining(Consumer action) { @SuppressWarnings("unchecked") E e = (E) a[i]; action.accept(e); } - if (lst.modCount == mc) + if (modCount == mc) return; } } @@ -1397,7 +1679,7 @@ public void forEachRemaining(Consumer action) { } public long estimateSize() { - return (long) (getFence() - index); + return getFence() - index; } public int characteristics() { @@ -1405,62 +1687,77 @@ public int characteristics() { } } + // A tiny bit set implementation + + private static long[] nBits(int n) { + return new long[((n - 1) >> 6) + 1]; + } + private static void setBit(long[] bits, int i) { + bits[i >> 6] |= 1L << i; + } + private static boolean isClear(long[] bits, int i) { + return (bits[i >> 6] & (1L << i)) == 0; + } + + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter); - // figure out which elements are to be removed - // any exception thrown from the filter predicate at this stage - // will leave the collection unmodified - int removeCount = 0; - final BitSet removeSet = new BitSet(size); - final int expectedModCount = modCount; - final int size = this.size; - for (int i=0; modCount == expectedModCount && i < size; i++) { - @SuppressWarnings("unchecked") - final E element = (E) elementData[i]; - if (filter.test(element)) { - removeSet.set(i); - removeCount++; - } - } - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } + return removeIf(filter, 0, size); + } - // shift surviving elements left over the spaces left by removed elements - final boolean anyToRemove = removeCount > 0; - if (anyToRemove) { - final int newSize = size - removeCount; - for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { - i = removeSet.nextClearBit(i); - elementData[j] = elementData[i]; - } - for (int k=newSize; k < size; k++) { - elementData[k] = null; // Let gc do its work - } - this.size = newSize; - if (modCount != expectedModCount) { + /** + * Removes all elements satisfying the given predicate, from index + * i (inclusive) to index end (exclusive). + */ + boolean removeIf(Predicate filter, int i, final int end) { + Objects.requireNonNull(filter); + int expectedModCount = modCount; + final Object[] es = elementData; + // Optimize for initial run of survivors + for (; i < end && !filter.test(elementAt(es, i)); i++) + ; + // Tolerate predicates that reentrantly access the collection for + // read (but writers still get CME), so traverse once to find + // elements to delete, a second pass to physically expunge. + if (i < end) { + final int beg = i; + final long[] deathRow = nBits(end - beg); + deathRow[0] = 1L; // set bit 0 + for (i = beg + 1; i < end; i++) + if (filter.test(elementAt(es, i))) + setBit(deathRow, i - beg); + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } modCount++; + int w = beg; + for (i = beg; i < end; i++) + if (isClear(deathRow, i - beg)) + es[w++] = es[i]; + shiftTailOverGap(es, w, end); + return true; + } else { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + return false; } - - return anyToRemove; } @Override - @SuppressWarnings("unchecked") public void replaceAll(UnaryOperator operator) { + replaceAllRange(operator, 0, size); + modCount++; + } + + private void replaceAllRange(UnaryOperator operator, int i, int end) { Objects.requireNonNull(operator); final int expectedModCount = modCount; - final int size = this.size; - for (int i=0; modCount == expectedModCount && i < size; i++) { - elementData[i] = operator.apply((E) elementData[i]); - } - if (modCount != expectedModCount) { + final Object[] es = elementData; + for (; modCount == expectedModCount && i < end; i++) + es[i] = operator.apply(elementAt(es, i)); + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } - modCount++; } @Override @@ -1468,12 +1765,16 @@ public void replaceAll(UnaryOperator operator) { public void sort(Comparator c) { final int expectedModCount = modCount; Arrays.sort((E[]) elementData, 0, size, c); - if (modCount != expectedModCount) { + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } modCount++; } + void checkInvariants() { + // assert size >= 0; + // assert size == elementData.length || elementData[size] == null; + } + /*-[ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id *)stackbuf diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Arrays.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Arrays.java index 8cd8aaf1e1..19770da14b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Arrays.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Arrays.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, 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 @@ -26,6 +26,12 @@ package java.util; +/* J2ObjC removed +import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.IntrinsicCandidate; +*/ + +import java.io.Serializable; import java.lang.reflect.Array; import java.util.concurrent.ForkJoinPool; import java.util.function.BinaryOperator; @@ -53,7 +59,7 @@ * if the specified array reference is null, except where noted. * *

The documentation for the methods contained in this class includes - * briefs description of the implementations. Such descriptions should + * brief descriptions of the implementations. Such descriptions should * be regarded as implementation notes, rather than parts of the * specification. Implementors should feel free to substitute other * algorithms, so long as the specification itself is adhered to. (For @@ -61,7 +67,7 @@ * a MergeSort, but it does have to be stable.) * *

This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -71,62 +77,12 @@ */ public class Arrays { - /** - * The minimum array length below which a parallel sorting - * algorithm will not further partition the sorting task. Using - * smaller sizes typically results in memory contention across - * tasks that makes parallel speedups unlikely. - * @hide - */ - // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony ArraysTest). - public static final int MIN_ARRAY_SORT_GRAN = 1 << 13; - // Suppresses default constructor, ensuring non-instantiability. private Arrays() {} - /** - * A comparator that implements the natural ordering of a group of - * mutually comparable elements. May be used when a supplied - * comparator is null. To simplify code-sharing within underlying - * implementations, the compare method only declares type Object - * for its second argument. - * - * Arrays class implementor's note: It is an empirical matter - * whether ComparableTimSort offers any performance benefit over - * TimSort used with this comparator. If not, you are better off - * deleting or bypassing ComparableTimSort. There is currently no - * empirical case for separating them for parallel sorting, so all - * public Object parallelSort methods use the same comparator - * based implementation. - */ - static final class NaturalOrder implements Comparator { - @SuppressWarnings("unchecked") - public int compare(Object first, Object second) { - return ((Comparable)first).compareTo(second); - } - static final NaturalOrder INSTANCE = new NaturalOrder(); - } - - /** - * Checks that {@code fromIndex} and {@code toIndex} are in - * the range and throws an exception if they aren't. - */ - private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { - if (fromIndex > toIndex) { - throw new IllegalArgumentException( - "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); - } - if (fromIndex < 0) { - throw new ArrayIndexOutOfBoundsException(fromIndex); - } - if (toIndex > arrayLength) { - throw new ArrayIndexOutOfBoundsException(toIndex); - } - } - /* * Sorting methods. Note that all public "sort" methods take the - * same form: Performing argument checks if necessary, and then + * same form: performing argument checks if necessary, and then * expanding arguments into those required for the internal * implementation methods residing in other package-private * classes (except for legacyMergeSort, included in this class). @@ -135,10 +91,9 @@ private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -153,10 +108,9 @@ public static void sort(int[] a) { * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -175,10 +129,9 @@ public static void sort(int[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -193,10 +146,9 @@ public static void sort(long[] a) { * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -215,10 +167,9 @@ public static void sort(long[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -233,10 +184,9 @@ public static void sort(short[] a) { * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -255,10 +205,9 @@ public static void sort(short[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -273,10 +222,9 @@ public static void sort(char[] a) { * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -295,10 +243,9 @@ public static void sort(char[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -313,10 +260,9 @@ public static void sort(byte[] a) { * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -343,10 +289,9 @@ public static void sort(byte[] a, int fromIndex, int toIndex) { * {@code 0.0f} and {@code Float.NaN} is considered greater than any * other value and all {@code Float.NaN} values are considered equal. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -369,10 +314,9 @@ public static void sort(float[] a) { * {@code 0.0f} and {@code Float.NaN} is considered greater than any * other value and all {@code Float.NaN} values are considered equal. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -399,10 +343,9 @@ public static void sort(float[] a, int fromIndex, int toIndex) { * {@code 0.0d} and {@code Double.NaN} is considered greater than any * other value and all {@code Double.NaN} values are considered equal. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -425,10 +368,9 @@ public static void sort(double[] a) { * {@code 0.0d} and {@code Double.NaN} is considered greater than any * other value and all {@code Double.NaN} values are considered equal. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * @implNote The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted @@ -447,16 +389,10 @@ public static void sort(double[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -480,16 +416,10 @@ public static void parallelSort(byte[] a) { * inclusive, to the index {@code toIndex}, exclusive. If * {@code fromIndex == toIndex}, the range to be sorted is empty. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -517,16 +447,10 @@ public static void parallelSort(byte[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -550,16 +474,10 @@ public static void parallelSort(char[] a) { * inclusive, to the index {@code toIndex}, exclusive. If * {@code fromIndex == toIndex}, the range to be sorted is empty. * - @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -587,16 +505,10 @@ public static void parallelSort(char[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -620,16 +532,10 @@ public static void parallelSort(short[] a) { * inclusive, to the index {@code toIndex}, exclusive. If * {@code fromIndex == toIndex}, the range to be sorted is empty. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -657,16 +563,10 @@ public static void parallelSort(short[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -690,16 +590,10 @@ public static void parallelSort(int[] a) { * inclusive, to the index {@code toIndex}, exclusive. If * {@code fromIndex == toIndex}, the range to be sorted is empty. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -727,16 +621,10 @@ public static void parallelSort(int[] a, int fromIndex, int toIndex) { /** * Sorts the specified array into ascending numerical order. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -760,16 +648,10 @@ public static void parallelSort(long[] a) { * inclusive, to the index {@code toIndex}, exclusive. If * {@code fromIndex == toIndex}, the range to be sorted is empty. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -805,16 +687,10 @@ public static void parallelSort(long[] a, int fromIndex, int toIndex) { * {@code 0.0f} and {@code Float.NaN} is considered greater than any * other value and all {@code Float.NaN} values are considered equal. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -846,16 +722,10 @@ public static void parallelSort(float[] a) { * {@code 0.0f} and {@code Float.NaN} is considered greater than any * other value and all {@code Float.NaN} values are considered equal. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -891,16 +761,10 @@ public static void parallelSort(float[] a, int fromIndex, int toIndex) { * {@code 0.0d} and {@code Double.NaN} is considered greater than any * other value and all {@code Double.NaN} values are considered equal. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @@ -932,16 +796,10 @@ public static void parallelSort(double[] a) { * {@code 0.0d} and {@code Double.NaN} is considered greater than any * other value and all {@code Double.NaN} values are considered equal. * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted * @param fromIndex the index of the first element, inclusive, to be sorted @@ -966,6 +824,58 @@ public static void parallelSort(double[] a, int fromIndex, int toIndex) { MIN_ARRAY_SORT_GRAN : g).invoke(); } + /** + * Checks that {@code fromIndex} and {@code toIndex} are in + * the range and throws an exception if they aren't. + */ + static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { + throw new ArrayIndexOutOfBoundsException(fromIndex); + } + if (toIndex > arrayLength) { + throw new ArrayIndexOutOfBoundsException(toIndex); + } + } + + /** + * A comparator that implements the natural ordering of a group of + * mutually comparable elements. May be used when a supplied + * comparator is null. To simplify code-sharing within underlying + * implementations, the compare method only declares type Object + * for its second argument. + * + * Arrays class implementor's note: It is an empirical matter + * whether ComparableTimSort offers any performance benefit over + * TimSort used with this comparator. If not, you are better off + * deleting or bypassing ComparableTimSort. There is currently no + * empirical case for separating them for parallel sorting, so all + * public Object parallelSort methods use the same comparator + * based implementation. + */ + static final class NaturalOrder implements Comparator { + @SuppressWarnings("unchecked") + public int compare(Object first, Object second) { + return ((Comparable)first).compareTo(second); + } + static final NaturalOrder INSTANCE = new NaturalOrder(); + } + + /** + * The minimum array length below which a parallel sorting + * algorithm will not further partition the sorting task. Using + * smaller sizes typically results in memory contention across + * tasks that makes parallel speedups unlikely. + * + * @hide + */ + // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony + // ArraysTest). + public static final int MIN_ARRAY_SORT_GRAN = 1 << 13; + /** * Sorts the specified array of objects into ascending order, according * to the {@linkplain Comparable natural ordering} of its elements. @@ -1007,7 +917,7 @@ public static > void parallelSort(T[] a) { (p = ForkJoinPool.getCommonPoolParallelism()) == 1) TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0); else - new ArraysParallelSortHelpers.FJObject.Sorter + new ArraysParallelSortHelpers.FJObject.Sorter<> (null, a, (T[])Array.newInstance(a.getClass().getComponentType(), n), 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? @@ -1066,7 +976,7 @@ void parallelSort(T[] a, int fromIndex, int toIndex) { (p = ForkJoinPool.getCommonPoolParallelism()) == 1) TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0); else - new ArraysParallelSortHelpers.FJObject.Sorter + new ArraysParallelSortHelpers.FJObject.Sorter<> (null, a, (T[])Array.newInstance(a.getClass().getComponentType(), n), fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? @@ -1115,7 +1025,7 @@ public static void parallelSort(T[] a, Comparator cmp) { (p = ForkJoinPool.getCommonPoolParallelism()) == 1) TimSort.sort(a, 0, n, cmp, null, 0, 0); else - new ArraysParallelSortHelpers.FJObject.Sorter + new ArraysParallelSortHelpers.FJObject.Sorter<> (null, a, (T[])Array.newInstance(a.getClass().getComponentType(), n), 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? @@ -1176,7 +1086,7 @@ public static void parallelSort(T[] a, int fromIndex, int toIndex, (p = ForkJoinPool.getCommonPoolParallelism()) == 1) TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0); else - new ArraysParallelSortHelpers.FJObject.Sorter + new ArraysParallelSortHelpers.FJObject.Sorter<> (null, a, (T[])Array.newInstance(a.getClass().getComponentType(), n), fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? @@ -1187,7 +1097,23 @@ public static void parallelSort(T[] a, int fromIndex, int toIndex, * Sorting of complex type arrays. */ - // Android-removed: LegacyMergeSort class (unused on Android). + // BEGIN Android-removed: LegacyMergeSort class (unused on Android). + /* + /** + * Old merge sort implementation can be selected (for + * compatibility with broken comparators) using a system property. + * Cannot be a static boolean in the enclosing class due to + * circular dependencies. To be removed in a future release. + * + static final class LegacyMergeSort { + @SuppressWarnings("removal") + private static final boolean userRequested = + java.security.AccessController.doPrivileged( + new sun.security.action.GetBooleanAction( + "java.util.Arrays.useLegacyMergeSort")).booleanValue(); + } + */ + // END Android-removed: LegacyMergeSort class (unused on Android). /** * Sorts the specified array of objects into ascending order, according @@ -1213,7 +1139,7 @@ public static void parallelSort(T[] a, int fromIndex, int toIndex, * *

The implementation takes equal advantage of ascending and * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the the same + * ascending and descending order in different parts of the same * input array. It is well-suited to merging two or more sorted arrays: * simply concatenate the arrays and sort the resulting array. * @@ -1232,14 +1158,25 @@ public static void parallelSort(T[] a, int fromIndex, int toIndex, * {@link Comparable} contract */ public static void sort(Object[] a) { - // Android-removed: LegacyMergeSort support. - // if (LegacyMergeSort.userRequested) - // legacyMergeSort(a); - // else + // BEGIN Android-removed: LegacyMergeSort support. + /* + if (LegacyMergeSort.userRequested) + legacyMergeSort(a); + else + */ + // END Android-removed: LegacyMergeSort support. ComparableTimSort.sort(a, 0, a.length, null, 0, 0); } - // Android-removed: legacyMergeSort() (unused on Android). + // BEGIN Android-removed: legacyMergeSort() (unused on Android). + /* + /** To be removed in a future release. + private static void legacyMergeSort(Object[] a) { + Object[] aux = a.clone(); + mergeSort(aux, a, 0, a.length, 0); + } + */ + // END Android-removed: legacyMergeSort() (unused on Android). /** * Sorts the specified range of the specified array of objects into @@ -1269,7 +1206,7 @@ public static void sort(Object[] a) { * *

The implementation takes equal advantage of ascending and * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the the same + * ascending and descending order in different parts of the same * input array. It is well-suited to merging two or more sorted arrays: * simply concatenate the arrays and sort the resulting array. * @@ -1295,14 +1232,27 @@ public static void sort(Object[] a) { */ public static void sort(Object[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - // Android-removed: LegacyMergeSort support. - // if (LegacyMergeSort.userRequested) - // legacyMergeSort(a, fromIndex, toIndex); - // else + // BEGIN Android-removed: LegacyMergeSort support. + /* + if (LegacyMergeSort.userRequested) + legacyMergeSort(a, fromIndex, toIndex); + else + */ + // END Android-removed: LegacyMergeSort support. ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0); } - // Android-removed: legacyMergeSort() (unused on Android). + // BEGIN Android-removed: legacyMergeSort() (unused on Android). + /* + /** To be removed in a future release. * + private static void legacyMergeSort(Object[] a, + int fromIndex, int toIndex) { + Object[] aux = copyOfRange(a, fromIndex, toIndex); + mergeSort(aux, a, fromIndex, toIndex, -fromIndex); + } + */ + // END Android-removed: legacyMergeSort() (unused on Android). + /** * Tuning parameter: list size at or below which insertion sort will be @@ -1392,7 +1342,7 @@ private static void swap(Object[] x, int a, int b) { * *

The implementation takes equal advantage of ascending and * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the the same + * ascending and descending order in different parts of the same * input array. It is well-suited to merging two or more sorted arrays: * simply concatenate the arrays and sort the resulting array. * @@ -1417,15 +1367,28 @@ public static void sort(T[] a, Comparator c) { if (c == null) { sort(a); } else { - // Android-removed: LegacyMergeSort support. - // if (LegacyMergeSort.userRequested) - // legacyMergeSort(a, c); - // else + // BEGIN Android-removed: LegacyMergeSort support. + /* + if (LegacyMergeSort.userRequested) + legacyMergeSort(a, c); + else + */ + // END Android-removed: LegacyMergeSort support. TimSort.sort(a, 0, a.length, c, null, 0, 0); } } - // Android-removed: legacyMergeSort() (unused on Android). + // BEGIN Android-removed: legacyMergeSort() (unused on Android). + /** To be removed in a future release. * + private static void legacyMergeSort(T[] a, Comparator c) { + T[] aux = a.clone(); + if (c==null) + mergeSort(aux, a, 0, a.length, 0); + else + mergeSort(aux, a, 0, a.length, 0, c); + } + */ + // END Android-removed: legacyMergeSort() (unused on Android). /** * Sorts the specified range of the specified array of objects according @@ -1452,7 +1415,7 @@ public static void sort(T[] a, Comparator c) { * *

The implementation takes equal advantage of ascending and * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the the same + * ascending and descending order in different parts of the same * input array. It is well-suited to merging two or more sorted arrays: * simply concatenate the arrays and sort the resulting array. * @@ -1485,16 +1448,78 @@ public static void sort(T[] a, int fromIndex, int toIndex, sort(a, fromIndex, toIndex); } else { rangeCheck(a.length, fromIndex, toIndex); - // Android-removed: LegacyMergeSort support. - // if (LegacyMergeSort.userRequested) - // legacyMergeSort(a, fromIndex, toIndex, c); - // else + // BEGIN Android-removed: LegacyMergeSort support. + /* + if (LegacyMergeSort.userRequested) + legacyMergeSort(a, fromIndex, toIndex, c); + else + */ + // END Android-removed: LegacyMergeSort support. TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); } } - // Android-removed: legacyMergeSort() (unused on Android). - // Android-removed: mergeSort() (unused on Android). + // BEGIN Android-removed: legacyMergeSort() and mergeSort() (unused on Android). + /* + /** To be removed in a future release. * + private static void legacyMergeSort(T[] a, int fromIndex, int toIndex, + Comparator c) { + T[] aux = copyOfRange(a, fromIndex, toIndex); + if (c==null) + mergeSort(aux, a, fromIndex, toIndex, -fromIndex); + else + mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c); + } + + /** + * Src is the source array that starts at index 0 + * Dest is the (possibly larger) array destination with a possible offset + * low is the index in dest to start sorting + * high is the end index in dest to end sorting + * off is the offset into src corresponding to low in dest + * To be removed in a future release. + * + @SuppressWarnings({"rawtypes", "unchecked"}) + private static void mergeSort(Object[] src, + Object[] dest, + int low, int high, int off, + Comparator c) { + int length = high - low; + + // Insertion sort on smallest arrays + if (length < INSERTIONSORT_THRESHOLD) { + for (int i=low; ilow && c.compare(dest[j-1], dest[j])>0; j--) + swap(dest, j, j-1); + return; + } + + // Recursively sort halves of dest into src + int destLow = low; + int destHigh = high; + low += off; + high += off; + int mid = (low + high) >>> 1; + mergeSort(dest, src, low, mid, -off, c); + mergeSort(dest, src, mid, high, -off, c); + + // If list is already sorted, just copy from src to dest. This is an + // optimization that results in faster sorts for nearly ordered lists. + if (c.compare(src[mid-1], src[mid]) <= 0) { + System.arraycopy(src, low, dest, destLow, length); + return; + } + + // Merge sorted halves (now in src) into dest + for(int i = destLow, p = low, q = mid; i < destHigh; i++) { + if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0) + dest[i] = src[p++]; + else + dest[i] = src[q++]; + } + } + */ + // END Android-removed: legacyMergeSort() and mergeSort() (unused on Android). // Parallel prefix @@ -1696,10 +1721,10 @@ public static void parallelPrefix(int[] array, int fromIndex, * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1726,11 +1751,11 @@ public static int binarySearch(long[] a, long key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1777,10 +1802,10 @@ else if (midVal > key) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1807,11 +1832,11 @@ public static int binarySearch(int[] a, int key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1858,10 +1883,10 @@ else if (midVal > key) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1888,11 +1913,11 @@ public static int binarySearch(short[] a, short key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1939,10 +1964,10 @@ else if (midVal > key) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -1969,11 +1994,11 @@ public static int binarySearch(char[] a, char key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2020,10 +2045,10 @@ else if (midVal > key) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2050,11 +2075,11 @@ public static int binarySearch(byte[] a, byte key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2102,10 +2127,10 @@ else if (midVal > key) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2133,11 +2158,11 @@ public static int binarySearch(double[] a, double key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2193,10 +2218,10 @@ else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2224,11 +2249,11 @@ public static int binarySearch(float[] a, float key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2290,10 +2315,10 @@ else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN) * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2328,11 +2353,11 @@ public static int binarySearch(Object[] a, Object key) { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2388,13 +2413,13 @@ else if (cmp > 0) * @param a the array to be searched * @param key the value to be searched for * @param c the comparator by which the array is ordered. A - * null value indicates that the elements' + * {@code null} value indicates that the elements' * {@linkplain Comparable natural ordering} should be used. * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first - * element greater than the key, or a.length if all + * element greater than the key, or {@code a.length} if all * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2427,15 +2452,15 @@ public static int binarySearch(T[] a, T key, Comparator c) { * @param toIndex the index of the last element (exclusive) to be searched * @param key the value to be searched for * @param c the comparator by which the array is ordered. A - * null value indicates that the elements' + * {@code null} value indicates that the elements' * {@linkplain Comparable natural ordering} should be used. * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, - * or toIndex if all + * or {@code toIndex} if all * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -2481,16 +2506,16 @@ else if (cmp > 0) // Equality Testing /** - * Returns true if the two specified arrays of longs are + * Returns {@code true} if the two specified arrays of longs are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ public static boolean equals(long[] a, long[] a2) { if (a==a2) @@ -2510,16 +2535,16 @@ public static boolean equals(long[] a, long[] a2) { } /** - * Returns true if the two specified arrays of ints are + * Returns {@code true} if the two specified arrays of ints are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ public static boolean equals(int[] a, int[] a2) { if (a==a2) @@ -2539,16 +2564,16 @@ public static boolean equals(int[] a, int[] a2) { } /** - * Returns true if the two specified arrays of shorts are + * Returns {@code true} if the two specified arrays of shorts are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ public static boolean equals(short[] a, short a2[]) { if (a==a2) @@ -2568,17 +2593,20 @@ public static boolean equals(short[] a, short a2[]) { } /** - * Returns true if the two specified arrays of chars are + * Returns {@code true} if the two specified arrays of chars are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ + /* J2ObjC removed + @IntrinsicCandidate + */ public static boolean equals(char[] a, char[] a2) { if (a==a2) return true; @@ -2597,17 +2625,20 @@ public static boolean equals(char[] a, char[] a2) { } /** - * Returns true if the two specified arrays of bytes are + * Returns {@code true} if the two specified arrays of bytes are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ + /* J2ObjC removed + @IntrinsicCandidate + */ public static boolean equals(byte[] a, byte[] a2) { if (a==a2) return true; @@ -2626,16 +2657,16 @@ public static boolean equals(byte[] a, byte[] a2) { } /** - * Returns true if the two specified arrays of booleans are + * Returns {@code true} if the two specified arrays of booleans are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ public static boolean equals(boolean[] a, boolean[] a2) { if (a==a2) @@ -2655,21 +2686,21 @@ public static boolean equals(boolean[] a, boolean[] a2) { } /** - * Returns true if the two specified arrays of doubles are + * Returns {@code true} if the two specified arrays of doubles are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * - * Two doubles d1 and d2 are considered equal if: - *

    new Double(d1).equals(new Double(d2))
- * (Unlike the == operator, this method considers - * NaN equals to itself, and 0.0d unequal to -0.0d.) + * Two doubles {@code d1} and {@code d2} are considered equal if: + *
    {@code new Double(d1).equals(new Double(d2))}
+ * (Unlike the {@code ==} operator, this method considers + * {@code NaN} equal to itself, and 0.0d unequal to -0.0d.) * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal * @see Double#equals(Object) */ public static boolean equals(double[] a, double[] a2) { @@ -2690,21 +2721,21 @@ public static boolean equals(double[] a, double[] a2) { } /** - * Returns true if the two specified arrays of floats are + * Returns {@code true} if the two specified arrays of floats are * equal to one another. Two arrays are considered equal if both * arrays contain the same number of elements, and all corresponding pairs * of elements in the two arrays are equal. In other words, two arrays * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are null.

+ * two array references are considered equal if both are {@code null}. * - * Two floats f1 and f2 are considered equal if: - *

    new Float(f1).equals(new Float(f2))
- * (Unlike the == operator, this method considers - * NaN equals to itself, and 0.0f unequal to -0.0f.) + * Two floats {@code f1} and {@code f2} are considered equal if: + *
    {@code new Float(f1).equals(new Float(f2))}
+ * (Unlike the {@code ==} operator, this method considers + * {@code NaN} equal to itself, and 0.0f unequal to -0.0f.) * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal * @see Float#equals(Object) */ public static boolean equals(float[] a, float[] a2) { @@ -2725,18 +2756,19 @@ public static boolean equals(float[] a, float[] a2) { } /** - * Returns true if the two specified arrays of Objects are + * Returns {@code true} if the two specified arrays of Objects are * equal to one another. The two arrays are considered equal if * both arrays contain the same number of elements, and all corresponding - * pairs of elements in the two arrays are equal. Two objects e1 - * and e2 are considered equal if (e1==null ? e2==null - * : e1.equals(e2)). In other words, the two arrays are equal if + * pairs of elements in the two arrays are equal. Two objects {@code e1} + * and {@code e2} are considered equal if + * {@code Objects.equals(e1, e2)}. + * In other words, the two arrays are equal if * they contain the same elements in the same order. Also, two array - * references are considered equal if both are null.

+ * references are considered equal if both are {@code null}. * * @param a one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal */ public static boolean equals(Object[] a, Object[] a2) { if (a==a2) @@ -2749,9 +2781,157 @@ public static boolean equals(Object[] a, Object[] a2) { return false; for (int i=0; iequal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + *

Two objects {@code e1} and {@code e2} are considered equal if + * {@code Objects.equals(e1, e2)}. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(Object[] a, int aFromIndex, int aToIndex, + Object[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + for (int i = 0; i < aLength; i++) { + if (!Objects.equals(a[aFromIndex++], b[bFromIndex++])) + return false; + } + + return true; + } + + /** + * Returns {@code true} if the two specified arrays of Objects are + * equal to one another. + * + *

Two arrays are considered equal if both arrays contain the same number + * of elements, and all corresponding pairs of elements in the two arrays + * are equal. In other words, the two arrays are equal if they contain the + * same elements in the same order. Also, two array references are + * considered equal if both are {@code null}. + * + *

Two objects {@code e1} and {@code e2} are considered equal if, + * given the specified comparator, {@code cmp.compare(e1, e2) == 0}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return {@code true} if the two arrays are equal + * @throws NullPointerException if the comparator is {@code null} + * @since 9 + */ + public static boolean equals(T[] a, T[] a2, Comparator cmp) { + Objects.requireNonNull(cmp); + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + for (int i=0; iequal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + *

Two objects {@code e1} and {@code e2} are considered equal if, + * given the specified comparator, {@code cmp.compare(e1, e2) == 0}. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array or the comparator is {@code null} + * @since 9 + */ + public static boolean equals(T[] a, int aFromIndex, int aToIndex, + T[] b, int bFromIndex, int bToIndex, + Comparator cmp) { + Objects.requireNonNull(cmp); + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + for (int i = 0; i < aLength; i++) { + if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0) return false; } @@ -2775,8 +2955,8 @@ public static void fill(long[] a, long val) { /** * Assigns the specified long value to each element of the specified * range of the specified array of longs. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2785,9 +2965,9 @@ public static void fill(long[] a, long val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(long[] a, int fromIndex, int toIndex, long val) { rangeCheck(a.length, fromIndex, toIndex); @@ -2810,8 +2990,8 @@ public static void fill(int[] a, int val) { /** * Assigns the specified int value to each element of the specified * range of the specified array of ints. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2820,9 +3000,9 @@ public static void fill(int[] a, int val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(int[] a, int fromIndex, int toIndex, int val) { rangeCheck(a.length, fromIndex, toIndex); @@ -2845,8 +3025,8 @@ public static void fill(short[] a, short val) { /** * Assigns the specified short value to each element of the specified * range of the specified array of shorts. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2855,9 +3035,9 @@ public static void fill(short[] a, short val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(short[] a, int fromIndex, int toIndex, short val) { rangeCheck(a.length, fromIndex, toIndex); @@ -2880,8 +3060,8 @@ public static void fill(char[] a, char val) { /** * Assigns the specified char value to each element of the specified * range of the specified array of chars. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2890,9 +3070,9 @@ public static void fill(char[] a, char val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(char[] a, int fromIndex, int toIndex, char val) { rangeCheck(a.length, fromIndex, toIndex); @@ -2915,8 +3095,8 @@ public static void fill(byte[] a, byte val) { /** * Assigns the specified byte value to each element of the specified * range of the specified array of bytes. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2925,9 +3105,9 @@ public static void fill(byte[] a, byte val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(byte[] a, int fromIndex, int toIndex, byte val) { rangeCheck(a.length, fromIndex, toIndex); @@ -2950,8 +3130,8 @@ public static void fill(boolean[] a, boolean val) { /** * Assigns the specified boolean value to each element of the specified * range of the specified array of booleans. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2960,9 +3140,9 @@ public static void fill(boolean[] a, boolean val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(boolean[] a, int fromIndex, int toIndex, boolean val) { @@ -2986,8 +3166,8 @@ public static void fill(double[] a, double val) { /** * Assigns the specified double value to each element of the specified * range of the specified array of doubles. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -2996,9 +3176,9 @@ public static void fill(double[] a, double val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(double[] a, int fromIndex, int toIndex,double val){ rangeCheck(a.length, fromIndex, toIndex); @@ -3021,8 +3201,8 @@ public static void fill(float[] a, float val) { /** * Assigns the specified float value to each element of the specified * range of the specified array of floats. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -3031,9 +3211,9 @@ public static void fill(float[] a, float val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} */ public static void fill(float[] a, int fromIndex, int toIndex, float val) { rangeCheck(a.length, fromIndex, toIndex); @@ -3058,8 +3238,8 @@ public static void fill(Object[] a, Object val) { /** * Assigns the specified Object reference to each element of the specified * range of the specified array of Objects. The range to be filled - * extends from index fromIndex, inclusive, to index - * toIndex, exclusive. (If fromIndex==toIndex, the + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the * range to be filled is empty.) * * @param a the array to be filled @@ -3068,9 +3248,9 @@ public static void fill(Object[] a, Object val) { * @param toIndex the index of the last element (exclusive) to be * filled with the specified value * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} * @throws ArrayStoreException if the specified value is not of a * runtime type that can be stored in the specified array */ @@ -3087,7 +3267,7 @@ public static void fill(Object[] a, int fromIndex, int toIndex, Object val) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain null. + * copy but not the original, the copy will contain {@code null}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * The resulting array is of exactly the same class as the original array. @@ -3097,8 +3277,8 @@ public static void fill(Object[] a, int fromIndex, int toIndex, Object val) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with nulls * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ @SuppressWarnings("unchecked") @@ -3111,10 +3291,10 @@ public static T[] copyOf(T[] original, int newLength) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain null. + * copy but not the original, the copy will contain {@code null}. * Such indices will exist if and only if the specified length * is greater than that of the original array. - * The resulting array is of the class newType. + * The resulting array is of the class {@code newType}. * * @param the class of the objects in the original array * @param the class of the objects in the returned array @@ -3123,13 +3303,16 @@ public static T[] copyOf(T[] original, int newLength) { * @param newType the class of the copy to be returned * @return a copy of the original array, truncated or padded with nulls * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @throws ArrayStoreException if an element copied from - * original is not of a runtime type that can be stored in - * an array of class newType + * {@code original} is not of a runtime type that can be stored in + * an array of class {@code newType} * @since 1.6 */ + /* J2ObjC removed + @IntrinsicCandidate + */ public static T[] copyOf(U[] original, int newLength, Class newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) @@ -3145,7 +3328,7 @@ public static T[] copyOf(U[] original, int newLength, Class * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain (byte)0. + * copy but not the original, the copy will contain {@code (byte)0}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3153,8 +3336,8 @@ public static T[] copyOf(U[] original, int newLength, Class * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with zeros * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static byte[] copyOf(byte[] original, int newLength) { @@ -3169,7 +3352,7 @@ public static byte[] copyOf(byte[] original, int newLength) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain (short)0. + * copy but not the original, the copy will contain {@code (short)0}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3177,8 +3360,8 @@ public static byte[] copyOf(byte[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with zeros * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static short[] copyOf(short[] original, int newLength) { @@ -3193,7 +3376,7 @@ public static short[] copyOf(short[] original, int newLength) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain 0. + * copy but not the original, the copy will contain {@code 0}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3201,8 +3384,8 @@ public static short[] copyOf(short[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with zeros * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static int[] copyOf(int[] original, int newLength) { @@ -3217,7 +3400,7 @@ public static int[] copyOf(int[] original, int newLength) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain 0L. + * copy but not the original, the copy will contain {@code 0L}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3225,8 +3408,8 @@ public static int[] copyOf(int[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with zeros * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static long[] copyOf(long[] original, int newLength) { @@ -3241,7 +3424,7 @@ public static long[] copyOf(long[] original, int newLength) { * so the copy has the specified length. For all indices that are valid * in both the original array and the copy, the two arrays will contain * identical values. For any indices that are valid in the copy but not - * the original, the copy will contain '\\u000'. Such indices + * the original, the copy will contain {@code '\u005cu0000'}. Such indices * will exist if and only if the specified length is greater than that of * the original array. * @@ -3249,8 +3432,8 @@ public static long[] copyOf(long[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with null characters * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static char[] copyOf(char[] original, int newLength) { @@ -3265,7 +3448,7 @@ public static char[] copyOf(char[] original, int newLength) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain 0f. + * copy but not the original, the copy will contain {@code 0f}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3273,8 +3456,8 @@ public static char[] copyOf(char[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with zeros * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static float[] copyOf(float[] original, int newLength) { @@ -3289,7 +3472,7 @@ public static float[] copyOf(float[] original, int newLength) { * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain 0d. + * copy but not the original, the copy will contain {@code 0d}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3297,8 +3480,8 @@ public static float[] copyOf(float[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with zeros * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static double[] copyOf(double[] original, int newLength) { @@ -3309,11 +3492,11 @@ public static double[] copyOf(double[] original, int newLength) { } /** - * Copies the specified array, truncating or padding with false (if necessary) + * Copies the specified array, truncating or padding with {@code false} (if necessary) * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain false. + * copy but not the original, the copy will contain {@code false}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * @@ -3321,8 +3504,8 @@ public static double[] copyOf(double[] original, int newLength) { * @param newLength the length of the copy to be returned * @return a copy of the original array, truncated or padded with false elements * to obtain the specified length - * @throws NegativeArraySizeException if newLength is negative - * @throws NullPointerException if original is null + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static boolean[] copyOf(boolean[] original, int newLength) { @@ -3334,17 +3517,17 @@ public static boolean[] copyOf(boolean[] original, int newLength) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * null is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code null} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. *

* The resulting array is of exactly the same class as the original array. * @@ -3357,8 +3540,8 @@ public static boolean[] copyOf(boolean[] original, int newLength) { * truncated or padded with nulls to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ @SuppressWarnings("unchecked") @@ -3368,18 +3551,18 @@ public static T[] copyOfRange(T[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * null is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. - * The resulting array is of the class newType. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code null} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * The resulting array is of the class {@code newType}. * * @param the class of the objects in the original array * @param the class of the objects in the returned array @@ -3392,13 +3575,16 @@ public static T[] copyOfRange(T[] original, int from, int to) { * truncated or padded with nulls to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @throws ArrayStoreException if an element copied from - * original is not of a runtime type that can be stored in - * an array of class newType. + * {@code original} is not of a runtime type that can be stored in + * an array of class {@code newType}. * @since 1.6 */ + /* J2ObjC removed + @IntrinsicCandidate + */ public static T[] copyOfRange(U[] original, int from, int to, Class newType) { int newLength = to - from; if (newLength < 0) @@ -3414,17 +3600,17 @@ public static T[] copyOfRange(U[] original, int from, int to, Classfrom) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * (byte)0 is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code (byte)0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3434,8 +3620,8 @@ public static T[] copyOfRange(U[] original, int from, int to, Class original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static byte[] copyOfRange(byte[] original, int from, int to) { @@ -3450,17 +3636,17 @@ public static byte[] copyOfRange(byte[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * (short)0 is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code (short)0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3470,8 +3656,8 @@ public static byte[] copyOfRange(byte[] original, int from, int to) { * truncated or padded with zeros to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static short[] copyOfRange(short[] original, int from, int to) { @@ -3486,17 +3672,17 @@ public static short[] copyOfRange(short[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * 0 is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3506,8 +3692,8 @@ public static short[] copyOfRange(short[] original, int from, int to) { * truncated or padded with zeros to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static int[] copyOfRange(int[] original, int from, int to) { @@ -3522,17 +3708,17 @@ public static int[] copyOfRange(int[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * 0L is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0L} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3542,8 +3728,8 @@ public static int[] copyOfRange(int[] original, int from, int to) { * truncated or padded with zeros to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static long[] copyOfRange(long[] original, int from, int to) { @@ -3558,17 +3744,17 @@ public static long[] copyOfRange(long[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * '\\u000' is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code '\u005cu0000'} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3578,8 +3764,8 @@ public static long[] copyOfRange(long[] original, int from, int to) { * truncated or padded with null characters to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static char[] copyOfRange(char[] original, int from, int to) { @@ -3594,17 +3780,17 @@ public static char[] copyOfRange(char[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * 0f is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0f} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3614,8 +3800,8 @@ public static char[] copyOfRange(char[] original, int from, int to) { * truncated or padded with zeros to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static float[] copyOfRange(float[] original, int from, int to) { @@ -3630,17 +3816,17 @@ public static float[] copyOfRange(float[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * 0d is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0d} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3650,8 +3836,8 @@ public static float[] copyOfRange(float[] original, int from, int to) { * truncated or padded with zeros to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static double[] copyOfRange(double[] original, int from, int to) { @@ -3666,17 +3852,17 @@ public static double[] copyOfRange(double[] original, int from, int to) { /** * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). * Values from subsequent elements in the original array are placed into * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * false is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code false} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. * * @param original the array from which a range is to be copied * @param from the initial index of the range to be copied, inclusive @@ -3686,8 +3872,8 @@ public static double[] copyOfRange(double[] original, int from, int to) { * truncated or padded with false elements to obtain the required length * @throws ArrayIndexOutOfBoundsException if {@code from < 0} * or {@code from > original.length} - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null * @since 1.6 */ public static boolean[] copyOfRange(boolean[] original, int from, int to) { @@ -3703,21 +3889,41 @@ public static boolean[] copyOfRange(boolean[] original, int from, int to) { // Misc /** - * Returns a fixed-size list backed by the specified array. (Changes to - * the returned list "write through" to the array.) This method acts - * as bridge between array-based and collection-based APIs, in - * combination with {@link Collection#toArray}. The returned list is - * serializable and implements {@link RandomAccess}. + * Returns a fixed-size list backed by the specified array. Changes made to + * the array will be visible in the returned list, and changes made to the + * list will be visible in the array. The returned list is + * {@link Serializable} and implements {@link RandomAccess}. + * + *

The returned list implements the optional {@code Collection} methods, except + * those that would change the size of the returned list. Those methods leave + * the list unchanged and throw {@link UnsupportedOperationException}. + * + * @apiNote + * This method acts as bridge between array-based and collection-based + * APIs, in combination with {@link Collection#toArray}. + * + *

This method provides a way to wrap an existing array: + *

{@code
+     *     Integer[] numbers = ...
+     *     ...
+     *     List values = Arrays.asList(numbers);
+     * }
* *

This method also provides a convenient way to create a fixed-size * list initialized to contain several elements: - *

-     *     List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
-     * 
+ *
{@code
+     *     List stooges = Arrays.asList("Larry", "Moe", "Curly");
+     * }
+ * + *

The list returned by this method is modifiable. + * To create an unmodifiable list, use + * {@link Collections#unmodifiableList Collections.unmodifiableList} + * or Unmodifiable Lists. * * @param the class of the objects in the array * @param a the array by which the list will be backed * @return a list view of the specified array + * @throws NullPointerException if the specified array is {@code null} */ @SafeVarargs @SuppressWarnings("varargs") @@ -3731,6 +3937,7 @@ public static List asList(T... a) { private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { + @java.io.Serial private static final long serialVersionUID = -2764017481108945198L; private final E[] a; @@ -3745,6 +3952,11 @@ public int size() { @Override public Object[] toArray() { + // Android-changed: there are applications which expect this method + // to return array with component type E, not just Object. + // Keeping pre-Java 9 behaviour for compatibility sake. + // See b/204397945. + // return Arrays.copyOf(a, a.length, Object[].class); return a.clone(); } @@ -3790,7 +4002,7 @@ public int indexOf(Object o) { @Override public boolean contains(Object o) { - return indexOf(o) != -1; + return indexOf(o) >= 0; } @Override @@ -3819,22 +4031,51 @@ public void replaceAll(UnaryOperator operator) { public void sort(Comparator c) { Arrays.sort(a, c); } + + @Override + public Iterator iterator() { + return new ArrayItr<>(a); + } + } + + private static class ArrayItr implements Iterator { + private int cursor; + private final E[] a; + + ArrayItr(E[] a) { + this.a = a; + } + + @Override + public boolean hasNext() { + return cursor < a.length; + } + + @Override + public E next() { + int i = cursor; + if (i >= a.length) { + throw new NoSuchElementException(); + } + cursor = i + 1; + return a[i]; + } } /** * Returns a hash code based on the contents of the specified array. - * For any two long arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code long} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Long} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(long a[]) { @@ -3852,18 +4093,18 @@ public static int hashCode(long a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two non-null int arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two non-null {@code int} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Integer} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(int a[]) { @@ -3879,18 +4120,18 @@ public static int hashCode(int a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two short arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code short} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Short} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(short a[]) { @@ -3906,18 +4147,18 @@ public static int hashCode(short a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two char arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code char} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Character} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(char a[]) { @@ -3933,18 +4174,18 @@ public static int hashCode(char a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two byte arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code byte} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Byte} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(byte a[]) { @@ -3960,18 +4201,18 @@ public static int hashCode(byte a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two boolean arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code boolean} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Boolean} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(boolean a[]) { @@ -3987,18 +4228,18 @@ public static int hashCode(boolean a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two float arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code float} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Float} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(float a[]) { @@ -4014,18 +4255,18 @@ public static int hashCode(float a[]) { /** * Returns a hash code based on the contents of the specified array. - * For any two double arrays a and b - * such that Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + * For any two {@code double} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} + * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Double} - * instances representing the elements of a in the same order. - * If a is null, this method returns 0. + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. * * @param a the array whose hash value to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @since 1.5 */ public static int hashCode(double a[]) { @@ -4048,16 +4289,16 @@ public static int hashCode(double a[]) { * element, either directly or indirectly through one or more levels of * arrays. * - *

For any two arrays a and b such that - * Arrays.equals(a, b), it is also the case that - * Arrays.hashCode(a) == Arrays.hashCode(b). + *

For any two arrays {@code a} and {@code b} such that + * {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. * *

The value returned by this method is equal to the value that would - * be returned by Arrays.asList(a).hashCode(), unless a - * is null, in which case 0 is returned. + * be returned by {@code Arrays.asList(a).hashCode()}, unless {@code a} + * is {@code null}, in which case {@code 0} is returned. * * @param a the array whose content-based hash code to compute - * @return a content-based hash code for a + * @return a content-based hash code for {@code a} * @see #deepHashCode(Object[]) * @since 1.5 */ @@ -4082,23 +4323,23 @@ public static int hashCode(Object a[]) { * one or more levels of arrays. The behavior of such an invocation is * undefined. * - *

For any two arrays a and b such that - * Arrays.deepEquals(a, b), it is also the case that - * Arrays.deepHashCode(a) == Arrays.deepHashCode(b). + *

For any two arrays {@code a} and {@code b} such that + * {@code Arrays.deepEquals(a, b)}, it is also the case that + * {@code Arrays.deepHashCode(a) == Arrays.deepHashCode(b)}. * *

The computation of the value returned by this method is similar to * that of the value returned by {@link List#hashCode()} on a list - * containing the same elements as a in the same order, with one - * difference: If an element e of a is itself an array, - * its hash code is computed not by calling e.hashCode(), but as - * by calling the appropriate overloading of Arrays.hashCode(e) - * if e is an array of a primitive type, or as by calling - * Arrays.deepHashCode(e) recursively if e is an array - * of a reference type. If a is null, this method + * containing the same elements as {@code a} in the same order, with one + * difference: If an element {@code e} of {@code a} is itself an array, + * its hash code is computed not by calling {@code e.hashCode()}, but as + * by calling the appropriate overloading of {@code Arrays.hashCode(e)} + * if {@code e} is an array of a primitive type, or as by calling + * {@code Arrays.deepHashCode(e)} recursively if {@code e} is an array + * of a reference type. If {@code a} is {@code null}, this method * returns 0. * * @param a the array whose deep-content-based hash code to compute - * @return a deep-content-based hash code for a + * @return a deep-content-based hash code for {@code a} * @see #hashCode(Object[]) * @since 1.5 */ @@ -4109,63 +4350,60 @@ public static int deepHashCode(Object a[]) { int result = 1; for (Object element : a) { - int elementHash = 0; - // BEGIN Android-changed: getComponentType() is faster than instanceof(). - if (element != null) { - Class cl = element.getClass().getComponentType(); - if (cl == null) - elementHash = element.hashCode(); - else if (element instanceof Object[]) - elementHash = deepHashCode((Object[]) element); - else if (cl == byte.class) - elementHash = hashCode((byte[]) element); - else if (cl == short.class) - elementHash = hashCode((short[]) element); - else if (cl == int.class) - elementHash = hashCode((int[]) element); - else if (cl == long.class) - elementHash = hashCode((long[]) element); - else if (cl == char.class) - elementHash = hashCode((char[]) element); - else if (cl == float.class) - elementHash = hashCode((float[]) element); - else if (cl == double.class) - elementHash = hashCode((double[]) element); - else if (cl == boolean.class) - elementHash = hashCode((boolean[]) element); - else - elementHash = element.hashCode(); - } - // END Android-changed: getComponentType() is faster than instanceof(). + final int elementHash; + final Class cl; + if (element == null) + elementHash = 0; + else if ((cl = element.getClass().getComponentType()) == null) + elementHash = element.hashCode(); + else if (element instanceof Object[]) + elementHash = deepHashCode((Object[]) element); + else + elementHash = primitiveArrayHashCode(element, cl); + result = 31 * result + elementHash; } return result; } + private static int primitiveArrayHashCode(Object a, Class cl) { + return + (cl == byte.class) ? hashCode((byte[]) a) : + (cl == int.class) ? hashCode((int[]) a) : + (cl == long.class) ? hashCode((long[]) a) : + (cl == char.class) ? hashCode((char[]) a) : + (cl == short.class) ? hashCode((short[]) a) : + (cl == boolean.class) ? hashCode((boolean[]) a) : + (cl == double.class) ? hashCode((double[]) a) : + // If new primitive types are ever added, this method must be + // expanded or we will fail here with ClassCastException. + hashCode((float[]) a); + } + /** - * Returns true if the two specified arrays are deeply + * Returns {@code true} if the two specified arrays are deeply * equal to one another. Unlike the {@link #equals(Object[],Object[])} * method, this method is appropriate for use with nested arrays of * arbitrary depth. * *

Two array references are considered deeply equal if both - * are null, or if they refer to arrays that contain the same + * are {@code null}, or if they refer to arrays that contain the same * number of elements and all corresponding pairs of elements in the two * arrays are deeply equal. * - *

Two possibly null elements e1 and e2 are + *

Two possibly {@code null} elements {@code e1} and {@code e2} are * deeply equal if any of the following conditions hold: *

    - *
  • e1 and e2 are both arrays of object reference - * types, and Arrays.deepEquals(e1, e2) would return true - *
  • e1 and e2 are arrays of the same primitive + *
  • {@code e1} and {@code e2} are both arrays of object reference + * types, and {@code Arrays.deepEquals(e1, e2) would return true} + *
  • {@code e1} and {@code e2} are arrays of the same primitive * type, and the appropriate overloading of - * Arrays.equals(e1, e2) would return true. - *
  • e1 == e2 - *
  • e1.equals(e2) would return true. + * {@code Arrays.equals(e1, e2)} would return true. + *
  • {@code e1 == e2} + *
  • {@code e1.equals(e2)} would return true. *
- * Note that this definition permits null elements at any depth. + * Note that this definition permits {@code null} elements at any depth. * *

If either of the specified arrays contain themselves as elements * either directly or indirectly through one or more levels of arrays, @@ -4173,7 +4411,7 @@ else if (cl == boolean.class) * * @param a1 one array to be tested for equality * @param a2 the other array to be tested for equality - * @return true if the two arrays are equal + * @return {@code true} if the two arrays are equal * @see #equals(Object[],Object[]) * @see Objects#deepEquals(Object, Object) * @since 1.5 @@ -4234,14 +4472,14 @@ else if (e1 instanceof boolean[] && e2 instanceof boolean[]) /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(long). Returns "null" if a - * is null. + * {@code String.valueOf(long)}. Returns {@code "null"} if {@code a} + * is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(long[] a) { @@ -4264,14 +4502,14 @@ public static String toString(long[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(int). Returns "null" if a is - * null. + * {@code String.valueOf(int)}. Returns {@code "null"} if {@code a} is + * {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(int[] a) { @@ -4294,14 +4532,14 @@ public static String toString(int[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(short). Returns "null" if a - * is null. + * {@code String.valueOf(short)}. Returns {@code "null"} if {@code a} + * is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(short[] a) { @@ -4324,14 +4562,14 @@ public static String toString(short[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(char). Returns "null" if a - * is null. + * {@code String.valueOf(char)}. Returns {@code "null"} if {@code a} + * is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(char[] a) { @@ -4354,14 +4592,14 @@ public static String toString(char[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements - * are separated by the characters ", " (a comma followed + * enclosed in square brackets ({@code "[]"}). Adjacent elements + * are separated by the characters {@code ", "} (a comma followed * by a space). Elements are converted to strings as by - * String.valueOf(byte). Returns "null" if - * a is null. + * {@code String.valueOf(byte)}. Returns {@code "null"} if + * {@code a} is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(byte[] a) { @@ -4384,14 +4622,14 @@ public static String toString(byte[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(boolean). Returns "null" if - * a is null. + * {@code String.valueOf(boolean)}. Returns {@code "null"} if + * {@code a} is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(boolean[] a) { @@ -4414,14 +4652,14 @@ public static String toString(boolean[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(float). Returns "null" if a - * is null. + * {@code String.valueOf(float)}. Returns {@code "null"} if {@code a} + * is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(float[] a) { @@ -4445,14 +4683,14 @@ public static String toString(float[] a) { /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, - * enclosed in square brackets ("[]"). Adjacent elements are - * separated by the characters ", " (a comma followed by a + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a * space). Elements are converted to strings as by - * String.valueOf(double). Returns "null" if a - * is null. + * {@code String.valueOf(double)}. Returns {@code "null"} if {@code a} + * is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @since 1.5 */ public static String toString(double[] a) { @@ -4476,15 +4714,15 @@ public static String toString(double[] a) { * Returns a string representation of the contents of the specified array. * If the array contains other arrays as elements, they are converted to * strings by the {@link Object#toString} method inherited from - * Object, which describes their identities rather than + * {@code Object}, which describes their identities rather than * their contents. * *

The value returned by this method is equal to the value that would - * be returned by Arrays.asList(a).toString(), unless a - * is null, in which case "null" is returned. + * be returned by {@code Arrays.asList(a).toString()}, unless {@code a} + * is {@code null}, in which case {@code "null"} is returned. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @see #deepToString(Object[]) * @since 1.5 */ @@ -4513,29 +4751,29 @@ public static String toString(Object[] a) { * designed for converting multidimensional arrays to strings. * *

The string representation consists of a list of the array's - * elements, enclosed in square brackets ("[]"). Adjacent - * elements are separated by the characters ", " (a comma + * elements, enclosed in square brackets ({@code "[]"}). Adjacent + * elements are separated by the characters {@code ", "} (a comma * followed by a space). Elements are converted to strings as by - * String.valueOf(Object), unless they are themselves + * {@code String.valueOf(Object)}, unless they are themselves * arrays. * - *

If an element e is an array of a primitive type, it is + *

If an element {@code e} is an array of a primitive type, it is * converted to a string as by invoking the appropriate overloading of - * Arrays.toString(e). If an element e is an array of a + * {@code Arrays.toString(e)}. If an element {@code e} is an array of a * reference type, it is converted to a string as by invoking * this method recursively. * *

To avoid infinite recursion, if the specified array contains itself * as an element, or contains an indirect reference to itself through one * or more levels of arrays, the self-reference is converted to the string - * "[...]". For example, an array containing only a reference - * to itself would be rendered as "[[...]]". + * {@code "[...]"}. For example, an array containing only a reference + * to itself would be rendered as {@code "[[...]]"}. * - *

This method returns "null" if the specified array - * is null. + *

This method returns {@code "null"} if the specified array + * is {@code null}. * * @param a the array whose string representation to return - * @return a string representation of a + * @return a string representation of {@code a} * @see #toString(Object[]) * @since 1.5 */ @@ -4547,7 +4785,7 @@ public static String deepToString(Object[] a) { if (a.length != 0 && bufLen <= 0) bufLen = Integer.MAX_VALUE; StringBuilder buf = new StringBuilder(bufLen); - deepToString(a, buf, new HashSet()); + deepToString(a, buf, new HashSet<>()); return buf.toString(); } @@ -4616,6 +4854,14 @@ else if (eClass == boolean[].class) *

If the generator function throws an exception, it is relayed to * the caller and the array is left in an indeterminate state. * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }
+ * * @param type of elements of the array * @param array array to be initialized * @param generator a function accepting an index and producing the desired @@ -4637,6 +4883,15 @@ public static void setAll(T[] array, IntFunction generator) { * is thrown from {@code parallelSetAll} and the array is left in an * indeterminate state. * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *
{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }
+ * * @param type of elements of the array * @param array array to be initialized * @param generator a function accepting an index and producing the desired @@ -4656,6 +4911,14 @@ public static void parallelSetAll(T[] array, IntFunction genera *

If the generator function throws an exception, it is relayed to * the caller and the array is left in an indeterminate state. * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }
+ * * @param array array to be initialized * @param generator a function accepting an index and producing the desired * value for that position @@ -4676,6 +4939,15 @@ public static void setAll(int[] array, IntUnaryOperator generator) { * is thrown from {@code parallelSetAll} and the array is left in an * indeterminate state. * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *
{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }
+ * * @param array array to be initialized * @param generator a function accepting an index and producing the desired * value for that position @@ -4694,6 +4966,14 @@ public static void parallelSetAll(int[] array, IntUnaryOperator generator) { *

If the generator function throws an exception, it is relayed to * the caller and the array is left in an indeterminate state. * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }
+ * * @param array array to be initialized * @param generator a function accepting an index and producing the desired * value for that position @@ -4714,6 +4994,15 @@ public static void setAll(long[] array, IntToLongFunction generator) { * is thrown from {@code parallelSetAll} and the array is left in an * indeterminate state. * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *
{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }
+ * * @param array array to be initialized * @param generator a function accepting an index and producing the desired * value for that position @@ -4732,6 +5021,14 @@ public static void parallelSetAll(long[] array, IntToLongFunction generator) { *

If the generator function throws an exception, it is relayed to * the caller and the array is left in an indeterminate state. * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }
+ * * @param array array to be initialized * @param generator a function accepting an index and producing the desired * value for that position @@ -4752,6 +5049,15 @@ public static void setAll(double[] array, IntToDoubleFunction generator) { * is thrown from {@code parallelSetAll} and the array is left in an * indeterminate state. * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *
{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }
+ * * @param array array to be initialized * @param generator a function accepting an index and producing the desired * value for that position @@ -5043,4 +5349,3186 @@ public static DoubleStream stream(double[] array) { public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) { return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false); } + + + // Comparison methods + + // Compare boolean + + // J2ObjC removed + // /** + // * Compares two {@code boolean} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Boolean#compare(boolean, boolean)}, at an index within the + // * respective arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(boolean[], boolean[])} for the definition of a + // * common and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(boolean[], boolean[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Boolean.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(boolean[] a, boolean[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Boolean.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code boolean} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Boolean#compare(boolean, boolean)}, at a + // * relative index within the respective arrays that is the length of the + // * prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(boolean[], int, int, boolean[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(boolean[], int, int, boolean[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(boolean[] a, int aFromIndex, int aToIndex, + // boolean[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare byte + + // /** + // * Compares two {@code byte} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Byte#compare(byte, byte)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(byte[], byte[])} for the definition of a common and + // * proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(byte[], byte[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Byte.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(byte[] a, byte[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Byte.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code byte} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Byte#compare(byte, byte)}, at a relative index + // * within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(byte[], int, int, byte[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(byte[] a, int aFromIndex, int aToIndex, + // byte[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // /** + // * Compares two {@code byte} arrays lexicographically, numerically treating + // * elements as unsigned. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Byte#compareUnsigned(byte, byte)}, at an index within the + // * respective arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(byte[], byte[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Byte.compareUnsigned(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are + // * equal and contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compareUnsigned(byte[] a, byte[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Byte.compareUnsigned(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + + // /** + // * Compares two {@code byte} arrays lexicographically over the specified + // * ranges, numerically treating elements as unsigned. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Byte#compareUnsigned(byte, byte)}, at a + // * relative index within the respective arrays that is the length of the + // * prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is null + // * @since 9 + // */ + // public static int compareUnsigned(byte[] a, int aFromIndex, int aToIndex, + // byte[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare short + + // /** + // * Compares two {@code short} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Short#compare(short, short)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(short[], short[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(short[], short[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Short.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(short[] a, short[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Short.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code short} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Short#compare(short, short)}, at a relative + // * index within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(short[], int, int, short[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(short[], int, int, short[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(short[] a, int aFromIndex, int aToIndex, + // short[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Short.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // /** + // * Compares two {@code short} arrays lexicographically, numerically treating + // * elements as unsigned. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Short#compareUnsigned(short, short)}, at an index within the + // * respective arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(short[], short[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Short.compareUnsigned(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are + // * equal and contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compareUnsigned(short[] a, short[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Short.compareUnsigned(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code short} arrays lexicographically over the specified + // * ranges, numerically treating elements as unsigned. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Short#compareUnsigned(short, short)}, at a + // * relative index within the respective arrays that is the length of the + // * prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(short[], int, int, short[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is null + // * @since 9 + // */ + // public static int compareUnsigned(short[] a, int aFromIndex, int aToIndex, + // short[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare char + + // /** + // * Compares two {@code char} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Character#compare(char, char)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(char[], char[])} for the definition of a common and + // * proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(char[], char[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Character.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(char[] a, char[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Character.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code char} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Character#compare(char, char)}, at a relative + // * index within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(char[], int, int, char[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(char[], int, int, char[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(char[] a, int aFromIndex, int aToIndex, + // char[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Character.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare int + + // /** + // * Compares two {@code int} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Integer#compare(int, int)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(int[], int[])} for the definition of a common and + // * proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(int[], int[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Integer.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(int[] a, int[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Integer.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code int} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Integer#compare(int, int)}, at a relative index + // * within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(int[], int, int, int[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(int[], int, int, int[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(int[] a, int aFromIndex, int aToIndex, + // int[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // /** + // * Compares two {@code int} arrays lexicographically, numerically treating + // * elements as unsigned. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Integer#compareUnsigned(int, int)}, at an index within the + // * respective arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(int[], int[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Integer.compareUnsigned(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are + // * equal and contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compareUnsigned(int[] a, int[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Integer.compareUnsigned(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code int} arrays lexicographically over the specified + // * ranges, numerically treating elements as unsigned. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Integer#compareUnsigned(int, int)}, at a + // * relative index within the respective arrays that is the length of the + // * prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(int[], int, int, int[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is null + // * @since 9 + // */ + // public static int compareUnsigned(int[] a, int aFromIndex, int aToIndex, + // int[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare long + + // /** + // * Compares two {@code long} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Long#compare(long, long)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(long[], long[])} for the definition of a common and + // * proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(long[], long[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Long.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(long[] a, long[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Long.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code long} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Long#compare(long, long)}, at a relative index + // * within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(long[], int, int, long[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(long[], int, int, long[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(long[] a, int aFromIndex, int aToIndex, + // long[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Long.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // /** + // * Compares two {@code long} arrays lexicographically, numerically treating + // * elements as unsigned. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Long#compareUnsigned(long, long)}, at an index within the + // * respective arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(long[], long[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Long.compareUnsigned(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are + // * equal and contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compareUnsigned(long[] a, long[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Long.compareUnsigned(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code long} arrays lexicographically over the specified + // * ranges, numerically treating elements as unsigned. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Long#compareUnsigned(long, long)}, at a + // * relative index within the respective arrays that is the length of the + // * prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(long[], int, int, long[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is null + // * @since 9 + // */ + // public static int compareUnsigned(long[] a, int aFromIndex, int aToIndex, + // long[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare float + + // /** + // * Compares two {@code float} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Float#compare(float, float)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(float[], float[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(float[], float[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Float.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(float[] a, float[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Float.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code float} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Float#compare(float, float)}, at a relative + // * index within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(float[], int, int, float[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(float[], int, int, float[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(float[] a, int aFromIndex, int aToIndex, + // float[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Float.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare double + + // /** + // * Compares two {@code double} arrays lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements, as if by + // * {@link Double#compare(double, double)}, at an index within the respective + // * arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(double[], double[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // *

The comparison is consistent with {@link #equals(double[], double[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return Double.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static int compare(double[] a, double[] b) { + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int i = ArraysSupport.mismatch(a, b, + // Math.min(a.length, b.length)); + // if (i >= 0) { + // return Double.compare(a[i], b[i]); + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code double} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements, as if by {@link Double#compare(double, double)}, at a relative + // * index within the respective arrays that is the length of the prefix. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(double[], int, int, double[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(double[], int, int, double[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if: + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int compare(double[] a, int aFromIndex, int aToIndex, + // double[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // Math.min(aLength, bLength)); + // if (i >= 0) { + // return Double.compare(a[aFromIndex + i], b[bFromIndex + i]); + // } + + // return aLength - bLength; + // } + + // // Compare objects + + // /** + // * Compares two {@code Object} arrays, within comparable elements, + // * lexicographically. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing two elements of type {@code T} at + // * an index {@code i} within the respective arrays that is the prefix + // * length, as if by: + // *

{@code
+    //  *     Comparator.nullsFirst(Comparator.naturalOrder()).
+    //  *         compare(a[i], b[i])
+    //  * }
+ // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(Object[], Object[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * A {@code null} array element is considered lexicographically less than a + // * non-{@code null} array element. Two {@code null} array elements are + // * considered equal. + // * + // *

The comparison is consistent with {@link #equals(Object[], Object[]) equals}, + // * more specifically the following holds for arrays {@code a} and {@code b}: + // *

{@code
+    //  *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references + // * and elements): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return a[i].compareTo(b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @param the type of comparable array elements + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @since 9 + // */ + // public static > int compare(T[] a, T[] b) { + // if (a == b) + // return 0; + // // A null array is less than a non-null array + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int length = Math.min(a.length, b.length); + // for (int i = 0; i < length; i++) { + // T oa = a[i]; + // T ob = b[i]; + // if (oa != ob) { + // // A null element is less than a non-null element + // if (oa == null || ob == null) + // return oa == null ? -1 : 1; + // int v = oa.compareTo(ob); + // if (v != 0) { + // return v; + // } + // } + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code Object} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing two + // * elements of type {@code T} at a relative index {@code i} within the + // * respective arrays that is the prefix length, as if by: + // *

{@code
+    //  *     Comparator.nullsFirst(Comparator.naturalOrder()).
+    //  *         compare(a[aFromIndex + i, b[bFromIndex + i])
+    //  * }
+ // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // *

The comparison is consistent with + // * {@link #equals(Object[], int, int, Object[], int, int) equals}, more + // * specifically the following holds for arrays {@code a} and {@code b} with + // * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively: + // *

{@code
+    //  *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+    //  *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+    //  * }
+ // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array elements): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return a[aFromIndex + i].compareTo(b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @param the type of comparable array elements + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static > int compare( + // T[] a, int aFromIndex, int aToIndex, + // T[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // for (int i = 0; i < length; i++) { + // T oa = a[aFromIndex++]; + // T ob = b[bFromIndex++]; + // if (oa != ob) { + // if (oa == null || ob == null) + // return oa == null ? -1 : 1; + // int v = oa.compareTo(ob); + // if (v != 0) { + // return v; + // } + // } + // } + + // return aLength - bLength; + // } + + // /** + // * Compares two {@code Object} arrays lexicographically using a specified + // * comparator. + // * + // *

If the two arrays share a common prefix then the lexicographic + // * comparison is the result of comparing with the specified comparator two + // * elements at an index within the respective arrays that is the prefix + // * length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two array lengths. + // * (See {@link #mismatch(Object[], Object[])} for the definition of a common + // * and proper prefix.) + // * + // *

A {@code null} array reference is considered lexicographically less + // * than a non-{@code null} array reference. Two {@code null} array + // * references are considered equal. + // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array references): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, b, cmp);
+    //  *     if (i >= 0 && i < Math.min(a.length, b.length))
+    //  *         return cmp.compare(a[i], b[i]);
+    //  *     return a.length - b.length;
+    //  * }
+ // * + // * @param a the first array to compare + // * @param b the second array to compare + // * @param cmp the comparator to compare array elements + // * @param the type of array elements + // * @return the value {@code 0} if the first and second array are equal and + // * contain the same elements in the same order; + // * a value less than {@code 0} if the first array is + // * lexicographically less than the second array; and + // * a value greater than {@code 0} if the first array is + // * lexicographically greater than the second array + // * @throws NullPointerException if the comparator is {@code null} + // * @since 9 + // */ + // public static int compare(T[] a, T[] b, + // Comparator cmp) { + // Objects.requireNonNull(cmp); + // if (a == b) + // return 0; + // if (a == null || b == null) + // return a == null ? -1 : 1; + + // int length = Math.min(a.length, b.length); + // for (int i = 0; i < length; i++) { + // T oa = a[i]; + // T ob = b[i]; + // if (oa != ob) { + // // Null-value comparison is deferred to the comparator + // int v = cmp.compare(oa, ob); + // if (v != 0) { + // return v; + // } + // } + // } + + // return a.length - b.length; + // } + + // /** + // * Compares two {@code Object} arrays lexicographically over the specified + // * ranges. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the lexicographic comparison is the result of comparing with the + // * specified comparator two elements at a relative index within the + // * respective arrays that is the prefix length. + // * Otherwise, one array is a proper prefix of the other and, lexicographic + // * comparison is the result of comparing the two range lengths. + // * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the + // * definition of a common and proper prefix.) + // * + // * @apiNote + // *

This method behaves as if (for non-{@code null} array elements): + // *

{@code
+    //  *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+    //  *                             b, bFromIndex, bToIndex, cmp);
+    //  *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  *         return cmp.compare(a[aFromIndex + i], b[bFromIndex + i]);
+    //  *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+    //  * }
+ // * + // * @param a the first array to compare + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be compared + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be compared + // * @param b the second array to compare + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be compared + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be compared + // * @param cmp the comparator to compare array elements + // * @param the type of array elements + // * @return the value {@code 0} if, over the specified ranges, the first and + // * second array are equal and contain the same elements in the same + // * order; + // * a value less than {@code 0} if, over the specified ranges, the + // * first array is lexicographically less than the second array; and + // * a value greater than {@code 0} if, over the specified ranges, the + // * first array is lexicographically greater than the second array + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array or the comparator is {@code null} + // * @since 9 + // */ + // public static int compare( + // T[] a, int aFromIndex, int aToIndex, + // T[] b, int bFromIndex, int bToIndex, + // Comparator cmp) { + // Objects.requireNonNull(cmp); + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // for (int i = 0; i < length; i++) { + // T oa = a[aFromIndex++]; + // T ob = b[bFromIndex++]; + // if (oa != ob) { + // // Null-value comparison is deferred to the comparator + // int v = cmp.compare(oa, ob); + // if (v != 0) { + // return v; + // } + // } + // } + + // return aLength - bLength; + // } + + + // // Mismatch methods + + // // Mismatch boolean + + // /** + // * Finds and returns the index of the first mismatch between two + // * {@code boolean} arrays, otherwise return -1 if no mismatch is found. The + // * index will be in the range of 0 (inclusive) up to the length (inclusive) + // * of the smaller array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     a[pl] != b[pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(boolean[] a, boolean[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code boolean} arrays over the specified ranges, otherwise return -1 if + // * no mismatch is found. The index will be in the range of 0 (inclusive) up + // * to the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     a[aFromIndex + pl] != b[bFromIndex + pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(boolean[] a, int aFromIndex, int aToIndex, + // boolean[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch byte + + // /** + // * Finds and returns the index of the first mismatch between two {@code byte} + // * arrays, otherwise return -1 if no mismatch is found. The index will be + // * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + // * array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     a[pl] != b[pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(byte[] a, byte[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code byte} arrays over the specified ranges, otherwise return -1 if no + // * mismatch is found. The index will be in the range of 0 (inclusive) up to + // * the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     a[aFromIndex + pl] != b[bFromIndex + pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(byte[] a, int aFromIndex, int aToIndex, + // byte[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch char + + // /** + // * Finds and returns the index of the first mismatch between two {@code char} + // * arrays, otherwise return -1 if no mismatch is found. The index will be + // * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + // * array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     a[pl] != b[pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(char[] a, char[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code char} arrays over the specified ranges, otherwise return -1 if no + // * mismatch is found. The index will be in the range of 0 (inclusive) up to + // * the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     a[aFromIndex + pl] != b[bFromIndex + pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(char[] a, int aFromIndex, int aToIndex, + // char[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch short + + // /** + // * Finds and returns the index of the first mismatch between two {@code short} + // * arrays, otherwise return -1 if no mismatch is found. The index will be + // * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + // * array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     a[pl] != b[pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(short[] a, short[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code short} arrays over the specified ranges, otherwise return -1 if no + // * mismatch is found. The index will be in the range of 0 (inclusive) up to + // * the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     a[aFromIndex + pl] != b[bFromIndex + pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(short[] a, int aFromIndex, int aToIndex, + // short[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch int + + // /** + // * Finds and returns the index of the first mismatch between two {@code int} + // * arrays, otherwise return -1 if no mismatch is found. The index will be + // * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + // * array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     a[pl] != b[pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(int[] a, int[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code int} arrays over the specified ranges, otherwise return -1 if no + // * mismatch is found. The index will be in the range of 0 (inclusive) up to + // * the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     a[aFromIndex + pl] != b[bFromIndex + pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(int[] a, int aFromIndex, int aToIndex, + // int[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch long + + // /** + // * Finds and returns the index of the first mismatch between two {@code long} + // * arrays, otherwise return -1 if no mismatch is found. The index will be + // * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + // * array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     a[pl] != b[pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(long[] a, long[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code long} arrays over the specified ranges, otherwise return -1 if no + // * mismatch is found. The index will be in the range of 0 (inclusive) up to + // * the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     a[aFromIndex + pl] != b[bFromIndex + pl]
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(long[] a, int aFromIndex, int aToIndex, + // long[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch float + + // /** + // * Finds and returns the index of the first mismatch between two {@code float} + // * arrays, otherwise return -1 if no mismatch is found. The index will be + // * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + // * array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     Float.compare(a[pl], b[pl]) != 0
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(float[] a, float[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code float} arrays over the specified ranges, otherwise return -1 if no + // * mismatch is found. The index will be in the range of 0 (inclusive) up to + // * the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     Float.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(float[] a, int aFromIndex, int aToIndex, + // float[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch double + + // /** + // * Finds and returns the index of the first mismatch between two + // * {@code double} arrays, otherwise return -1 if no mismatch is found. The + // * index will be in the range of 0 (inclusive) up to the length (inclusive) + // * of the smaller array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     Double.compare(a[pl], b[pl]) != 0
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(double[] a, double[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // int i = ArraysSupport.mismatch(a, b, length); + // return (i < 0 && a.length != b.length) ? length : i; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code double} arrays over the specified ranges, otherwise return -1 if + // * no mismatch is found. The index will be in the range of 0 (inclusive) up + // * to the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     Double.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(double[] a, int aFromIndex, int aToIndex, + // double[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // int i = ArraysSupport.mismatch(a, aFromIndex, + // b, bFromIndex, + // length); + // return (i < 0 && aLength != bLength) ? length : i; + // } + + // // Mismatch objects + + // /** + // * Finds and returns the index of the first mismatch between two + // * {@code Object} arrays, otherwise return -1 if no mismatch is found. The + // * index will be in the range of 0 (inclusive) up to the length (inclusive) + // * of the smaller array. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+    //  *     !Objects.equals(a[pl], b[pl])
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch(Object[] a, Object[] b) { + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // for (int i = 0; i < length; i++) { + // if (!Objects.equals(a[i], b[i])) + // return i; + // } + + // return a.length != b.length ? length : -1; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code Object} arrays over the specified ranges, otherwise return -1 if + // * no mismatch is found. The index will be in the range of 0 (inclusive) up + // * to the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+    //  *     !Objects.equals(a[aFromIndex + pl], b[bFromIndex + pl])
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array is {@code null} + // * @since 9 + // */ + // public static int mismatch( + // Object[] a, int aFromIndex, int aToIndex, + // Object[] b, int bFromIndex, int bToIndex) { + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // for (int i = 0; i < length; i++) { + // if (!Objects.equals(a[aFromIndex++], b[bFromIndex++])) + // return i; + // } + + // return aLength != bLength ? length : -1; + // } + + // /** + // * Finds and returns the index of the first mismatch between two + // * {@code Object} arrays, otherwise return -1 if no mismatch is found. + // * The index will be in the range of 0 (inclusive) up to the length + // * (inclusive) of the smaller array. + // * + // *

The specified comparator is used to determine if two array elements + // * from the each array are not equal. + // * + // *

If the two arrays share a common prefix then the returned index is the + // * length of the common prefix and it follows that there is a mismatch + // * between the two elements at that index within the respective arrays. + // * If one array is a proper prefix of the other then the returned index is + // * the length of the smaller array and it follows that the index is only + // * valid for the larger array. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(a.length, b.length) &&
+    //  *     Arrays.equals(a, 0, pl, b, 0, pl, cmp)
+    //  *     cmp.compare(a[pl], b[pl]) != 0
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     a.length != b.length &&
+    //  *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+    //  *                   b, 0, Math.min(a.length, b.length),
+    //  *                   cmp)
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param b the second array to be tested for a mismatch + // * @param cmp the comparator to compare array elements + // * @param the type of array elements + // * @return the index of the first mismatch between the two arrays, + // * otherwise {@code -1}. + // * @throws NullPointerException + // * if either array or the comparator is {@code null} + // * @since 9 + // */ + // public static int mismatch(T[] a, T[] b, Comparator cmp) { + // Objects.requireNonNull(cmp); + // int length = Math.min(a.length, b.length); // Check null array refs + // if (a == b) + // return -1; + + // for (int i = 0; i < length; i++) { + // T oa = a[i]; + // T ob = b[i]; + // if (oa != ob) { + // // Null-value comparison is deferred to the comparator + // int v = cmp.compare(oa, ob); + // if (v != 0) { + // return i; + // } + // } + // } + + // return a.length != b.length ? length : -1; + // } + + // /** + // * Finds and returns the relative index of the first mismatch between two + // * {@code Object} arrays over the specified ranges, otherwise return -1 if + // * no mismatch is found. The index will be in the range of 0 (inclusive) up + // * to the length (inclusive) of the smaller range. + // * + // *

If the two arrays, over the specified ranges, share a common prefix + // * then the returned relative index is the length of the common prefix and + // * it follows that there is a mismatch between the two elements at that + // * relative index within the respective arrays. + // * If one array is a proper prefix of the other, over the specified ranges, + // * then the returned relative index is the length of the smaller range and + // * it follows that the relative index is only valid for the array with the + // * larger range. + // * Otherwise, there is no mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + // * prefix of length {@code pl} if the following expression is true: + // *

{@code
+    //  *     pl >= 0 &&
+    //  *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
+    //  *     cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+    //  * }
+ // * Note that a common prefix length of {@code 0} indicates that the first + // * elements from each array mismatch. + // * + // *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + // * ranges [{@code aFromIndex}, {@code atoIndex}) and + // * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + // * prefix if the following expression is true: + // *

{@code
+    //  *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+    //  *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+    //  *                   cmp)
+    //  * }
+ // * + // * @param a the first array to be tested for a mismatch + // * @param aFromIndex the index (inclusive) of the first element in the + // * first array to be tested + // * @param aToIndex the index (exclusive) of the last element in the + // * first array to be tested + // * @param b the second array to be tested for a mismatch + // * @param bFromIndex the index (inclusive) of the first element in the + // * second array to be tested + // * @param bToIndex the index (exclusive) of the last element in the + // * second array to be tested + // * @param cmp the comparator to compare array elements + // * @param the type of array elements + // * @return the relative index of the first mismatch between the two arrays + // * over the specified ranges, otherwise {@code -1}. + // * @throws IllegalArgumentException + // * if {@code aFromIndex > aToIndex} or + // * if {@code bFromIndex > bToIndex} + // * @throws ArrayIndexOutOfBoundsException + // * if {@code aFromIndex < 0 or aToIndex > a.length} or + // * if {@code bFromIndex < 0 or bToIndex > b.length} + // * @throws NullPointerException + // * if either array or the comparator is {@code null} + // * @since 9 + // */ + // public static int mismatch( + // T[] a, int aFromIndex, int aToIndex, + // T[] b, int bFromIndex, int bToIndex, + // Comparator cmp) { + // Objects.requireNonNull(cmp); + // rangeCheck(a.length, aFromIndex, aToIndex); + // rangeCheck(b.length, bFromIndex, bToIndex); + + // int aLength = aToIndex - aFromIndex; + // int bLength = bToIndex - bFromIndex; + // int length = Math.min(aLength, bLength); + // for (int i = 0; i < length; i++) { + // T oa = a[aFromIndex++]; + // T ob = b[bFromIndex++]; + // if (oa != ob) { + // // Null-value comparison is deferred to the comparator + // int v = cmp.compare(oa, ob); + // if (v != 0) { + // return i; + // } + // } + // } + + // return aLength != bLength ? length : -1; + // } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java index 8fa2262d77..bcf490340f 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, 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 @@ -24,7 +24,6 @@ */ package java.util; -import java.util.concurrent.RecursiveAction; import java.util.concurrent.CountedCompleter; /** @@ -36,7 +35,7 @@ * Sorter classes based mainly on CilkSort * Cilk: * Basic algorithm: - * if array size is small, just use a sequential quicksort (via Arrays.sort) + * if array size is small, just use a sequential sort (via Arrays.sort) * Otherwise: * 1. Break array in half. * 2. For each half, @@ -63,14 +62,10 @@ * need to keep track of the arrays, and are never themselves forked, * so don't hold any task state. * - * The primitive class versions (FJByte... FJDouble) are - * identical to each other except for type declarations. - * * The base sequential sorts rely on non-public versions of TimSort, - * ComparableTimSort, and DualPivotQuicksort sort methods that accept - * temp workspace array slices that we will have already allocated, so - * avoids redundant allocation. (Except for DualPivotQuicksort byte[] - * sort, that does not ever use a workspace array.) + * ComparableTimSort sort methods that accept temp workspace array + * slices that we will have already allocated, so avoids redundant + * allocation. */ /*package*/ class ArraysParallelSortHelpers { @@ -87,6 +82,7 @@ * quartile task, that does not need to maintain array state. */ static final class EmptyCompleter extends CountedCompleter { + @java.io.Serial static final long serialVersionUID = 2446542900576103244L; EmptyCompleter(CountedCompleter p) { super(p); } public final void compute() { } @@ -96,6 +92,7 @@ public final void compute() { } * A trigger for secondary merge of two merges */ static final class Relay extends CountedCompleter { + @java.io.Serial static final long serialVersionUID = 2446542900576103244L; final CountedCompleter task; Relay(CountedCompleter task) { @@ -111,9 +108,14 @@ public final void onCompletion(CountedCompleter t) { /** Object + Comparator support class */ static final class FJObject { static final class Sorter extends CountedCompleter { + @java.io.Serial static final long serialVersionUID = 2446542900576103244L; - final T[] a, w; + @SuppressWarnings("serial") // Not statically typed as Serializable + final T[] a; + @SuppressWarnings("serial") // Not statically typed as Serializable + final T[] w; final int base, size, wbase, gran; + @SuppressWarnings("serial") // Not statically typed as Serializable Comparator comparator; Sorter(CountedCompleter par, T[] a, T[] w, int base, int size, int wbase, int gran, @@ -130,15 +132,15 @@ public final void compute() { int b = this.base, n = this.size, wb = this.wbase, g = this.gran; while (n > g) { int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g, c)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g, c)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g, c).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g, c).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g, c)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g, c).fork(); + Relay fc = new Relay(new Merger<>(s, w, a, wb, h, + wb+h, n-h, b, g, c)); + Relay rc = new Relay(new Merger<>(fc, a, w, b+h, q, + b+u, n-u, wb+h, g, c)); + new Sorter<>(rc, a, w, b+u, n-u, wb+u, g, c).fork(); + new Sorter<>(rc, a, w, b+h, q, wb+h, g, c).fork(); + Relay bc = new Relay(new Merger<>(fc, a, w, b, q, + b+q, h-q, wb, g, c)); + new Sorter<>(bc, a, w, b+q, h-q, wb+q, g, c).fork(); s = new EmptyCompleter(bc); n = q; } @@ -148,9 +150,15 @@ public final void compute() { } static final class Merger extends CountedCompleter { + @java.io.Serial static final long serialVersionUID = 2446542900576103244L; - final T[] a, w; // main and workspace arrays + // main and workspace arrays + @SuppressWarnings("serial") // Not statically typed as Serializable + final T[] a; + @SuppressWarnings("serial") // Not statically typed as Serializable + final T[] w; final int lbase, lsize, rbase, rsize, wbase, gran; + @SuppressWarnings("serial") // Not statically typed as Serializable Comparator comparator; Merger(CountedCompleter par, T[] a, T[] w, int lbase, int lsize, int rbase, @@ -199,9 +207,9 @@ public final void compute() { lo = lm + 1; } } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g, c); + Merger m = new Merger<>(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g, c); rn = rh; ln = lh; addToPendingCount(1); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Base64.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Base64.java index be98fadfa0..8577fee3a6 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Base64.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Base64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -25,6 +25,10 @@ package java.util; +/* J2ObjC removed +import jdk.internal.HotSpotIntrinsicCandidate; +*/ + import java.io.FilterOutputStream; import java.io.InputStream; import java.io.IOException; @@ -32,6 +36,9 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +// Android-removed: class is not present in Android. +// import sun.nio.cs.ISO_8859_1; + /** * This class consists exclusively of static methods for obtaining * encoders and decoders for the Base64 encoding scheme. The @@ -41,22 +48,22 @@ * RFC 2045. * *
    - *
  • Basic + *
  • Basic *

    Uses "The Base64 Alphabet" as specified in Table 1 of * RFC 4648 and RFC 2045 for encoding and decoding operation. * The encoder does not add any line feed (line separator) * character. The decoder rejects data that contains characters * outside the base64 alphabet.

  • * - *
  • URL and Filename safe + *
  • URL and Filename safe *

    Uses the "URL and Filename safe Base64 Alphabet" as specified * in Table 2 of RFC 4648 for encoding and decoding. The * encoder does not add any line feed (line separator) character. * The decoder rejects data that contains characters outside the * base64 alphabet.

  • * - *
  • MIME - *

    Uses the "The Base64 Alphabet" as specified in Table 1 of + *

  • MIME + *

    Uses "The Base64 Alphabet" as specified in Table 1 of * RFC 2045 for encoding and decoding operation. The encoded output * must be represented in lines of no more than 76 characters each * and uses a carriage return {@code '\r'} followed immediately by @@ -116,8 +123,8 @@ public static Encoder getMimeEncoder() { * * @param lineLength * the length of each output line (rounded down to nearest multiple - * of 4). If {@code lineLength <= 0} the output will not be separated - * in lines + * of 4). If the rounded down line length is not a positive value, + * the output will not be separated in lines * @param lineSeparator * the line separator for each output line * @@ -135,10 +142,12 @@ public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) { throw new IllegalArgumentException( "Illegal base64 line separator character 0x" + Integer.toString(b, 16)); } + // round down to nearest multiple of 4 + lineLength &= ~0b11; if (lineLength <= 0) { return Encoder.RFC4648; } - return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true); + return new Encoder(false, lineSeparator, lineLength, true); } /** @@ -387,6 +396,22 @@ public Encoder withoutPadding() { return this; return new Encoder(isURL, newline, linemax, false); } + + /* J2ObjC removed + @HotSpotIntrinsicCandidate + */ + private void encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL) { + char[] base64 = isURL ? toBase64URL : toBase64; + for (int sp0 = sp, dp0 = dp ; sp0 < sl; ) { + int bits = (src[sp0++] & 0xff) << 16 | + (src[sp0++] & 0xff) << 8 | + (src[sp0++] & 0xff); + dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f]; + dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f]; + dst[dp0++] = (byte)base64[(bits >>> 6) & 0x3f]; + dst[dp0++] = (byte)base64[bits & 0x3f]; + } + } private int encode0(byte[] src, int off, int end, byte[] dst) { char[] base64 = isURL ? toBase64URL : toBase64; @@ -398,15 +423,7 @@ private int encode0(byte[] src, int off, int end, byte[] dst) { int dp = 0; while (sp < sl) { int sl0 = Math.min(sp + slen, sl); - for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) { - int bits = (src[sp0++] & 0xff) << 16 | - (src[sp0++] & 0xff) << 8 | - (src[sp0++] & 0xff); - dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f]; - dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f]; - dst[dp0++] = (byte)base64[(bits >>> 6) & 0x3f]; - dst[dp0++] = (byte)base64[bits & 0x3f]; - } + encodeBlock(src, sp, sl0, dst, dp, isURL); int dlen = (sl0 - sp) / 3 * 4; dp += dlen; sp = sl0; @@ -546,6 +563,8 @@ public byte[] decode(byte[] src) { * if {@code src} is not in valid Base64 scheme */ public byte[] decode(String src) { + // Android-changed: keep Java 8 implementation. + // return decode(src.getBytes(ISO_8859_1.INSTANCE)); return decode(src.getBytes(StandardCharsets.ISO_8859_1)); } @@ -556,7 +575,7 @@ public byte[] decode(String src) { * *

    It is the responsibility of the invoker of this method to make * sure the output byte array {@code dst} has enough space for decoding - * all bytes from the input byte array. No bytes will be be written to + * all bytes from the input byte array. No bytes will be written to * the output byte array if the output byte array is not big enough. * *

    If the input byte array is not in valid Base64 encoding scheme @@ -690,7 +709,27 @@ private int decode0(byte[] src, int sp, int sl, byte[] dst) { int dp = 0; int bits = 0; int shiftto = 18; // pos of first byte of 4-byte atom + while (sp < sl) { + if (shiftto == 18 && sp + 4 < sl) { // fast path + int sl0 = sp + ((sl - sp) & ~0b11); + while (sp < sl0) { + int b1 = base64[src[sp++] & 0xff]; + int b2 = base64[src[sp++] & 0xff]; + int b3 = base64[src[sp++] & 0xff]; + int b4 = base64[src[sp++] & 0xff]; + if ((b1 | b2 | b3 | b4) < 0) { // non base64 byte + sp -= 4; + break; + } + int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4; + dst[dp++] = (byte)(bits0 >> 16); + dst[dp++] = (byte)(bits0 >> 8); + dst[dp++] = (byte)(bits0); + } + if (sp >= sl) + break; + } int b = src[sp++] & 0xff; if ((b = base64[b]) < 0) { if (b == -2) { // padding byte '=' @@ -737,7 +776,7 @@ private int decode0(byte[] src, int sp, int sl, byte[] dst) { // anything left is invalid, if is not MIME. // if MIME, ignore all non-base64 character while (sp < sl) { - if (isMIME && base64[src[sp++]] < 0) + if (isMIME && base64[src[sp++] & 0xff] < 0) continue; throw new IllegalArgumentException( "Input byte array has incorrect ending byte at " + sp); @@ -760,6 +799,7 @@ private static class EncOutputStream extends FilterOutputStream { private final int linemax; private final boolean doPadding;// whether or not to pad private int linepos = 0; + private byte[] buf; EncOutputStream(OutputStream os, char[] base64, byte[] newline, int linemax, boolean doPadding) { @@ -768,6 +808,7 @@ private static class EncOutputStream extends FilterOutputStream { this.newline = newline; this.linemax = linemax; this.doPadding = doPadding; + this.buf = new byte[linemax <= 0 ? 8124 : linemax]; } @Override @@ -784,13 +825,18 @@ private void checkNewline() throws IOException { } } + private void writeb4(char b1, char b2, char b3, char b4) throws IOException { + buf[0] = (byte)b1; + buf[1] = (byte)b2; + buf[2] = (byte)b3; + buf[3] = (byte)b4; + out.write(buf, 0, 4); + } + @Override public void write(byte[] b, int off, int len) throws IOException { if (closed) throw new IOException("Stream is closed"); - // Android-changed: Upstream fix to avoid overflow. - // This upstream fix is from beyond OpenJDK8u121-b13. http://b/62368386 - // if (off < 0 || len < 0 || off + len > b.length) if (off < 0 || len < 0 || len > b.length - off) throw new ArrayIndexOutOfBoundsException(); if (len == 0) @@ -807,25 +853,34 @@ public void write(byte[] b, int off, int len) throws IOException { b2 = b[off++] & 0xff; len--; checkNewline(); - out.write(base64[b0 >> 2]); - out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]); - out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]); - out.write(base64[b2 & 0x3f]); + writeb4(base64[b0 >> 2], + base64[(b0 << 4) & 0x3f | (b1 >> 4)], + base64[(b1 << 2) & 0x3f | (b2 >> 6)], + base64[b2 & 0x3f]); linepos += 4; } int nBits24 = len / 3; leftover = len - (nBits24 * 3); - while (nBits24-- > 0) { + + while (nBits24 > 0) { checkNewline(); - int bits = (b[off++] & 0xff) << 16 | - (b[off++] & 0xff) << 8 | - (b[off++] & 0xff); - out.write(base64[(bits >>> 18) & 0x3f]); - out.write(base64[(bits >>> 12) & 0x3f]); - out.write(base64[(bits >>> 6) & 0x3f]); - out.write(base64[bits & 0x3f]); - linepos += 4; - } + int dl = linemax <= 0 ? buf.length : buf.length - linepos; + int sl = off + Math.min(nBits24, dl / 4) * 3; + int dp = 0; + for (int sp = off; sp < sl; ) { + int bits = (b[sp++] & 0xff) << 16 | + (b[sp++] & 0xff) << 8 | + (b[sp++] & 0xff); + buf[dp++] = (byte)base64[(bits >>> 18) & 0x3f]; + buf[dp++] = (byte)base64[(bits >>> 12) & 0x3f]; + buf[dp++] = (byte)base64[(bits >>> 6) & 0x3f]; + buf[dp++] = (byte)base64[bits & 0x3f]; + } + out.write(buf, 0, dp); + off = sl; + linepos += dp; + nBits24 -= dp / 4; + } if (leftover == 1) { b0 = b[off++] & 0xff; } else if (leftover == 2) { @@ -890,6 +945,52 @@ public int read() throws IOException { return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff; } + private int eof(byte[] b, int off, int len, int oldOff) + throws IOException + { + eof = true; + if (nextin != 18) { + if (nextin == 12) + throw new IOException("Base64 stream has one un-decoded dangling byte."); + // treat ending xx/xxx without padding character legal. + // same logic as v == '=' below + b[off++] = (byte)(bits >> (16)); + if (nextin == 0) { // only one padding byte + if (len == 1) { // no enough output space + bits >>= 8; // shift to lowest byte + nextout = 0; + } else { + b[off++] = (byte) (bits >> 8); + } + } + } + return off == oldOff ? -1 : off - oldOff; + } + + private int padding(byte[] b, int off, int len, int oldOff) + throws IOException + { + // = shiftto==18 unnecessary padding + // x= shiftto==12 dangling x, invalid unit + // xx= shiftto==6 && missing last '=' + // xx=y or last is not '=' + if (nextin == 18 || nextin == 12 || + nextin == 6 && is.read() != '=') { + throw new IOException("Illegal base64 ending sequence:" + nextin); + } + b[off++] = (byte)(bits >> (16)); + if (nextin == 0) { // only one padding byte + if (len == 1) { // no enough output space + bits >>= 8; // shift to lowest byte + nextout = 0; + } else { + b[off++] = (byte) (bits >> 8); + } + } + eof = true; + return off - oldOff; + } + @Override public int read(byte[] b, int off, int len) throws IOException { if (closed) @@ -899,82 +1000,46 @@ public int read(byte[] b, int off, int len) throws IOException { if (off < 0 || len < 0 || len > b.length - off) throw new IndexOutOfBoundsException(); int oldOff = off; - if (nextout >= 0) { // leftover output byte(s) in bits buf - do { - if (len == 0) - return off - oldOff; - b[off++] = (byte)(bits >> nextout); - len--; - nextout -= 8; - } while (nextout >= 0); - bits = 0; + while (nextout >= 0) { // leftover output byte(s) in bits buf + if (len == 0) + return off - oldOff; + b[off++] = (byte)(bits >> nextout); + len--; + nextout -= 8; } + bits = 0; while (len > 0) { int v = is.read(); if (v == -1) { - eof = true; - if (nextin != 18) { - if (nextin == 12) - throw new IOException("Base64 stream has one un-decoded dangling byte."); - // treat ending xx/xxx without padding character legal. - // same logic as v == '=' below - b[off++] = (byte)(bits >> (16)); - len--; - if (nextin == 0) { // only one padding byte - if (len == 0) { // no enough output space - bits >>= 8; // shift to lowest byte - nextout = 0; - } else { - b[off++] = (byte) (bits >> 8); - } - } - } - if (off == oldOff) - return -1; - else - return off - oldOff; + return eof(b, off, len, oldOff); } - if (v == '=') { // padding byte(s) - // = shiftto==18 unnecessary padding - // x= shiftto==12 dangling x, invalid unit - // xx= shiftto==6 && missing last '=' - // xx=y or last is not '=' - if (nextin == 18 || nextin == 12 || - nextin == 6 && is.read() != '=') { - throw new IOException("Illegal base64 ending sequence:" + nextin); + if ((v = base64[v]) < 0) { + if (v == -2) { // padding byte(s) + return padding(b, off, len, oldOff); } - b[off++] = (byte)(bits >> (16)); - len--; - if (nextin == 0) { // only one padding byte - if (len == 0) { // no enough output space - bits >>= 8; // shift to lowest byte - nextout = 0; - } else { - b[off++] = (byte) (bits >> 8); - } + if (v == -1) { + if (!isMIME) + throw new IOException("Illegal base64 character " + + Integer.toString(v, 16)); + continue; // skip if for rfc2045 } - eof = true; - break; - } - if ((v = base64[v]) == -1) { - if (isMIME) // skip if for rfc2045 - continue; - else - throw new IOException("Illegal base64 character " + - Integer.toString(v, 16)); + // neve be here } bits |= (v << nextin); if (nextin == 0) { - nextin = 18; // clear for next - nextout = 16; - while (nextout >= 0) { - b[off++] = (byte)(bits >> nextout); - len--; - nextout -= 8; - if (len == 0 && nextout >= 0) { // don't clean "bits" - return off - oldOff; - } + nextin = 18; // clear for next in + b[off++] = (byte)(bits >> 16); + if (len == 1) { + nextout = 8; // 2 bytes left in bits + break; + } + b[off++] = (byte)(bits >> 8); + if (len == 2) { + nextout = 0; // 1 byte left in bits + break; } + b[off++] = (byte)bits; + len -= 3; bits = 0; } else { nextin -= 6; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/BitSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/BitSet.java index 261a77c12a..c72970def0 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/BitSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/BitSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2018, 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 @@ -29,6 +29,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.LongBuffer; +import java.util.function.IntConsumer; import java.util.stream.IntStream; import java.util.stream.StreamSupport; @@ -60,7 +61,7 @@ * @author Arthur van Hoff * @author Michael McCloskey * @author Martin Buchholz - * @since JDK1.0 + * @since 1.0 */ public class BitSet implements Cloneable, java.io.Serializable { /* @@ -68,9 +69,9 @@ public class BitSet implements Cloneable, java.io.Serializable { * a long, which consists of 64 bits, requiring 6 address bits. * The choice of word size is determined purely by performance concerns. */ - private final static int ADDRESS_BITS_PER_WORD = 6; - private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; - private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1; + private static final int ADDRESS_BITS_PER_WORD = 6; + private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; + private static final int BIT_INDEX_MASK = BITS_PER_WORD - 1; /* Used to shift left or right for a partial word mask */ private static final long WORD_MASK = 0xffffffffffffffffL; @@ -437,7 +438,7 @@ public void flip(int fromIndex, int toIndex) { * * @param bitIndex a bit index * @throws IndexOutOfBoundsException if the specified index is negative - * @since JDK1.0 + * @since 1.0 */ public void set(int bitIndex) { if (bitIndex < 0) @@ -533,7 +534,7 @@ public void set(int fromIndex, int toIndex, boolean value) { * * @param bitIndex the index of the bit to be cleared * @throws IndexOutOfBoundsException if the specified index is negative - * @since JDK1.0 + * @since 1.0 */ public void clear(int bitIndex) { if (bitIndex < 0) @@ -1209,40 +1210,186 @@ public String toString() { * is the number of bits in the set state, equal to the value * returned by the {@link #cardinality()} method. * - *

    The bit set must remain constant during the execution of the - * terminal stream operation. Otherwise, the result of the terminal - * stream operation is undefined. + *

    The stream binds to this bit set when the terminal stream operation + * commences (specifically, the spliterator for the stream is + * late-binding). If the + * bit set is modified during that operation then the result is undefined. * * @return a stream of integers representing set indices * @since 1.8 */ public IntStream stream() { - class BitSetIterator implements PrimitiveIterator.OfInt { - int next = nextSetBit(0); + class BitSetSpliterator implements Spliterator.OfInt { + private int index; // current bit index for a set bit + private int fence; // -1 until used; then one past last bit index + private int est; // size estimate + private boolean root; // true if root and not split + // root == true then size estimate is accurate + // index == -1 or index >= fence if fully traversed + // Special case when the max bit set is Integer.MAX_VALUE + + BitSetSpliterator(int origin, int fence, int est, boolean root) { + this.index = origin; + this.fence = fence; + this.est = est; + this.root = root; + } + + private int getFence() { + int hi; + if ((hi = fence) < 0) { + // Round up fence to maximum cardinality for allocated words + // This is sufficient and cheap for sequential access + // When splitting this value is lowered + hi = fence = (wordsInUse >= wordIndex(Integer.MAX_VALUE)) + ? Integer.MAX_VALUE + : wordsInUse << ADDRESS_BITS_PER_WORD; + est = cardinality(); + index = nextSetBit(0); + } + return hi; + } @Override - public boolean hasNext() { - return next != -1; + public boolean tryAdvance(IntConsumer action) { + Objects.requireNonNull(action); + + int hi = getFence(); + int i = index; + if (i < 0 || i >= hi) { + // Check if there is a final bit set for Integer.MAX_VALUE + if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) { + index = -1; + action.accept(Integer.MAX_VALUE); + return true; + } + return false; + } + + index = nextSetBit(i + 1, wordIndex(hi - 1)); + action.accept(i); + return true; } @Override - public int nextInt() { - if (next != -1) { - int ret = next; - next = nextSetBit(next+1); - return ret; - } else { - throw new NoSuchElementException(); + public void forEachRemaining(IntConsumer action) { + Objects.requireNonNull(action); + + int hi = getFence(); + int i = index; + index = -1; + + if (i >= 0 && i < hi) { + action.accept(i++); + + int u = wordIndex(i); // next lower word bound + int v = wordIndex(hi - 1); // upper word bound + + words_loop: + for (; u <= v && i <= hi; u++, i = u << ADDRESS_BITS_PER_WORD) { + long word = words[u] & (WORD_MASK << i); + while (word != 0) { + i = (u << ADDRESS_BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + if (i >= hi) { + // Break out of outer loop to ensure check of + // Integer.MAX_VALUE bit set + break words_loop; + } + + // Flip the set bit + word &= ~(1L << i); + + action.accept(i); + } + } + } + + // Check if there is a final bit set for Integer.MAX_VALUE + if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) { + action.accept(Integer.MAX_VALUE); } } + + @Override + public OfInt trySplit() { + int hi = getFence(); + int lo = index; + if (lo < 0) { + return null; + } + + // Lower the fence to be the upper bound of last bit set + // The index is the first bit set, thus this spliterator + // covers one bit and cannot be split, or two or more + // bits + hi = fence = (hi < Integer.MAX_VALUE || !get(Integer.MAX_VALUE)) + ? previousSetBit(hi - 1) + 1 + : Integer.MAX_VALUE; + + // Find the mid point + int mid = (lo + hi) >>> 1; + if (lo >= mid) { + return null; + } + + // Raise the index of this spliterator to be the next set bit + // from the mid point + index = nextSetBit(mid, wordIndex(hi - 1)); + root = false; + + // Don't lower the fence (mid point) of the returned spliterator, + // traversal or further splitting will do that work + return new BitSetSpliterator(lo, mid, est >>>= 1, false); + } + + @Override + public long estimateSize() { + getFence(); // force init + return est; + } + + @Override + public int characteristics() { + // Only sized when root and not split + return (root ? Spliterator.SIZED : 0) | + Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED; + } + + @Override + public Comparator getComparator() { + return null; + } } + return StreamSupport.intStream(new BitSetSpliterator(0, -1, 0, true), false); + } - return StreamSupport.intStream( - () -> Spliterators.spliterator( - new BitSetIterator(), cardinality(), - Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED), - Spliterator.SIZED | Spliterator.SUBSIZED | - Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED, - false); + /** + * Returns the index of the first bit that is set to {@code true} + * that occurs on or after the specified starting index and up to and + * including the specified word index + * If no such bit exists then {@code -1} is returned. + * + * @param fromIndex the index to start checking from (inclusive) + * @param toWordIndex the last word index to check (inclusive) + * @return the index of the next set bit, or {@code -1} if there + * is no such bit + */ + private int nextSetBit(int fromIndex, int toWordIndex) { + int u = wordIndex(fromIndex); + // Check if out of bounds + if (u > toWordIndex) + return -1; + + long word = words[u] & (WORD_MASK << fromIndex); + + while (true) { + if (word != 0) + return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + // Check if out of bounds + if (++u > toWordIndex) + return -1; + word = words[u]; + } } + } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Calendar.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Calendar.java index 86e6f69856..a10229e6e4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Calendar.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Calendar.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, 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 @@ -42,20 +42,21 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.io.OptionalDataException; import java.io.Serializable; -/*import java.security.AccessControlContext; -import java.security.AccessController; +import java.security.AccessControlContext; import java.security.PermissionCollection; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.security.ProtectionDomain;*/ +import java.security.ProtectionDomain; import java.text.DateFormat; import java.text.DateFormatSymbols; +import java.time.Instant; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import libcore.icu.ICU; import libcore.icu.LocaleData; +import sun.util.locale.provider.CalendarDataUtility; +// Android-changed: Remove "rg" support in the javadoc. See http://b/228322300. +// Android-changed: Support the "fw" extension since Android 13. /** * The Calendar class is an abstract class that provides methods * for converting between a specific instant in time and a set of {@link @@ -63,7 +64,7 @@ * DAY_OF_MONTH, HOUR, and so on, and for * manipulating the calendar fields, such as getting the date of the next * week. An instant in time can be represented by a millisecond value that is - * an offset from the Epoch, January 1, 1970 + * an offset from the Epoch, January 1, 1970 * 00:00:00.000 GMT (Gregorian). * *

    The class also provides additional fields and methods for @@ -120,13 +121,17 @@ * calculating its time or calendar field values if any out-of-range field * value has been set. * - *

    First Week

    + *

    First Week

    * * Calendar defines a locale-specific seven day week using two * parameters: the first day of the week and the minimal days in first week - * (from 1 to 7). These numbers are taken from the locale resource data when a - * Calendar is constructed. They may also be specified explicitly - * through the methods for setting their values. + * (from 1 to 7). These numbers are taken from the locale resource data or the + * locale itself when a {@code Calendar} is constructed. If the designated + * locale contains "fw" + * Unicode extensions, the first day of the week will be obtained according to + * those extensions. + * They may also be specified explicitly through the methods for setting their + * values. * *

    When setting or getting the WEEK_OF_MONTH or * WEEK_OF_YEAR fields, Calendar must determine the @@ -150,13 +155,13 @@ * calendar field values to determine the date and time in the * following way. * - *

    If there is any conflict in calendar field values, + *

    If there is any conflict in calendar field values, * Calendar gives priorities to calendar fields that have been set * more recently. The following are the default combinations of the * calendar fields. The most recent combination, as determined by the * most recently set single field, will be used. * - *

    For the date fields: + *

    For the date fields: *

    *
      * YEAR + MONTH + DAY_OF_MONTH
    @@ -166,7 +171,7 @@
      * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
      * 
    * - * For the time of day fields: + * For the time of day fields: *
    *
      * HOUR_OF_DAY
    @@ -304,7 +309,7 @@
      * @see          TimeZone
      * @see          java.text.DateFormat
      * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
    - * @since JDK1.1
    + * @since 1.1
      */
     public abstract class Calendar implements Serializable, Cloneable, Comparable {
     
    @@ -366,13 +371,13 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
          * year. This is a calendar-specific value; see subclass documentation.
          */
    -    public final static int YEAR = 1;
    +    public static final int YEAR = 1;
     
         /**
          * Field number for get and set indicating the
    @@ -395,7 +400,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -408,7 +413,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -421,7 +426,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -430,7 +435,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -439,13 +444,13 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the day
          * number within the current year.  The first day of the year has value 1.
          */
    -    public final static int DAY_OF_YEAR = 6;
    +    public static final int DAY_OF_YEAR = 6;
     
         /**
          * Field number for get and set indicating the day
    @@ -461,7 +466,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -486,7 +491,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating
    @@ -497,7 +502,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -508,7 +513,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
    @@ -517,28 +522,28 @@ public abstract class Calendar implements Serializable, Cloneable, Comparableget and set indicating the
          * minute within the hour.
          * E.g., at 10:04:15.250 PM the MINUTE is 4.
          */
    -    public final static int MINUTE = 12;
    +    public static final int MINUTE = 12;
     
         /**
          * Field number for get and set indicating the
          * second within the minute.
          * E.g., at 10:04:15.250 PM the SECOND is 15.
          */
    -    public final static int SECOND = 13;
    +    public static final int SECOND = 13;
     
         /**
          * Field number for get and set indicating the
          * millisecond within the second.
          * E.g., at 10:04:15.250 PM the MILLISECOND is 250.
          */
    -    public final static int MILLISECOND = 14;
    +    public static final int MILLISECOND = 14;
     
         /**
          * Field number for get and set
    @@ -549,7 +554,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableTimeZone implementation subclass supports
          * historical GMT offset changes.
          */
    -    public final static int ZONE_OFFSET = 15;
    +    public static final int ZONE_OFFSET = 15;
     
         /**
          * Field number for get and set indicating the
    @@ -560,146 +565,146 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableTimeZone implementation subclass supports
          * historical Daylight Saving Time schedule changes.
          */
    -    public final static int DST_OFFSET = 16;
    +    public static final int DST_OFFSET = 16;
     
         /**
          * The number of distinct fields recognized by get and set.
          * Field numbers range from 0..FIELD_COUNT-1.
          */
    -    public final static int FIELD_COUNT = 17;
    +    public static final int FIELD_COUNT = 17;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Sunday.
          */
    -    public final static int SUNDAY = 1;
    +    public static final int SUNDAY = 1;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Monday.
          */
    -    public final static int MONDAY = 2;
    +    public static final int MONDAY = 2;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Tuesday.
          */
    -    public final static int TUESDAY = 3;
    +    public static final int TUESDAY = 3;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Wednesday.
          */
    -    public final static int WEDNESDAY = 4;
    +    public static final int WEDNESDAY = 4;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Thursday.
          */
    -    public final static int THURSDAY = 5;
    +    public static final int THURSDAY = 5;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Friday.
          */
    -    public final static int FRIDAY = 6;
    +    public static final int FRIDAY = 6;
     
         /**
          * Value of the {@link #DAY_OF_WEEK} field indicating
          * Saturday.
          */
    -    public final static int SATURDAY = 7;
    +    public static final int SATURDAY = 7;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * first month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int JANUARY = 0;
    +    public static final int JANUARY = 0;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * second month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int FEBRUARY = 1;
    +    public static final int FEBRUARY = 1;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * third month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int MARCH = 2;
    +    public static final int MARCH = 2;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * fourth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int APRIL = 3;
    +    public static final int APRIL = 3;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * fifth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int MAY = 4;
    +    public static final int MAY = 4;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * sixth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int JUNE = 5;
    +    public static final int JUNE = 5;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * seventh month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int JULY = 6;
    +    public static final int JULY = 6;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * eighth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int AUGUST = 7;
    +    public static final int AUGUST = 7;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * ninth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int SEPTEMBER = 8;
    +    public static final int SEPTEMBER = 8;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * tenth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int OCTOBER = 9;
    +    public static final int OCTOBER = 9;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * eleventh month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int NOVEMBER = 10;
    +    public static final int NOVEMBER = 10;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * twelfth month of the year in the Gregorian and Julian calendars.
          */
    -    public final static int DECEMBER = 11;
    +    public static final int DECEMBER = 11;
     
         /**
          * Value of the {@link #MONTH} field indicating the
          * thirteenth month of the year. Although GregorianCalendar
          * does not use this value, lunar calendars do.
          */
    -    public final static int UNDECIMBER = 12;
    +    public static final int UNDECIMBER = 12;
     
         /**
          * Value of the {@link #AM_PM} field indicating the
          * period of the day from midnight to just before noon.
          */
    -    public final static int AM = 0;
    +    public static final int AM = 0;
     
         /**
          * Value of the {@link #AM_PM} field indicating the
          * period of the day from noon to just before midnight.
          */
    -    public final static int PM = 1;
    +    public static final int PM = 1;
     
         /**
          * A style specifier for {@link #getDisplayNames(int, int, Locale)
    @@ -852,7 +857,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableTrue if zone references to a shared TimeZone object.
          */
    -    transient private boolean sharedZone = false;
    +    private transient boolean sharedZone = false;
     
         /**
          * The first day of the week, with possible values SUNDAY,
    @@ -990,7 +995,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableserialVersionOnStream
          * is written.
          * @serial
    -     * @since JDK1.1.6
    +     * @since 1.1.6
          */
         private int             serialVersionOnStream = currentSerialVersion;
     
    @@ -999,24 +1004,24 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableTimeZone} will be used in the {@link #build() build}
              * method.
    @@ -1396,7 +1401,7 @@ public Builder setLocale(Locale locale) {
             /**
              * Sets the week definition parameters to the values given by
              * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are
    -         * used to determine the first
    +         * used to determine the first
              * week of a year. The parameters given by this method have
              * precedence over the default values given by the
              * {@linkplain #setLocale(Locale) locale}.
    @@ -1421,6 +1426,7 @@ public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek)
                 return this;
             }
     
    +        // Android-changed: Support the "tz" extension since Android 13.
             /**
              * Returns a {@code Calendar} built from the parameters set by the
              * setter methods. The calendar type given by the {@link #setCalendarType(String)
    @@ -1441,6 +1447,11 @@ public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek)
              *
              * 

    The default values are used for locale and time zone if these * parameters haven't been given explicitly. + *

    + * Since Android 13, if the locale contains the time zone with "tz" + * Unicode extension, + * and time zone hasn't been given explicitly, time zone in the locale + * is used. * *

    Any out of range field values are either normalized in lenient * mode or detected as an invalid value in non-lenient mode. @@ -1460,7 +1471,7 @@ public Calendar build() { locale = Locale.getDefault(); } if (zone == null) { - zone = TimeZone.getDefault(); + zone = defaultTimeZone(locale); } Calendar cal; if (type == null) { @@ -1597,7 +1608,7 @@ protected Calendar() */ protected Calendar(TimeZone zone, Locale aLocale) { - // BEGIN Android-added: Allow aLocale == null + // BEGIN Android-added: Allow aLocale == null. // http://b/16938922. // // TODO: This is for backwards compatibility only. Seems like a better idea to throw @@ -1605,7 +1616,7 @@ protected Calendar(TimeZone zone, Locale aLocale) if (aLocale == null) { aLocale = Locale.getDefault(); } - // END Android-added: Allow aLocale == null + // END Android-added: Allow aLocale == null. fields = new int[FIELD_COUNT]; isSet = new boolean[FIELD_COUNT]; stamp = new int[FIELD_COUNT]; @@ -1614,17 +1625,23 @@ protected Calendar(TimeZone zone, Locale aLocale) setWeekCountData(aLocale); } + // Android-changed: Support the "tz" extension since Android 13. /** * Gets a calendar using the default time zone and locale. The * Calendar returned is based on the current time * in the default time zone with the default * {@link Locale.Category#FORMAT FORMAT} locale. + *

    + * Since Android 13, if the locale contains the time zone with "tz" + * Unicode extension, + * that time zone is used instead. * * @return a Calendar. */ public static Calendar getInstance() { - return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); + Locale aLocale = Locale.getDefault(Locale.Category.FORMAT); + return createCalendar(defaultTimeZone(aLocale), aLocale); } /** @@ -1641,17 +1658,22 @@ public static Calendar getInstance(TimeZone zone) return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT)); } + // Android-changed: Support the "tz" extension since Android 13. /** * Gets a calendar using the default time zone and specified locale. * The Calendar returned is based on the current time * in the default time zone with the given locale. + *

    + * Since Android 13, if the locale contains the time zone with "tz" + * Unicode extension, + * that time zone is used instead. * * @param aLocale the locale for the week data * @return a Calendar. */ public static Calendar getInstance(Locale aLocale) { - return createCalendar(TimeZone.getDefault(), aLocale); + return createCalendar(defaultTimeZone(aLocale), aLocale); } /** @@ -1669,12 +1691,40 @@ public static Calendar getInstance(TimeZone zone, return createCalendar(zone, aLocale); } + // BEGIN Android-added: add getJapaneseImperialInstance(). + /** + * Create a Japanese Imperial Calendar. + * @hide + */ + /* J2ObjC removed + public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) { + return new JapaneseImperialCalendar(zone, aLocale); + } + */ + // END Android-added: add getJapaneseImperialInstance(). + + private static TimeZone defaultTimeZone(Locale l) { + TimeZone defaultTZ = TimeZone.getDefault(); + // Android-added: Accept null locale. http://b/16938922 + if (l == null) { + return defaultTZ; + } + String shortTZID = l.getUnicodeLocaleType("tz"); + return shortTZID != null ? + // Android-changed: Use ICU to convert LDML short ID + // TimeZoneNameUtility.convertLDMLShortID(shortTZID) + Optional.ofNullable(ICU.convertToTzId(shortTZID)) + .map(TimeZone::getTimeZone) + .orElse(defaultTZ) : + defaultTZ; + } + private static Calendar createCalendar(TimeZone zone, Locale aLocale) { - // BEGIN Android-changed: only support GregorianCalendar here + // BEGIN Android-changed: only support GregorianCalendar here. return new GregorianCalendar(zone, aLocale); - // END Android-changed: only support GregorianCalendar here + // END Android-changed: only support GregorianCalendar here. } /** @@ -1765,11 +1815,11 @@ public long getTimeInMillis() { public void setTimeInMillis(long millis) { // If we don't need to recalculate the calendar field values, // do nothing. -// BEGIN Android-changed: Removed ZoneInfo support +// BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo. // if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet // && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) { if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) { -// END Android-changed: Removed ZoneInfo support +// END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo. return; } @@ -2152,7 +2202,7 @@ private Map getDisplayNamesImpl(int field, int style, Locale loc if (strings != null) { Map names = new HashMap<>(); for (int i = 0; i < strings.length; i++) { - if (strings[i].length() == 0) { + if (strings[i].isEmpty()) { continue; } names.put(strings[i], i); @@ -2164,10 +2214,17 @@ private Map getDisplayNamesImpl(int field, int style, Locale loc boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle, Locale locale, int fieldMask) { + int baseStyle = getBaseStyle(style); // Ignore the standalone mask if (field < 0 || field >= fields.length || - style < minStyle || style > maxStyle) { + baseStyle < minStyle || baseStyle > maxStyle || baseStyle == 3) { + throw new IllegalArgumentException(); + } + // BEGIN Android-added: Check for invalid baseStyle == 3. + // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used. + if (baseStyle == 3) { throw new IllegalArgumentException(); } + // END Android-added: Check for invalid baseStyle == 3. if (locale == null) { throw new NullPointerException(); } @@ -2175,6 +2232,13 @@ boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle, } private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) { + int baseStyle = getBaseStyle(style); // ignore the standalone mask + + // DateFormatSymbols doesn't support any narrow names. + if (baseStyle == NARROW_FORMAT) { + return null; + } + String[] strings = null; switch (field) { case ERA: @@ -2182,11 +2246,11 @@ private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols break; case MONTH: - strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths(); + strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths(); break; case DAY_OF_WEEK: - strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays(); + strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays(); break; case AM_PM: @@ -2516,6 +2580,31 @@ final int selectFields() { return fieldMask; } + int getBaseStyle(int style) { + return style & ~STANDALONE_MASK; + } + + // BEGIN Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat. + /** + * @hide + */ + public static int toStandaloneStyle(int style) { + // END Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat. + return style | STANDALONE_MASK; + } + + private boolean isStandaloneStyle(int style) { + return (style & STANDALONE_MASK) != 0; + } + + private boolean isNarrowStyle(int style) { + return style == NARROW_FORMAT || style == NARROW_STANDALONE; + } + + private boolean isNarrowFormatStyle(int style) { + return style == NARROW_FORMAT; + } + /** * Returns the pseudo-time-stamp for two fields, given their * individual pseudo-time-stamps. If either of the fields @@ -2720,7 +2809,7 @@ public int compareTo(Calendar anotherCalendar) { * @see #roll(int,int) * @see #set(int,int) */ - abstract public void add(int field, int amount); + public abstract void add(int field, int amount); /** * Adds or subtracts (up/down) a single unit of time on the given time @@ -2742,7 +2831,7 @@ public int compareTo(Calendar anotherCalendar) { * @see Calendar#add(int,int) * @see Calendar#set(int,int) */ - abstract public void roll(int field, boolean up); + public abstract void roll(int field, boolean up); /** * Adds the specified (signed) amount to the specified calendar field @@ -2958,7 +3047,7 @@ public int getWeekYear() { } /** - * Sets the date of this {@code Calendar} with the the given date + * Sets the date of this {@code Calendar} with the given date * specifiers - week year, week of year, and day of week. * *

    Unlike the {@code set} method, all of the calendar fields @@ -3029,7 +3118,7 @@ public int getWeeksInWeekYear() { * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ - abstract public int getMinimum(int field); + public abstract int getMinimum(int field); /** * Returns the maximum value for the given calendar field of this @@ -3046,7 +3135,7 @@ public int getWeeksInWeekYear() { * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ - abstract public int getMaximum(int field); + public abstract int getMaximum(int field); /** * Returns the highest minimum value for the given calendar field @@ -3064,7 +3153,7 @@ public int getWeeksInWeekYear() { * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ - abstract public int getGreatestMinimum(int field); + public abstract int getGreatestMinimum(int field); /** * Returns the lowest maximum value for the given calendar field @@ -3086,7 +3175,7 @@ public int getWeeksInWeekYear() { * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ - abstract public int getLeastMaximum(int field); + public abstract int getLeastMaximum(int field); /** * Returns the minimum value that the specified calendar field @@ -3241,7 +3330,7 @@ public Object clone() * @param field the calendar field * @return the calendar field name * @exception IndexOutOfBoundsException if field is negative, - * equal to or greater then FIELD_COUNT. + * equal to or greater than {@code FIELD_COUNT}. */ static String getFieldName(int field) { return FIELD_NAME[field]; @@ -3350,8 +3439,7 @@ private void adjustStamp() { for (;;) { int min = Integer.MAX_VALUE; - for (int i = 0; i < stamp.length; i++) { - int v = stamp[i]; + for (int v : stamp) { if (v >= newStamp && min > v) { min = v; } @@ -3434,7 +3522,7 @@ private synchronized void writeObject(ObjectOutputStream stream) catch (IllegalArgumentException e) {} } - // Android-changed: Removed ZoneInfo support/workaround. + // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo. // Write out the 1.1 FCS object. stream.defaultWriteObject(); } @@ -3450,7 +3538,10 @@ private static class CalendarAccessControlContext { new ProtectionDomain(null, perms) }); } - }*/ + private CalendarAccessControlContext() { + } + } + */ /** * Reconstitutes this object from a stream (i.e., deserialize it). @@ -3485,7 +3576,36 @@ else if (serialVersionOnStream >= 0) serialVersionOnStream = currentSerialVersion; - // Android-changed: removed ZoneInfo support. + // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo. + /* + // If there's a ZoneInfo object, use it for zone. + ZoneInfo zi = null; + try { + zi = AccessController.doPrivileged( + new PrivilegedExceptionAction<>() { + @Override + public ZoneInfo run() throws Exception { + return (ZoneInfo) input.readObject(); + } + }, + CalendarAccessControlContext.INSTANCE); + } catch (PrivilegedActionException pae) { + Exception e = pae.getException(); + if (!(e instanceof OptionalDataException)) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else if (e instanceof IOException) { + throw (IOException) e; + } else if (e instanceof ClassNotFoundException) { + throw (ClassNotFoundException) e; + } + throw new RuntimeException(e); + } + } + if (zi != null) { + zone = zi; + } + */ // If the deserialized object has a SimpleTimeZone, try to // replace it with a ZoneInfo equivalent (as of 1.4) in order @@ -3499,4 +3619,18 @@ else if (serialVersionOnStream >= 0) } } } + + /** + * Converts this object to an {@link Instant}. + *

    + * The conversion creates an {@code Instant} that represents the + * same point on the time-line as this {@code Calendar}. + * + * @return the instant representing the same point on the time-line + * @since 1.8 + */ + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // public final Instant toInstant() { + // return Instant.ofEpochMilli(getTimeInMillis()); + // } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collection.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collection.java index 2ae88727a0..0ded04ba29 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collection.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -25,6 +25,7 @@ package java.util; +import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -35,41 +36,37 @@ * collections allow duplicate elements and others do not. Some are ordered * and others unordered. The JDK does not provide any direct * implementations of this interface: it provides implementations of more - * specific subinterfaces like Set and List. This interface + * specific subinterfaces like {@code Set} and {@code List}. This interface * is typically used to pass collections around and manipulate them where * maximum generality is desired. * *

    Bags or multisets (unordered collections that may contain * duplicate elements) should implement this interface directly. * - *

    All general-purpose Collection implementation classes (which - * typically implement Collection indirectly through one of its + *

    All general-purpose {@code Collection} implementation classes (which + * typically implement {@code Collection} indirectly through one of its * subinterfaces) should provide two "standard" constructors: a void (no * arguments) constructor, which creates an empty collection, and a - * constructor with a single argument of type Collection, which + * constructor with a single argument of type {@code Collection}, which * creates a new collection with the same elements as its argument. In * effect, the latter constructor allows the user to copy any collection, * producing an equivalent collection of the desired implementation type. * There is no way to enforce this convention (as interfaces cannot contain - * constructors) but all of the general-purpose Collection + * constructors) but all of the general-purpose {@code Collection} * implementations in the Java platform libraries comply. * - *

    The "destructive" methods contained in this interface, that is, the - * methods that modify the collection on which they operate, are specified to - * throw UnsupportedOperationException if this collection does not - * support the operation. If this is the case, these methods may, but are not - * required to, throw an UnsupportedOperationException if the - * invocation would have no effect on the collection. For example, invoking - * the {@link #addAll(Collection)} method on an unmodifiable collection may, - * but is not required to, throw the exception if the collection to be added - * is empty. + *

    Certain methods are specified to be + * optional. If a collection implementation doesn't implement a + * particular operation, it should define the corresponding method to throw + * {@code UnsupportedOperationException}. Such methods are marked "optional + * operation" in method specifications of the collections interfaces. * - *

    - * Some collection implementations have restrictions on the elements that - * they may contain. For example, some implementations prohibit null elements, + *

    Some collection implementations + * have restrictions on the elements that they may contain. + * For example, some implementations prohibit null elements, * and some have restrictions on the types of their elements. Attempting to * add an ineligible element throws an unchecked exception, typically - * NullPointerException or ClassCastException. Attempting + * {@code NullPointerException} or {@code ClassCastException}. Attempting * to query the presence of an ineligible element may throw an exception, * or it may simply return false; some implementations will exhibit the former * behavior and some will exhibit the latter. More generally, attempting an @@ -90,13 +87,13 @@ *

    Many methods in Collections Framework interfaces are defined in * terms of the {@link Object#equals(Object) equals} method. For example, * the specification for the {@link #contains(Object) contains(Object o)} - * method says: "returns true if and only if this collection - * contains at least one element e such that - * (o==null ? e==null : o.equals(e))." This specification should - * not be construed to imply that invoking Collection.contains - * with a non-null argument o will cause o.equals(e) to be - * invoked for any element e. Implementations are free to implement - * optimizations whereby the equals invocation is avoided, for + * method says: "returns {@code true} if and only if this collection + * contains at least one element {@code e} such that + * {@code (o==null ? e==null : o.equals(e))}." This specification should + * not be construed to imply that invoking {@code Collection.contains} + * with a non-null argument {@code o} will cause {@code o.equals(e)} to be + * invoked for any element {@code e}. Implementations are free to implement + * optimizations whereby the {@code equals} invocation is avoided, for * example, by first comparing the hash codes of the two elements. (The * {@link Object#hashCode()} specification guarantees that two objects with * unequal hash codes cannot be equal.) More generally, implementations of @@ -111,6 +108,86 @@ * methods. Implementations may optionally handle the self-referential scenario, * however most current implementations do not do so. * + *

    View Collections

    + * + *

    Most collections manage storage for elements they contain. By contrast, view + * collections themselves do not store elements, but instead they rely on a + * backing collection to store the actual elements. Operations that are not handled + * by the view collection itself are delegated to the backing collection. Examples of + * view collections include the wrapper collections returned by methods such as + * {@link Collections#checkedCollection Collections.checkedCollection}, + * {@link Collections#synchronizedCollection Collections.synchronizedCollection}, and + * {@link Collections#unmodifiableCollection Collections.unmodifiableCollection}. + * Other examples of view collections include collections that provide a + * different representation of the same elements, for example, as + * provided by {@link List#subList List.subList}, + * {@link NavigableSet#subSet NavigableSet.subSet}, or + * {@link Map#entrySet Map.entrySet}. + * Any changes made to the backing collection are visible in the view collection. + * Correspondingly, any changes made to the view collection — if changes + * are permitted — are written through to the backing collection. + * Although they technically aren't collections, instances of + * {@link Iterator} and {@link ListIterator} can also allow modifications + * to be written through to the backing collection, and in some cases, + * modifications to the backing collection will be visible to the Iterator + * during iteration. + * + *

    Unmodifiable Collections

    + * + *

    Certain methods of this interface are considered "destructive" and are called + * "mutator" methods in that they modify the group of objects contained within + * the collection on which they operate. They can be specified to throw + * {@code UnsupportedOperationException} if this collection implementation + * does not support the operation. Such methods should (but are not required + * to) throw an {@code UnsupportedOperationException} if the invocation would + * have no effect on the collection. For example, consider a collection that + * does not support the {@link #add add} operation. What will happen if the + * {@link #addAll addAll} method is invoked on this collection, with an empty + * collection as the argument? The addition of zero elements has no effect, + * so it is permissible for this collection simply to do nothing and not to throw + * an exception. However, it is recommended that such cases throw an exception + * unconditionally, as throwing only in certain cases can lead to + * programming errors. + * + *

    An unmodifiable collection is a collection, all of whose + * mutator methods (as defined above) are specified to throw + * {@code UnsupportedOperationException}. Such a collection thus cannot be + * modified by calling any methods on it. For a collection to be properly + * unmodifiable, any view collections derived from it must also be unmodifiable. + * For example, if a List is unmodifiable, the List returned by + * {@link List#subList List.subList} is also unmodifiable. + * + *

    An unmodifiable collection is not necessarily immutable. If the + * contained elements are mutable, the entire collection is clearly + * mutable, even though it might be unmodifiable. For example, consider + * two unmodifiable lists containing mutable elements. The result of calling + * {@code list1.equals(list2)} might differ from one call to the next if + * the elements had been mutated, even though both lists are unmodifiable. + * However, if an unmodifiable collection contains all immutable elements, + * it can be considered effectively immutable. + * + *

    Unmodifiable View Collections

    + * + *

    An unmodifiable view collection is a collection that is unmodifiable + * and that is also a view onto a backing collection. Its mutator methods throw + * {@code UnsupportedOperationException}, as described above, while + * reading and querying methods are delegated to the backing collection. + * The effect is to provide read-only access to the backing collection. + * This is useful for a component to provide users with read access to + * an internal collection, while preventing them from modifying such + * collections unexpectedly. Examples of unmodifiable view collections + * are those returned by the + * {@link Collections#unmodifiableCollection Collections.unmodifiableCollection}, + * {@link Collections#unmodifiableList Collections.unmodifiableList}, and + * related methods. + * + *

    Note that changes to the backing collection might still be possible, + * and if they occur, they are visible through the unmodifiable view. Thus, + * an unmodifiable view collection is not necessarily immutable. However, + * if the backing collection of an unmodifiable view is effectively immutable, + * or if the only reference to the backing collection is through an + * unmodifiable view, the view can be considered effectively immutable. + * *

    This interface is a member of the * * Java Collections Framework. @@ -146,35 +223,35 @@ public interface Collection extends Iterable { /** * Returns the number of elements in this collection. If this collection - * contains more than Integer.MAX_VALUE elements, returns - * Integer.MAX_VALUE. + * contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. * * @return the number of elements in this collection */ int size(); /** - * Returns true if this collection contains no elements. + * Returns {@code true} if this collection contains no elements. * - * @return true if this collection contains no elements + * @return {@code true} if this collection contains no elements */ boolean isEmpty(); /** - * Returns true if this collection contains the specified element. - * More formally, returns true if and only if this collection - * contains at least one element e such that - * (o==null ? e==null : o.equals(e)). + * Returns {@code true} if this collection contains the specified element. + * More formally, returns {@code true} if and only if this collection + * contains at least one element {@code e} such that + * {@code Objects.equals(o, e)}. * * @param o element whose presence in this collection is to be tested - * @return true if this collection contains the specified + * @return {@code true} if this collection contains the specified * element * @throws ClassCastException if the type of the specified element * is incompatible with this collection - * (optional) + * (optional) * @throws NullPointerException if the specified element is null and this * collection does not permit null elements - * (optional) + * (optional) */ boolean contains(Object o); @@ -184,7 +261,7 @@ public interface Collection extends Iterable { * (unless this collection is an instance of some class that provides a * guarantee). * - * @return an Iterator over the elements in this collection + * @return an {@code Iterator} over the elements in this collection */ Iterator iterator(); @@ -192,17 +269,23 @@ public interface Collection extends Iterable { * Returns an array containing all of the elements in this collection. * If this collection makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements in - * the same order. + * the same order. The returned array's {@linkplain Class#getComponentType + * runtime component type} is {@code Object}. * *

    The returned array will be "safe" in that no references to it are * maintained by this collection. (In other words, this method must * allocate a new array even if this collection is backed by an array). * The caller is thus free to modify the returned array. * - *

    This method acts as bridge between array-based and collection-based - * APIs. + * @apiNote + * This method acts as a bridge between array-based and collection-based APIs. + * It returns an array whose runtime type is {@code Object[]}. + * Use {@link #toArray(Object[]) toArray(T[])} to reuse an existing + * array, or use {@link #toArray(IntFunction)} to control the runtime type + * of the array. * - * @return an array containing all of the elements in this collection + * @return an array, whose {@linkplain Class#getComponentType runtime component + * type} is {@code Object}, containing all of the elements in this collection */ Object[] toArray(); @@ -216,66 +299,115 @@ public interface Collection extends Iterable { *

    If this collection fits in the specified array with room to spare * (i.e., the array has more elements than this collection), the element * in the array immediately following the end of the collection is set to - * null. (This is useful in determining the length of this + * {@code null}. (This is useful in determining the length of this * collection only if the caller knows that this collection does - * not contain any null elements.) + * not contain any {@code null} elements.) * *

    If this collection makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements in * the same order. * - *

    Like the {@link #toArray()} method, this method acts as bridge between - * array-based and collection-based APIs. Further, this method allows - * precise control over the runtime type of the output array, and may, - * under certain circumstances, be used to save allocation costs. + * @apiNote + * This method acts as a bridge between array-based and collection-based APIs. + * It allows an existing array to be reused under certain circumstances. + * Use {@link #toArray()} to create an array whose runtime type is {@code Object[]}, + * or use {@link #toArray(IntFunction)} to control the runtime type of + * the array. * - *

    Suppose x is a collection known to contain only strings. - * The following code can be used to dump the collection into a newly - * allocated array of String: + *

    Suppose {@code x} is a collection known to contain only strings. + * The following code can be used to dump the collection into a previously + * allocated {@code String} array: * *

    -     *     String[] y = x.toArray(new String[0]);
    + * String[] y = new String[SIZE]; + * ... + * y = x.toArray(y);
    * - * Note that toArray(new Object[0]) is identical in function to - * toArray(). + *

    The return value is reassigned to the variable {@code y}, because a + * new array will be allocated and returned if the collection {@code x} has + * too many elements to fit into the existing array {@code y}. * - * @param the runtime type of the array to contain the collection + *

    Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param the component type of the array to contain the collection * @param a the array into which the elements of this collection are to be * stored, if it is big enough; otherwise, a new array of the same * runtime type is allocated for this purpose. * @return an array containing all of the elements in this collection - * @throws ArrayStoreException if the runtime type of the specified array - * is not a supertype of the runtime type of every element in - * this collection + * @throws ArrayStoreException if the runtime type of any element in this + * collection is not assignable to the {@linkplain Class#getComponentType + * runtime component type} of the specified array * @throws NullPointerException if the specified array is null */ T[] toArray(T[] a); + /** + * Returns an array containing all of the elements in this collection, + * using the provided {@code generator} function to allocate the returned array. + * + *

    If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements in + * the same order. + * + * @apiNote + * This method acts as a bridge between array-based and collection-based APIs. + * It allows creation of an array of a particular runtime type. Use + * {@link #toArray()} to create an array whose runtime type is {@code Object[]}, + * or use {@link #toArray(Object[]) toArray(T[])} to reuse an existing array. + * + *

    Suppose {@code x} is a collection known to contain only strings. + * The following code can be used to dump the collection into a newly + * allocated array of {@code String}: + * + *

    +     *     String[] y = x.toArray(String[]::new);
    + * + * @implSpec + * The default implementation calls the generator function with zero + * and then passes the resulting array to {@link #toArray(Object[]) toArray(T[])}. + * + * @param the component type of the array to contain the collection + * @param generator a function which produces a new array of the desired + * type and the provided length + * @return an array containing all of the elements in this collection + * @throws ArrayStoreException if the runtime type of any element in this + * collection is not assignable to the {@linkplain Class#getComponentType + * runtime component type} of the generated array + * @throws NullPointerException if the generator function is null + * @since 11 + */ + /* J2ObjC removed + default T[] toArray(IntFunction generator) { + return toArray(generator.apply(0)); + } + */ + // Modification Operations /** * Ensures that this collection contains the specified element (optional - * operation). Returns true if this collection changed as a - * result of the call. (Returns false if this collection does + * operation). Returns {@code true} if this collection changed as a + * result of the call. (Returns {@code false} if this collection does * not permit duplicates and already contains the specified element.)

    * * Collections that support this operation may place limitations on what * elements may be added to this collection. In particular, some - * collections will refuse to add null elements, and others will + * collections will refuse to add {@code null} elements, and others will * impose restrictions on the type of elements that may be added. * Collection classes should clearly specify in their documentation any * restrictions on what elements may be added.

    * * If a collection refuses to add a particular element for any reason * other than that it already contains the element, it must throw - * an exception (rather than returning false). This preserves + * an exception (rather than returning {@code false}). This preserves * the invariant that a collection always contains the specified element * after this call returns. * * @param e element whose presence in this collection is to be ensured - * @return true if this collection changed as a result of the + * @return {@code true} if this collection changed as a result of the * call - * @throws UnsupportedOperationException if the add operation + * @throws UnsupportedOperationException if the {@code add} operation * is not supported by this collection * @throws ClassCastException if the class of the specified element * prevents it from being added to this collection @@ -291,14 +423,14 @@ public interface Collection extends Iterable { /** * Removes a single instance of the specified element from this * collection, if it is present (optional operation). More formally, - * removes an element e such that - * (o==null ? e==null : o.equals(e)), if + * removes an element {@code e} such that + * {@code Objects.equals(o, e)}, if * this collection contains one or more such elements. Returns - * true if this collection contained the specified element (or + * {@code true} if this collection contained the specified element (or * equivalently, if this collection changed as a result of the call). * * @param o element to be removed from this collection, if present - * @return true if an element was removed as a result of this call + * @return {@code true} if an element was removed as a result of this call * @throws ClassCastException if the type of the specified element * is incompatible with this collection * (optional) @@ -314,11 +446,11 @@ public interface Collection extends Iterable { // Bulk Operations /** - * Returns true if this collection contains all of the elements + * Returns {@code true} if this collection contains all of the elements * in the specified collection. * * @param c collection to be checked for containment in this collection - * @return true if this collection contains all of the elements + * @return {@code true} if this collection contains all of the elements * in the specified collection * @throws ClassCastException if the types of one or more elements * in the specified collection are incompatible with this @@ -342,8 +474,8 @@ public interface Collection extends Iterable { * nonempty.) * * @param c collection containing elements to be added to this collection - * @return true if this collection changed as a result of the call - * @throws UnsupportedOperationException if the addAll operation + * @return {@code true} if this collection changed as a result of the call + * @throws UnsupportedOperationException if the {@code addAll} operation * is not supported by this collection * @throws ClassCastException if the class of an element of the specified * collection prevents it from being added to this collection @@ -366,9 +498,9 @@ public interface Collection extends Iterable { * collection. * * @param c collection containing elements to be removed from this collection - * @return true if this collection changed as a result of the + * @return {@code true} if this collection changed as a result of the * call - * @throws UnsupportedOperationException if the removeAll method + * @throws UnsupportedOperationException if the {@code removeAll} method * is not supported by this collection * @throws ClassCastException if the types of one or more elements * in this collection are incompatible with the specified @@ -426,8 +558,8 @@ default boolean removeIf(Predicate filter) { * specified collection. * * @param c collection containing elements to be retained in this collection - * @return true if this collection changed as a result of the call - * @throws UnsupportedOperationException if the retainAll operation + * @return {@code true} if this collection changed as a result of the call + * @throws UnsupportedOperationException if the {@code retainAll} operation * is not supported by this collection * @throws ClassCastException if the types of one or more elements * in this collection are incompatible with the specified @@ -447,7 +579,7 @@ default boolean removeIf(Predicate filter) { * Removes all of the elements from this collection (optional operation). * The collection will be empty after this method returns. * - * @throws UnsupportedOperationException if the clear operation + * @throws UnsupportedOperationException if the {@code clear} operation * is not supported by this collection */ void clear(); @@ -458,30 +590,30 @@ default boolean removeIf(Predicate filter) { /** * Compares the specified object with this collection for equality.

    * - * While the Collection interface adds no stipulations to the - * general contract for the Object.equals, programmers who - * implement the Collection interface "directly" (in other words, - * create a class that is a Collection but is not a Set - * or a List) must exercise care if they choose to override the - * Object.equals. It is not necessary to do so, and the simplest - * course of action is to rely on Object's implementation, but + * While the {@code Collection} interface adds no stipulations to the + * general contract for the {@code Object.equals}, programmers who + * implement the {@code Collection} interface "directly" (in other words, + * create a class that is a {@code Collection} but is not a {@code Set} + * or a {@code List}) must exercise care if they choose to override the + * {@code Object.equals}. It is not necessary to do so, and the simplest + * course of action is to rely on {@code Object}'s implementation, but * the implementor may wish to implement a "value comparison" in place of - * the default "reference comparison." (The List and - * Set interfaces mandate such value comparisons.)

    - * - * The general contract for the Object.equals method states that - * equals must be symmetric (in other words, a.equals(b) if and - * only if b.equals(a)). The contracts for List.equals - * and Set.equals state that lists are only equal to other lists, - * and sets to other sets. Thus, a custom equals method for a - * collection class that implements neither the List nor - * Set interface must return false when this collection + * the default "reference comparison." (The {@code List} and + * {@code Set} interfaces mandate such value comparisons.)

    + * + * The general contract for the {@code Object.equals} method states that + * equals must be symmetric (in other words, {@code a.equals(b)} if and + * only if {@code b.equals(a)}). The contracts for {@code List.equals} + * and {@code Set.equals} state that lists are only equal to other lists, + * and sets to other sets. Thus, a custom {@code equals} method for a + * collection class that implements neither the {@code List} nor + * {@code Set} interface must return {@code false} when this collection * is compared to any list or set. (By the same logic, it is not possible - * to write a class that correctly implements both the Set and - * List interfaces.) + * to write a class that correctly implements both the {@code Set} and + * {@code List} interfaces.) * * @param o object to be compared for equality with this collection - * @return true if the specified object is equal to this + * @return {@code true} if the specified object is equal to this * collection * * @see Object#equals(Object) @@ -492,13 +624,13 @@ default boolean removeIf(Predicate filter) { /** * Returns the hash code value for this collection. While the - * Collection interface adds no stipulations to the general - * contract for the Object.hashCode method, programmers should - * take note that any class that overrides the Object.equals - * method must also override the Object.hashCode method in order - * to satisfy the general contract for the Object.hashCode method. - * In particular, c1.equals(c2) implies that - * c1.hashCode()==c2.hashCode(). + * {@code Collection} interface adds no stipulations to the general + * contract for the {@code Object.hashCode} method, programmers should + * take note that any class that overrides the {@code Object.equals} + * method must also override the {@code Object.hashCode} method in order + * to satisfy the general contract for the {@code Object.hashCode} method. + * In particular, {@code c1.equals(c2)} implies that + * {@code c1.hashCode()==c2.hashCode()}. * * @return the hash code value for this collection * @@ -518,7 +650,7 @@ default boolean removeIf(Predicate filter) { *

    The default implementation should be overridden by subclasses that * can return a more efficient spliterator. In order to * preserve expected laziness behavior for the {@link #stream()} and - * {@link #parallelStream()}} methods, spliterators should either have the + * {@link #parallelStream()} methods, spliterators should either have the * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be * late-binding. * If none of these is practical, the overriding class should describe the @@ -537,7 +669,7 @@ default boolean removeIf(Predicate filter) { * @implSpec * The default implementation creates a * late-binding spliterator - * from the collections's {@code Iterator}. The spliterator inherits the + * from the collection's {@code Iterator}. The spliterator inherits the * fail-fast properties of the collection's iterator. *

    * The created {@code Spliterator} reports {@link Spliterator#SIZED}. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collections.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collections.java index 8252d04ea1..59cd1ebf82 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collections.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Collections.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, 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 @@ -25,9 +25,13 @@ */ package java.util; -import java.io.Serializable; -import java.io.ObjectOutputStream; + +/* J2ObjC removed. +import dalvik.system.VMRuntime; +*/ + import java.io.IOException; +import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Array; @@ -35,14 +39,14 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; -/* J2ObjC removed. -import dalvik.system.VMRuntime; - */ +// Android-changed: SharedSecrets are not moved yet. +// import jdk.internal.access.SharedSecrets; /** * This class consists exclusively of static methods that operate on or return @@ -50,7 +54,7 @@ * collections, "wrappers", which return a new collection backed by a * specified collection, and a few other odds and ends. * - *

    The methods of this class all throw a NullPointerException + *

    The methods of this class all throw a {@code NullPointerException} * if the collections or class objects provided to them are null. * *

    The documentation for the polymorphic algorithms contained in this class @@ -58,20 +62,20 @@ * descriptions should be regarded as implementation notes, rather than * parts of the specification. Implementors should feel free to * substitute other algorithms, so long as the specification itself is adhered - * to. (For example, the algorithm used by sort does not have to be + * to. (For example, the algorithm used by {@code sort} does not have to be * a mergesort, but it does have to be stable.) * *

    The "destructive" algorithms contained in this class, that is, the * algorithms that modify the collection on which they operate, are specified - * to throw UnsupportedOperationException if the collection does not - * support the appropriate mutation primitive(s), such as the set + * to throw {@code UnsupportedOperationException} if the collection does not + * support the appropriate mutation primitive(s), such as the {@code set} * method. These algorithms may, but are not required to, throw this * exception if an invocation would have no effect on the collection. For - * example, invoking the sort method on an unmodifiable list that is - * already sorted may or may not throw UnsupportedOperationException. + * example, invoking the {@code sort} method on an unmodifiable list that is + * already sorted may or may not throw {@code UnsupportedOperationException}. * *

    This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -245,10 +249,10 @@ public static void sort(List list, Comparator c) { * @param list the list to be searched. * @param key the key to be searched for. * @return the index of the search key, if it is contained in the list; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the list: the index of the first - * element greater than the key, or list.size() if all + * element greater than the key, or {@code list.size()} if all * elements in the list are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -346,13 +350,13 @@ private static T get(ListIterator i, int index) { * @param list the list to be searched. * @param key the key to be searched for. * @param c the comparator by which the list is ordered. - * A null value indicates that the elements' + * A {@code null} value indicates that the elements' * {@linkplain Comparable natural ordering} should be used. * @return the index of the search key, if it is contained in the list; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the list: the index of the first - * element greater than the key, or list.size() if all + * element greater than the key, or {@code list.size()} if all * elements in the list are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. @@ -418,7 +422,7 @@ else if (cmp > 0) * * @param list the list whose elements are to be reversed. * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set operation. + * its list-iterator does not support the {@code set} operation. */ @SuppressWarnings({"rawtypes", "unchecked"}) public static void reverse(List list) { @@ -466,7 +470,7 @@ public static void reverse(List list) { * * @param list the list to be shuffled. * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set operation. + * its list-iterator does not support the {@code set} operation. */ public static void shuffle(List list) { Random rnd = r; @@ -498,7 +502,7 @@ public static void shuffle(List list) { * @param list the list to be shuffled. * @param rnd the source of randomness to use to shuffle the list. * @throws UnsupportedOperationException if the specified list or its - * list-iterator does not support the set operation. + * list-iterator does not support the {@code set} operation. */ @SuppressWarnings({"rawtypes", "unchecked"}) public static void shuffle(List list, Random rnd) { @@ -507,7 +511,7 @@ public static void shuffle(List list, Random rnd) { for (int i=size; i>1; i--) swap(list, i-1, rnd.nextInt(i)); } else { - Object arr[] = list.toArray(); + Object[] arr = list.toArray(); // Shuffle array for (int i=size; i>1; i--) @@ -518,9 +522,9 @@ public static void shuffle(List list, Random rnd) { // the wildcard but it will require a call to a supplementary // private method ListIterator it = list.listIterator(); - for (int i=0; i list, Random rnd) { * @param list The list in which to swap elements. * @param i the index of one element to be swapped. * @param j the index of the other element to be swapped. - * @throws IndexOutOfBoundsException if either i or j + * @throws IndexOutOfBoundsException if either {@code i} or {@code j} * is out of range (i < 0 || i >= list.size() * || j < 0 || j >= list.size()). * @since 1.4 @@ -566,7 +570,7 @@ private static void swap(Object[] arr, int i, int j) { * @param list the list to be filled with the specified element. * @param obj The element with which to fill the specified list. * @throws UnsupportedOperationException if the specified list or its - * list-iterator does not support the set operation. + * list-iterator does not support the {@code set} operation. */ public static void fill(List list, T obj) { int size = list.size(); @@ -587,8 +591,9 @@ public static void fill(List list, T obj) { * Copies all of the elements from one list into another. After the * operation, the index of each copied element in the destination list * will be identical to its index in the source list. The destination - * list must be at least as long as the source list. If it is longer, the - * remaining elements in the destination list are unaffected.

    + * list's size must be greater than or equal to the source list's size. + * If it is greater, the remaining elements in the destination list are + * unaffected.

    * * This method runs in linear time. * @@ -598,7 +603,7 @@ public static void fill(List list, T obj) { * @throws IndexOutOfBoundsException if the destination list is too small * to contain the entire source List. * @throws UnsupportedOperationException if the destination list's - * list-iterator does not support the set operation. + * list-iterator does not support the {@code set} operation. */ public static void copy(List dest, List src) { int srcSize = src.size(); @@ -622,11 +627,11 @@ public static void copy(List dest, List src) { /** * Returns the minimum element of the given collection, according to the * natural ordering of its elements. All elements in the - * collection must implement the Comparable interface. + * collection must implement the {@code Comparable} interface. * Furthermore, all elements in the collection must be mutually - * comparable (that is, e1.compareTo(e2) must not throw a - * ClassCastException for any elements e1 and - * e2 in the collection).

    + * comparable (that is, {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the collection).

    * * This method iterates over the entire collection, hence it requires * time proportional to the size of the collection. @@ -657,9 +662,9 @@ public static > T min(Collectionmutually comparable by the specified - * comparator (that is, comp.compare(e1, e2) must not throw a - * ClassCastException for any elements e1 and - * e2 in the collection).

    + * comparator (that is, {@code comp.compare(e1, e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the collection).

    * * This method iterates over the entire collection, hence it requires * time proportional to the size of the collection. @@ -667,7 +672,7 @@ public static > T min(Collection the class of the objects in the collection * @param coll the collection whose minimum element is to be determined. * @param comp the comparator with which to determine the minimum element. - * A null value indicates that the elements' natural + * A {@code null} value indicates that the elements' natural * ordering should be used. * @return the minimum element of the given collection, according * to the specified comparator. @@ -695,11 +700,11 @@ public static T min(Collection coll, Comparator comp /** * Returns the maximum element of the given collection, according to the * natural ordering of its elements. All elements in the - * collection must implement the Comparable interface. + * collection must implement the {@code Comparable} interface. * Furthermore, all elements in the collection must be mutually - * comparable (that is, e1.compareTo(e2) must not throw a - * ClassCastException for any elements e1 and - * e2 in the collection).

    + * comparable (that is, {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the collection).

    * * This method iterates over the entire collection, hence it requires * time proportional to the size of the collection. @@ -730,9 +735,9 @@ public static > T max(Collectionmutually comparable by the specified - * comparator (that is, comp.compare(e1, e2) must not throw a - * ClassCastException for any elements e1 and - * e2 in the collection).

    + * comparator (that is, {@code comp.compare(e1, e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the collection).

    * * This method iterates over the entire collection, hence it requires * time proportional to the size of the collection. @@ -740,7 +745,7 @@ public static > T max(Collection the class of the objects in the collection * @param coll the collection whose maximum element is to be determined. * @param comp the comparator with which to determine the maximum element. - * A null value indicates that the elements' natural + * A {@code null} value indicates that the elements' natural * ordering should be used. * @return the maximum element of the given collection, according * to the specified comparator. @@ -767,32 +772,32 @@ public static T max(Collection coll, Comparator comp /** * Rotates the elements in the specified list by the specified distance. - * After calling this method, the element at index i will be - * the element previously at index (i - distance) mod - * list.size(), for all values of i between 0 - * and list.size()-1, inclusive. (This method has no effect on + * After calling this method, the element at index {@code i} will be + * the element previously at index {@code (i - distance)} mod + * {@code list.size()}, for all values of {@code i} between {@code 0} + * and {@code list.size()-1}, inclusive. (This method has no effect on * the size of the list.) * - *

    For example, suppose list comprises [t, a, n, k, s]. - * After invoking Collections.rotate(list, 1) (or - * Collections.rotate(list, -4)), list will comprise - * [s, t, a, n, k]. + *

    For example, suppose {@code list} comprises{@code [t, a, n, k, s]}. + * After invoking {@code Collections.rotate(list, 1)} (or + * {@code Collections.rotate(list, -4)}), {@code list} will comprise + * {@code [s, t, a, n, k]}. * *

    Note that this method can usefully be applied to sublists to * move one or more elements within a list while preserving the * order of the remaining elements. For example, the following idiom - * moves the element at index j forward to position - * k (which must be greater than or equal to j): + * moves the element at index {@code j} forward to position + * {@code k} (which must be greater than or equal to {@code j}): *

          *     Collections.rotate(list.subList(j, k+1), -1);
          * 
    - * To make this concrete, suppose list comprises - * [a, b, c, d, e]. To move the element at index 1 - * (b) forward two positions, perform the following invocation: + * To make this concrete, suppose {@code list} comprises + * {@code [a, b, c, d, e]}. To move the element at index {@code 1} + * ({@code b}) forward two positions, perform the following invocation: *
          *     Collections.rotate(l.subList(1, 4), -1);
          * 
    - * The resulting list is [a, c, d, b, e]. + * The resulting list is {@code [a, c, d, b, e]}. * *

    To move more than one element forward, increase the absolute value * of the rotation distance. To move elements backward, use a positive @@ -805,8 +810,8 @@ public static T max(Collection coll, Comparator comp * element is swapped into the first element. If necessary, the process * is repeated on the second and successive elements, until the rotation * is complete. If the specified list is large and doesn't implement the - * RandomAccess interface, this implementation breaks the - * list into two sublist views around index -distance mod size. + * {@code RandomAccess} interface, this implementation breaks the + * list into two sublist views around index {@code -distance mod size}. * Then the {@link #reverse(List)} method is invoked on each sublist view, * and finally it is invoked on the entire list. For a more complete * description of both algorithms, see Section 2.3 of Jon Bentley's @@ -815,9 +820,9 @@ public static T max(Collection coll, Comparator comp * @param list the list to be rotated. * @param distance the distance to rotate the list. There are no * constraints on this value; it may be zero, negative, or - * greater than list.size(). + * greater than {@code list.size()}. * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set operation. + * its list-iterator does not support the {@code set} operation. * @since 1.4 */ public static void rotate(List list, int distance) { @@ -867,21 +872,21 @@ private static void rotate2(List list, int distance) { /** * Replaces all occurrences of one specified value in a list with another. - * More formally, replaces with newVal each element e - * in list such that - * (oldVal==null ? e==null : oldVal.equals(e)). + * More formally, replaces with {@code newVal} each element {@code e} + * in {@code list} such that + * {@code (oldVal==null ? e==null : oldVal.equals(e))}. * (This method has no effect on the size of the list.) * * @param the class of the objects in the list * @param list the list in which replacement is to occur. * @param oldVal the old value to be replaced. - * @param newVal the new value with which oldVal is to be + * @param newVal the new value with which {@code oldVal} is to be * replaced. - * @return true if list contained one or more elements - * e such that - * (oldVal==null ? e==null : oldVal.equals(e)). + * @return {@code true} if {@code list} contained one or more elements + * {@code e} such that + * {@code (oldVal==null ? e==null : oldVal.equals(e))}. * @throws UnsupportedOperationException if the specified list or - * its list-iterator does not support the set operation. + * its list-iterator does not support the {@code set} operation. * @since 1.4 */ public static boolean replaceAll(List list, T oldVal, T newVal) { @@ -927,7 +932,7 @@ public static boolean replaceAll(List list, T oldVal, T newVal) { /** * Returns the starting position of the first occurrence of the specified * target list within the specified source list, or -1 if there is no - * such occurrence. More formally, returns the lowest index i + * such occurrence. More formally, returns the lowest index {@code i} * such that {@code source.subList(i, i+target.size()).equals(target)}, * or -1 if there is no such index. (Returns -1 if * {@code target.size() > source.size()}) @@ -937,8 +942,8 @@ public static boolean replaceAll(List list, T oldVal, T newVal) { * location in turn. * * @param source the list in which to search for the first occurrence - * of target. - * @param target the list to search for as a subList of source. + * of {@code target}. + * @param target the list to search for as a subList of {@code source}. * @return the starting position of the first occurrence of the specified * target list within the specified source list, or -1 if there * is no such occurrence. @@ -980,7 +985,7 @@ public static int indexOfSubList(List source, List target) { /** * Returns the starting position of the last occurrence of the specified * target list within the specified source list, or -1 if there is no such - * occurrence. More formally, returns the highest index i + * occurrence. More formally, returns the highest index {@code i} * such that {@code source.subList(i, i+target.size()).equals(target)}, * or -1 if there is no such index. (Returns -1 if * {@code target.size() > source.size()}) @@ -990,8 +995,8 @@ public static int indexOfSubList(List source, List target) { * location in turn. * * @param source the list in which to search for the last occurrence - * of target. - * @param target the list to search for as a subList of source. + * of {@code target}. + * @param target the list to search for as a subList of {@code source}. * @return the starting position of the last occurrence of the specified * target list within the specified source list, or -1 if there * is no such occurrence. @@ -1038,28 +1043,32 @@ public static int lastIndexOfSubList(List source, List target) { // Unmodifiable Wrappers /** - * Returns an unmodifiable view of the specified collection. This method - * allows modules to provide users with "read-only" access to internal - * collections. Query operations on the returned collection "read through" + * Returns an unmodifiable view of the + * specified collection. Query operations on the returned collection "read through" * to the specified collection, and attempts to modify the returned * collection, whether direct or via its iterator, result in an - * UnsupportedOperationException.

    + * {@code UnsupportedOperationException}.

    * * The returned collection does not pass the hashCode and equals * operations through to the backing collection, but relies on - * Object's equals and hashCode methods. This + * {@code Object}'s {@code equals} and {@code hashCode} methods. This * is necessary to preserve the contracts of these operations in the case * that the backing collection is a set or a list.

    * * The returned collection will be serializable if the specified collection * is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the objects in the collection * @param c the collection for which an unmodifiable view is to be * returned. * @return an unmodifiable view of the specified collection. */ + @SuppressWarnings("unchecked") public static Collection unmodifiableCollection(Collection c) { + if (c.getClass() == UnmodifiableCollection.class) { + return (Collection) c; + } return new UnmodifiableCollection<>(c); } @@ -1067,8 +1076,10 @@ public static Collection unmodifiableCollection(Collection c * @serial include */ static class UnmodifiableCollection implements Collection, Serializable { + @java.io.Serial private static final long serialVersionUID = 1820017752578914078L; + @SuppressWarnings("serial") // Conditionally serializable final Collection c; UnmodifiableCollection(Collection c) { @@ -1077,12 +1088,13 @@ static class UnmodifiableCollection implements Collection, Serializable { this.c = c; } - public int size() {return c.size();} - public boolean isEmpty() {return c.isEmpty();} - public boolean contains(Object o) {return c.contains(o);} - public Object[] toArray() {return c.toArray();} - public T[] toArray(T[] a) {return c.toArray(a);} - public String toString() {return c.toString();} + public int size() {return c.size();} + public boolean isEmpty() {return c.isEmpty();} + public boolean contains(Object o) {return c.contains(o);} + public Object[] toArray() {return c.toArray();} + public T[] toArray(T[] a) {return c.toArray(a);} + // public T[] toArray(IntFunction f) {return c.toArray(f);} + public String toString() {return c.toString();} public Iterator iterator() { return new Iterator() { @@ -1151,20 +1163,25 @@ public Stream parallelStream() { } /** - * Returns an unmodifiable view of the specified set. This method allows - * modules to provide users with "read-only" access to internal sets. - * Query operations on the returned set "read through" to the specified + * Returns an unmodifiable view of the + * specified set. Query operations on the returned set "read through" to the specified * set, and attempts to modify the returned set, whether direct or via its - * iterator, result in an UnsupportedOperationException.

    + * iterator, result in an {@code UnsupportedOperationException}.

    * * The returned set will be serializable if the specified set * is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the objects in the set * @param s the set for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified set. */ + @SuppressWarnings("unchecked") public static Set unmodifiableSet(Set s) { + // Not checking for subclasses because of heap pollution and information leakage. + if (s.getClass() == UnmodifiableSet.class) { + return (Set) s; + } return new UnmodifiableSet<>(s); } @@ -1173,6 +1190,7 @@ public static Set unmodifiableSet(Set s) { */ static class UnmodifiableSet extends UnmodifiableCollection implements Set, Serializable { + @java.io.Serial private static final long serialVersionUID = -9215047833775013803L; UnmodifiableSet(Set s) {super(s);} @@ -1181,23 +1199,27 @@ static class UnmodifiableSet extends UnmodifiableCollection } /** - * Returns an unmodifiable view of the specified sorted set. This method - * allows modules to provide users with "read-only" access to internal - * sorted sets. Query operations on the returned sorted set "read + * Returns an unmodifiable view of the + * specified sorted set. Query operations on the returned sorted set "read * through" to the specified sorted set. Attempts to modify the returned * sorted set, whether direct, via its iterator, or via its - * subSet, headSet, or tailSet views, result in - * an UnsupportedOperationException.

    + * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in + * an {@code UnsupportedOperationException}.

    * * The returned sorted set will be serializable if the specified sorted set * is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the objects in the set * @param s the sorted set for which an unmodifiable view is to be * returned. * @return an unmodifiable view of the specified sorted set. */ public static SortedSet unmodifiableSortedSet(SortedSet s) { + // Not checking for subclasses because of heap pollution and information leakage. + if (s.getClass() == UnmodifiableSortedSet.class) { + return s; + } return new UnmodifiableSortedSet<>(s); } @@ -1207,7 +1229,9 @@ public static SortedSet unmodifiableSortedSet(SortedSet s) { static class UnmodifiableSortedSet extends UnmodifiableSet implements SortedSet, Serializable { + @java.io.Serial private static final long serialVersionUID = -4929149591599911165L; + @SuppressWarnings("serial") // Conditionally serializable private final SortedSet ss; UnmodifiableSortedSet(SortedSet s) {super(s); ss = s;} @@ -1229,9 +1253,8 @@ public SortedSet tailSet(E fromElement) { } /** - * Returns an unmodifiable view of the specified navigable set. This method - * allows modules to provide users with "read-only" access to internal - * navigable sets. Query operations on the returned navigable set "read + * Returns an unmodifiable view of the + * specified navigable set. Query operations on the returned navigable set "read * through" to the specified navigable set. Attempts to modify the returned * navigable set, whether direct, via its iterator, or via its * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in @@ -1240,6 +1263,7 @@ public SortedSet tailSet(E fromElement) { * The returned navigable set will be serializable if the specified * navigable set is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the objects in the set * @param s the navigable set for which an unmodifiable view is to be * returned @@ -1247,6 +1271,9 @@ public SortedSet tailSet(E fromElement) { * @since 1.8 */ public static NavigableSet unmodifiableNavigableSet(NavigableSet s) { + if (s.getClass() == UnmodifiableNavigableSet.class) { + return s; + } return new UnmodifiableNavigableSet<>(s); } @@ -1260,6 +1287,7 @@ static class UnmodifiableNavigableSet extends UnmodifiableSortedSet implements NavigableSet, Serializable { + @java.io.Serial private static final long serialVersionUID = -6027448201786391929L; /** @@ -1270,12 +1298,14 @@ static class UnmodifiableNavigableSet */ private static class EmptyNavigableSet extends UnmodifiableNavigableSet implements Serializable { + @java.io.Serial private static final long serialVersionUID = -6291252904449939134L; public EmptyNavigableSet() { - super(new TreeSet()); + super(new TreeSet<>()); } + @java.io.Serial private Object readResolve() { return EMPTY_NAVIGABLE_SET; } } @@ -1286,6 +1316,7 @@ public EmptyNavigableSet() { /** * The instance we are protecting. */ + @SuppressWarnings("serial") // Conditionally serializable private final NavigableSet ns; UnmodifiableNavigableSet(NavigableSet s) {super(s); ns = s;} @@ -1318,22 +1349,27 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { } /** - * Returns an unmodifiable view of the specified list. This method allows - * modules to provide users with "read-only" access to internal - * lists. Query operations on the returned list "read through" to the + * Returns an unmodifiable view of the + * specified list. Query operations on the returned list "read through" to the * specified list, and attempts to modify the returned list, whether * direct or via its iterator, result in an - * UnsupportedOperationException.

    + * {@code UnsupportedOperationException}.

    * * The returned list will be serializable if the specified list * is serializable. Similarly, the returned list will implement * {@link RandomAccess} if the specified list does. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the objects in the list * @param list the list for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified list. */ + @SuppressWarnings("unchecked") public static List unmodifiableList(List list) { + if (list.getClass() == UnmodifiableList.class || list.getClass() == UnmodifiableRandomAccessList.class) { + return (List) list; + } + return (list instanceof RandomAccess ? new UnmodifiableRandomAccessList<>(list) : new UnmodifiableList<>(list)); @@ -1344,8 +1380,10 @@ public static List unmodifiableList(List list) { */ static class UnmodifiableList extends UnmodifiableCollection implements List { + @java.io.Serial private static final long serialVersionUID = -283967356065247728L; + @SuppressWarnings("serial") // Conditionally serializable final List list; UnmodifiableList(List list) { @@ -1428,6 +1466,7 @@ public List subList(int fromIndex, int toIndex) { * serialized in 1.4.1 and deserialized in 1.4 will become * UnmodifiableList instances, as this method was missing in 1.4. */ + @java.io.Serial private Object readResolve() { return (list instanceof RandomAccess ? new UnmodifiableRandomAccessList<>(list) @@ -1450,6 +1489,7 @@ public List subList(int fromIndex, int toIndex) { list.subList(fromIndex, toIndex)); } + @java.io.Serial private static final long serialVersionUID = -2542308836966382001L; /** @@ -1458,28 +1498,34 @@ public List subList(int fromIndex, int toIndex) { * a readResolve method that inverts this transformation upon * deserialization. */ + @java.io.Serial private Object writeReplace() { return new UnmodifiableList<>(list); } } /** - * Returns an unmodifiable view of the specified map. This method - * allows modules to provide users with "read-only" access to internal - * maps. Query operations on the returned map "read through" + * Returns an unmodifiable view of the + * specified map. Query operations on the returned map "read through" * to the specified map, and attempts to modify the returned * map, whether direct or via its collection views, result in an - * UnsupportedOperationException.

    + * {@code UnsupportedOperationException}.

    * * The returned map will be serializable if the specified map * is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the map keys * @param the class of the map values * @param m the map for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified map. */ + @SuppressWarnings("unchecked") public static Map unmodifiableMap(Map m) { + // Not checking for subclasses because of heap pollution and information leakage. + if (m.getClass() == UnmodifiableMap.class) { + return (Map) m; + } return new UnmodifiableMap<>(m); } @@ -1487,8 +1533,10 @@ public static Map unmodifiableMap(Map m) { * @serial include */ private static class UnmodifiableMap implements Map, Serializable { + @java.io.Serial private static final long serialVersionUID = -1034234728574286014L; + @SuppressWarnings("serial") // Conditionally serializable private final Map m; UnmodifiableMap(Map m) { @@ -1613,6 +1661,7 @@ public V merge(K key, V value, */ static class UnmodifiableEntrySet extends UnmodifiableSet> { + @java.io.Serial private static final long serialVersionUID = 7854390611657943733L; @SuppressWarnings({"unchecked", "rawtypes"}) @@ -1621,7 +1670,8 @@ static class UnmodifiableEntrySet super((Set)s); } - static Consumer> entryConsumer(Consumer> action) { + static Consumer> entryConsumer( + Consumer> action) { return e -> action.accept(new UnmodifiableEntry<>(e)); } @@ -1713,10 +1763,10 @@ public Map.Entry next() { public void remove() { throw new UnsupportedOperationException(); } - // Android-note: Oversight of Iterator.forEachRemaining(). - // This seems pretty inconsistent. Unlike other subclasses, - // we aren't delegating to the subclass iterator here. // Seems like an oversight. http://b/110351017 + public void forEachRemaining(Consumer> action) { + i.forEachRemaining(entryConsumer(action)); + } }; } @@ -1776,6 +1826,12 @@ public boolean equals(Object o) { if (o == this) return true; + // Android-changed: (b/247094511) instanceof pattern variable is not yet supported. + /* + return o instanceof Set s + && s.size() == c.size() + && containsAll(s); // Invokes safe containsAll() above + */ if (!(o instanceof Set)) return false; Set s = (Set) o; @@ -1806,11 +1862,18 @@ public V setValue(V value) { public boolean equals(Object o) { if (this == o) return true; + // Android-changed: (b/247094511) instanceof pattern variable is not yet + // supported. + /* + return o instanceof Map.Entry t + && eq(e.getKey(), t.getKey()) + && eq(e.getValue(), t.getValue()); + */ if (!(o instanceof Map.Entry)) return false; Map.Entry t = (Map.Entry)o; return eq(e.getKey(), t.getKey()) && - eq(e.getValue(), t.getValue()); + eq(e.getValue(), t.getValue()); } public String toString() {return e.toString();} } @@ -1818,24 +1881,29 @@ public boolean equals(Object o) { } /** - * Returns an unmodifiable view of the specified sorted map. This method - * allows modules to provide users with "read-only" access to internal - * sorted maps. Query operations on the returned sorted map "read through" + * Returns an unmodifiable view of the + * specified sorted map. Query operations on the returned sorted map "read through" * to the specified sorted map. Attempts to modify the returned * sorted map, whether direct, via its collection views, or via its - * subMap, headMap, or tailMap views, result in - * an UnsupportedOperationException.

    + * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in + * an {@code UnsupportedOperationException}.

    * * The returned sorted map will be serializable if the specified sorted map * is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the map keys * @param the class of the map values * @param m the sorted map for which an unmodifiable view is to be * returned. * @return an unmodifiable view of the specified sorted map. */ + @SuppressWarnings("unchecked") public static SortedMap unmodifiableSortedMap(SortedMap m) { + // Not checking for subclasses because of heap pollution and information leakage. + if (m.getClass() == UnmodifiableSortedMap.class) { + return (SortedMap) m; + } return new UnmodifiableSortedMap<>(m); } @@ -1845,8 +1913,10 @@ public static SortedMap unmodifiableSortedMap(SortedMap extends UnmodifiableMap implements SortedMap, Serializable { + @java.io.Serial private static final long serialVersionUID = -8806743815996713206L; + @SuppressWarnings("serial") // Conditionally serializable private final SortedMap sm; UnmodifiableSortedMap(SortedMap m) {super(m); sm = m; } @@ -1862,9 +1932,8 @@ public SortedMap tailMap(K fromKey) } /** - * Returns an unmodifiable view of the specified navigable map. This method - * allows modules to provide users with "read-only" access to internal - * navigable maps. Query operations on the returned navigable map "read + * Returns an unmodifiable view of the + * specified navigable map. Query operations on the returned navigable map "read * through" to the specified navigable map. Attempts to modify the returned * navigable map, whether direct, via its collection views, or via its * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in @@ -1873,6 +1942,7 @@ public SortedMap tailMap(K fromKey) * The returned navigable map will be serializable if the specified * navigable map is serializable. * + * @implNote This method may return its argument if the argument is already unmodifiable. * @param the class of the map keys * @param the class of the map values * @param m the navigable map for which an unmodifiable view is to be @@ -1880,7 +1950,11 @@ public SortedMap tailMap(K fromKey) * @return an unmodifiable view of the specified navigable map * @since 1.8 */ + @SuppressWarnings("unchecked") public static NavigableMap unmodifiableNavigableMap(NavigableMap m) { + if (m.getClass() == UnmodifiableNavigableMap.class) { + return (NavigableMap) m; + } return new UnmodifiableNavigableMap<>(m); } @@ -1890,6 +1964,7 @@ public static NavigableMap unmodifiableNavigableMap(NavigableMap extends UnmodifiableSortedMap implements NavigableMap, Serializable { + @java.io.Serial private static final long serialVersionUID = -4858195264774772197L; /** @@ -1902,14 +1977,16 @@ static class UnmodifiableNavigableMap private static class EmptyNavigableMap extends UnmodifiableNavigableMap implements Serializable { + @java.io.Serial private static final long serialVersionUID = -2239321462712562324L; - EmptyNavigableMap() { super(new TreeMap()); } + EmptyNavigableMap() { super(new TreeMap<>()); } @Override public NavigableSet navigableKeySet() { return emptyNavigableSet(); } + @java.io.Serial private Object readResolve() { return EMPTY_NAVIGABLE_MAP; } } @@ -1922,6 +1999,7 @@ public NavigableSet navigableKeySet() /** * The instance we wrap and protect. */ + @SuppressWarnings("serial") // Conditionally serializable private final NavigableMap nm; UnmodifiableNavigableMap(NavigableMap m) @@ -2050,9 +2128,12 @@ static Collection synchronizedCollection(Collection c, Object mutex) { * @serial include */ static class SynchronizedCollection implements Collection, Serializable { + @java.io.Serial private static final long serialVersionUID = 3053995032091335093L; + @SuppressWarnings("serial") // Conditionally serializable final Collection c; // Backing Collection + @SuppressWarnings("serial") // Conditionally serializable final Object mutex; // Object on which to synchronize SynchronizedCollection(Collection c) { @@ -2083,6 +2164,9 @@ public Object[] toArray() { public T[] toArray(T[] a) { synchronized (mutex) {return c.toArray(a);} } + // public T[] toArray(IntFunction f) { + // synchronized (mutex) {return c.toArray(f);} + // } public Iterator iterator() { return c.iterator(); // Must be manually synched by user! @@ -2134,6 +2218,7 @@ public Stream stream() { public Stream parallelStream() { return c.parallelStream(); // Must be manually synched by user! } + @java.io.Serial private void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) {s.defaultWriteObject();} } @@ -2146,7 +2231,8 @@ private void writeObject(ObjectOutputStream s) throws IOException { * through the returned set.

    * * It is imperative that the user manually synchronize on the returned - * set when iterating over it: + * collection when traversing it via {@link Iterator}, {@link Spliterator} + * or {@link Stream}: *

          *  Set s = Collections.synchronizedSet(new HashSet());
          *      ...
    @@ -2179,6 +2265,7 @@ static  Set synchronizedSet(Set s, Object mutex) {
         static class SynchronizedSet
               extends SynchronizedCollection
               implements Set {
    +        @java.io.Serial
             private static final long serialVersionUID = 487447009682186044L;
     
             SynchronizedSet(Set s) {
    @@ -2205,8 +2292,9 @@ public int hashCode() {
          * through the returned sorted set (or its views).

    * * It is imperative that the user manually synchronize on the returned - * sorted set when iterating over it or any of its subSet, - * headSet, or tailSet views. + * sorted set when traversing it or any of its {@code subSet}, + * {@code headSet}, or {@code tailSet} views via {@link Iterator}, + * {@link Spliterator} or {@link Stream}: *

          *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
          *      ...
    @@ -2247,8 +2335,10 @@ static class SynchronizedSortedSet
             extends SynchronizedSet
             implements SortedSet
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 8695801310862127406L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final SortedSet ss;
     
             SynchronizedSortedSet(SortedSet s) {
    @@ -2296,8 +2386,9 @@ public E last() {
          * accomplished through the returned navigable set (or its views).

    * * It is imperative that the user manually synchronize on the returned - * navigable set when iterating over it or any of its {@code subSet}, - * {@code headSet}, or {@code tailSet} views. + * navigable set when traversing it, or any of its {@code subSet}, + * {@code headSet}, or {@code tailSet} views, via {@link Iterator}, + * {@link Spliterator} or {@link Stream}: *

          *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
          *      ...
    @@ -2340,8 +2431,10 @@ static class SynchronizedNavigableSet
             extends SynchronizedSortedSet
             implements NavigableSet
         {
    +        @java.io.Serial
             private static final long serialVersionUID = -5505529816273629798L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final NavigableSet ns;
     
             SynchronizedNavigableSet(NavigableSet s) {
    @@ -2411,7 +2504,8 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) {
          * through the returned list.

    * * It is imperative that the user manually synchronize on the returned - * list when iterating over it: + * list when traversing it via {@link Iterator}, {@link Spliterator} + * or {@link Stream}: *

          *  List list = Collections.synchronizedList(new ArrayList());
          *      ...
    @@ -2448,8 +2542,10 @@ static  List synchronizedList(List list, Object mutex) {
         static class SynchronizedList
             extends SynchronizedCollection
             implements List {
    +        @java.io.Serial
             private static final long serialVersionUID = -7754090372962971524L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             final List list;
     
             SynchronizedList(List list) {
    @@ -2530,6 +2626,7 @@ public void sort(Comparator c) {
              * serialized in 1.4.1 and deserialized in 1.4 will become
              * SynchronizedList instances, as this method was missing in 1.4.
              */
    +        @java.io.Serial
             private Object readResolve() {
                 return (list instanceof RandomAccess
                         ? new SynchronizedRandomAccessList<>(list)
    @@ -2559,6 +2656,7 @@ public List subList(int fromIndex, int toIndex) {
                 }
             }
     
    +        @java.io.Serial
             private static final long serialVersionUID = 1530674583602358482L;
     
             /**
    @@ -2567,6 +2665,7 @@ public List subList(int fromIndex, int toIndex) {
              * a readResolve method that inverts this transformation upon
              * deserialization.
              */
    +        @java.io.Serial
             private Object writeReplace() {
                 return new SynchronizedList<>(list);
             }
    @@ -2579,7 +2678,8 @@ private Object writeReplace() {
          * through the returned map.

    * * It is imperative that the user manually synchronize on the returned - * map when iterating over any of its collection views: + * map when traversing any of its collection views via {@link Iterator}, + * {@link Spliterator} or {@link Stream}: *

          *  Map m = Collections.synchronizedMap(new HashMap());
          *      ...
    @@ -2610,9 +2710,12 @@ public static  Map synchronizedMap(Map m) {
          */
         private static class SynchronizedMap
             implements Map, Serializable {
    +        @java.io.Serial
             private static final long serialVersionUID = 1978198479659022715L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final Map m;     // Backing Map
    +        @SuppressWarnings("serial") // Conditionally serializable
             final Object      mutex;        // Object on which to synchronize
     
             SynchronizedMap(Map m) {
    @@ -2747,6 +2850,7 @@ public V merge(K key, V value,
                 synchronized (mutex) {return m.merge(key, value, remappingFunction);}
             }
     
    +        @java.io.Serial
             private void writeObject(ObjectOutputStream s) throws IOException {
                 synchronized (mutex) {s.defaultWriteObject();}
             }
    @@ -2759,9 +2863,10 @@ private void writeObject(ObjectOutputStream s) throws IOException {
          * through the returned sorted map (or its views).

    * * It is imperative that the user manually synchronize on the returned - * sorted map when iterating over any of its collection views, or the - * collections views of any of its subMap, headMap or - * tailMap views. + * sorted map when traversing any of its collection views, or the + * collections views of any of its {@code subMap}, {@code headMap} or + * {@code tailMap} views, via {@link Iterator}, {@link Spliterator} or + * {@link Stream}: *

          *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
          *      ...
    @@ -2781,7 +2886,7 @@ private void writeObject(ObjectOutputStream s) throws IOException {
          *  Set s2 = m2.keySet();  // Needn't be in synchronized block
          *      ...
          *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
    -     *      Iterator i = s.iterator(); // Must be in synchronized block
    +     *      Iterator i = s2.iterator(); // Must be in synchronized block
          *      while (i.hasNext())
          *          foo(i.next());
          *  }
    @@ -2807,8 +2912,10 @@ static class SynchronizedSortedMap
             extends SynchronizedMap
             implements SortedMap
         {
    +        @java.io.Serial
             private static final long serialVersionUID = -8798146769416483793L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final SortedMap sm;
     
             SynchronizedSortedMap(SortedMap m) {
    @@ -2856,9 +2963,10 @@ public K lastKey() {
          * accomplished through the returned navigable map (or its views).

    * * It is imperative that the user manually synchronize on the returned - * navigable map when iterating over any of its collection views, or the + * navigable map when traversing any of its collection views, or the * collections views of any of its {@code subMap}, {@code headMap} or - * {@code tailMap} views. + * {@code tailMap} views, via {@link Iterator}, {@link Spliterator} or + * {@link Stream}: *

          *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
          *      ...
    @@ -2908,8 +3016,10 @@ static class SynchronizedNavigableMap
             extends SynchronizedSortedMap
             implements NavigableMap
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 699392247599746807L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final NavigableMap nm;
     
             SynchronizedNavigableMap(NavigableMap m) {
    @@ -3086,9 +3196,12 @@ static  T[] zeroLengthArray(Class type) {
          * @serial include
          */
         static class CheckedCollection implements Collection, Serializable {
    +        @java.io.Serial
             private static final long serialVersionUID = 1578914078182001775L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             final Collection c;
    +        @SuppressWarnings("serial") // Conditionally serializable
             final Class type;
     
             @SuppressWarnings("unchecked")
    @@ -3108,14 +3221,15 @@ private String badElementMsg(Object o) {
                 this.type = Objects.requireNonNull(type, "type");
             }
     
    -        public int size()                 { return c.size(); }
    -        public boolean isEmpty()          { return c.isEmpty(); }
    -        public boolean contains(Object o) { return c.contains(o); }
    -        public Object[] toArray()         { return c.toArray(); }
    -        public  T[] toArray(T[] a)     { return c.toArray(a); }
    -        public String toString()          { return c.toString(); }
    -        public boolean remove(Object o)   { return c.remove(o); }
    -        public void clear()               {        c.clear(); }
    +        public int size()                          { return c.size(); }
    +        public boolean isEmpty()                   { return c.isEmpty(); }
    +        public boolean contains(Object o)          { return c.contains(o); }
    +        public Object[] toArray()                  { return c.toArray(); }
    +        public  T[] toArray(T[] a)              { return c.toArray(a); }
    +        // public  T[] toArray(IntFunction f) { return c.toArray(f); }
    +        public String toString()                   { return c.toString(); }
    +        public boolean remove(Object o)            { return c.remove(o); }
    +        public void clear()                        {        c.clear(); }
     
             public boolean containsAll(Collection coll) {
                 return c.containsAll(coll);
    @@ -3134,13 +3248,16 @@ public Iterator iterator() {
                 return new Iterator() {
                     public boolean hasNext() { return it.hasNext(); }
                     public E next()          { return it.next(); }
    -                public void remove()     {        it.remove(); }};
    -            // Android-note: Oversight of Iterator.forEachRemaining().
    -            // http://b/110351017
    +                public void remove()     {        it.remove(); }
    +                public void forEachRemaining(Consumer action) {
    +                    it.forEachRemaining(action);
    +                }
    +            };
             }
     
             public boolean add(E e)          { return c.add(typeCheck(e)); }
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private E[] zeroLengthElementArray; // Lazily initialized
     
             private E[] zeroLengthElementArray() {
    @@ -3232,7 +3349,9 @@ static class CheckedQueue
             extends CheckedCollection
             implements Queue, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 1433151992604707767L;
    +        @SuppressWarnings("serial") // Conditionally serializable
             final Queue queue;
     
             CheckedQueue(Queue queue, Class elementType) {
    @@ -3286,6 +3405,7 @@ public static  Set checkedSet(Set s, Class type) {
         static class CheckedSet extends CheckedCollection
                                      implements Set, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 4694047833775013803L;
     
             CheckedSet(Set s, Class elementType) { super(s, elementType); }
    @@ -3333,8 +3453,10 @@ public static  SortedSet checkedSortedSet(SortedSet s,
         static class CheckedSortedSet extends CheckedSet
             implements SortedSet, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 1599911165492914959L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final SortedSet ss;
     
             CheckedSortedSet(SortedSet s, Class type) {
    @@ -3357,7 +3479,7 @@ public SortedSet tailSet(E fromElement) {
             }
         }
     
    -/**
    +    /**
          * Returns a dynamically typesafe view of the specified navigable set.
          * Any attempt to insert an element of the wrong type will result in an
          * immediate {@link ClassCastException}.  Assuming a navigable set
    @@ -3396,8 +3518,10 @@ public static  NavigableSet checkedNavigableSet(NavigableSet s,
         static class CheckedNavigableSet extends CheckedSortedSet
             implements NavigableSet, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = -5429120189805438922L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final NavigableSet ns;
     
             CheckedNavigableSet(NavigableSet s, Class type) {
    @@ -3479,7 +3603,9 @@ static class CheckedList
             extends CheckedCollection
             implements List
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 65247728283967356L;
    +        @SuppressWarnings("serial") // Conditionally serializable
             final List list;
     
             CheckedList(List list, Class type) {
    @@ -3564,6 +3690,7 @@ public void sort(Comparator c) {
         static class CheckedRandomAccessList extends CheckedList
                                                 implements RandomAccess
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 1638200125423088369L;
     
             CheckedRandomAccessList(List list, Class type) {
    @@ -3625,10 +3752,14 @@ public static  Map checkedMap(Map m,
         private static class CheckedMap
             implements Map, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 5742860141034234728L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final Map m;
    +        @SuppressWarnings("serial") // Conditionally serializable
             final Class keyType;
    +        @SuppressWarnings("serial") // Conditionally serializable
             final Class valueType;
     
             private void typeCheck(Object key, Object value) {
    @@ -3812,7 +3943,6 @@ public boolean addAll(Collection> coll) {
     
                 public Iterator> iterator() {
                     final Iterator> i = s.iterator();
    -                final Class valueType = this.valueType;
     
                     return new Iterator>() {
                         public boolean hasNext() { return i.hasNext(); }
    @@ -3821,8 +3951,10 @@ public Iterator> iterator() {
                         public Map.Entry next() {
                             return checkedEntry(i.next(), valueType);
                         }
    -                    // Android-note: Oversight of Iterator.forEachRemaining().
    -                    // http://b/110351017
    +                    public void forEachRemaining(Consumer> action) {
    +                        i.forEachRemaining(
    +                            e -> action.accept(checkedEntry(e, valueType)));
    +                    }
                     };
                 }
     
    @@ -3836,9 +3968,9 @@ public Object[] toArray() {
                      * Ensure that we don't get an ArrayStoreException even if
                      * s.toArray returns an array of something other than Object
                      */
    -                Object[] dest = (CheckedEntry.class.isInstance(
    -                    source.getClass().getComponentType()) ? source :
    -                                 new Object[source.length]);
    +                Object[] dest = (source.getClass() == Object[].class)
    +                    ? source
    +                    : new Object[source.length];
     
                     for (int i = 0; i < source.length; i++)
                         dest[i] = checkedEntry((Map.Entry)source[i],
    @@ -3872,11 +4004,16 @@ public  T[] toArray(T[] a) {
                  * setValue method.
                  */
                 public boolean contains(Object o) {
    +                // Android-changed: (b/247094511) instanceof pattern variable is not yet supported.
    +                /*
    +                return o instanceof Map.Entry e
    +                        && s.contains((e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
    +                 */
                     if (!(o instanceof Map.Entry))
                         return false;
                     Map.Entry e = (Map.Entry) o;
                     return s.contains(
    -                    (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
    +                        (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
                 }
     
                 /**
    @@ -3920,11 +4057,17 @@ private boolean batchRemove(Collection c, boolean complement) {
                 public boolean equals(Object o) {
                     if (o == this)
                         return true;
    +                // Android-changed: (b/247094511) instanceof pattern variable is not yet supported
    +                /*
    +                return o instanceof Set that
    +                        && that.size() == s.size()
    +                        && containsAll(that); // Invokes safe containsAll() above
    +                 */
                     if (!(o instanceof Set))
                         return false;
                     Set that = (Set) o;
                     return that.size() == s.size()
    -                    && containsAll(that); // Invokes safe containsAll() above
    +                        && containsAll(that); // Invokes safe containsAll() above
                 }
     
                 static  CheckedEntry checkedEntry(Map.Entry e,
    @@ -4024,8 +4167,10 @@ public static  SortedMap checkedSortedMap(SortedMap m,
         static class CheckedSortedMap extends CheckedMap
             implements SortedMap, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 1599671320688067438L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final SortedMap sm;
     
             CheckedSortedMap(SortedMap m,
    @@ -4098,8 +4243,10 @@ public static  NavigableMap checkedNavigableMap(NavigableMap m,
         static class CheckedNavigableMap extends CheckedSortedMap
             implements NavigableMap, Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = -4852462692372534096L;
     
    +        @SuppressWarnings("serial") // Conditionally serializable
             private final NavigableMap nm;
     
             CheckedNavigableMap(NavigableMap m,
    @@ -4334,6 +4481,7 @@ private static class EmptyEnumeration implements Enumeration {
     
             public boolean hasMoreElements() { return false; }
             public E nextElement() { throw new NoSuchElementException(); }
    +        public Iterator asIterator() { return emptyIterator(); }
         }
     
         /**
    @@ -4375,12 +4523,14 @@ private static class EmptySet
             extends AbstractSet
             implements Serializable
         {
    +        @java.io.Serial
             private static final long serialVersionUID = 1582296315990362920L;
     
             public Iterator iterator() { return emptyIterator(); }
     
             public int size() {return 0;}
             public boolean isEmpty() {return true;}
    +        public void clear() {}
     
             public boolean contains(Object obj) {return false;}
             public boolean containsAll(Collection c) { return c.isEmpty(); }
    @@ -4407,9 +4557,15 @@ public boolean removeIf(Predicate filter) {
             public Spliterator spliterator() { return Spliterators.emptySpliterator(); }
     
             // Preserves singleton property
    +        @java.io.Serial
             private Object readResolve() {
                 return EMPTY_SET;
             }
    +
    +        @Override
    +        public int hashCode() {
    +            return 0;
    +        }
         }
     
         /**
    @@ -4471,7 +4627,7 @@ public static  NavigableSet emptyNavigableSet() {
          * 
    * * @implNote - * Implementations of this method need not create a separate List + * Implementations of this method need not create a separate {@code List} * object for each call. Using this method is likely to have comparable * cost to using the like-named field. (Unlike this method, the field does * not provide type safety.) @@ -4493,6 +4649,7 @@ public static final List emptyList() { private static class EmptyList extends AbstractList implements RandomAccess, Serializable { + @java.io.Serial private static final long serialVersionUID = 8842843931221139166L; public Iterator iterator() { @@ -4504,6 +4661,7 @@ public ListIterator listIterator() { public int size() {return 0;} public boolean isEmpty() {return true;} + public void clear() {} public boolean contains(Object obj) {return false;} public boolean containsAll(Collection c) { return c.isEmpty(); } @@ -4549,6 +4707,7 @@ public void forEach(Consumer action) { public Spliterator spliterator() { return Spliterators.emptySpliterator(); } // Preserves singleton property + @java.io.Serial private Object readResolve() { return EMPTY_LIST; } @@ -4635,10 +4794,12 @@ private static class EmptyMap extends AbstractMap implements Serializable { + @java.io.Serial private static final long serialVersionUID = 6428348081105594320L; public int size() {return 0;} public boolean isEmpty() {return true;} + public void clear() {} public boolean containsKey(Object key) {return false;} public boolean containsValue(Object value) {return false;} public V get(Object key) {return null;} @@ -4714,6 +4875,7 @@ public V merge(K key, V value, } // Preserves singleton property + @java.io.Serial private Object readResolve() { return EMPTY_MAP; } @@ -4753,8 +4915,8 @@ public void remove() { public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); if (hasNext) { - action.accept(e); hasNext = false; + action.accept(e); } } }; @@ -4813,8 +4975,10 @@ private static class SingletonSet extends AbstractSet implements Serializable { + @java.io.Serial private static final long serialVersionUID = 3193687207550431679L; + @SuppressWarnings("serial") // Conditionally serializable private final E element; SingletonSet(E e) {element = e;} @@ -4840,6 +5004,10 @@ public Spliterator spliterator() { public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } + @Override + public int hashCode() { + return Objects.hashCode(element); + } } /** @@ -4862,8 +5030,10 @@ private static class SingletonList extends AbstractList implements RandomAccess, Serializable { + @java.io.Serial private static final long serialVersionUID = 3093736618740652951L; + @SuppressWarnings("serial") // Conditionally serializable private final E element; SingletonList(E obj) {element = obj;} @@ -4902,6 +5072,10 @@ public void sort(Comparator c) { public Spliterator spliterator() { return singletonSpliterator(element); } + @Override + public int hashCode() { + return 31 + Objects.hashCode(element); + } } /** @@ -4911,7 +5085,7 @@ public Spliterator spliterator() { * @param the class of the map keys * @param the class of the map values * @param key the sole key to be stored in the returned map. - * @param value the value to which the returned map maps key. + * @param value the value to which the returned map maps {@code key}. * @return an immutable map containing only the specified key-value * mapping. * @since 1.3 @@ -4926,9 +5100,12 @@ public static Map singletonMap(K key, V value) { private static class SingletonMap extends AbstractMap implements Serializable { + @java.io.Serial private static final long serialVersionUID = -6979724477215052911L; + @SuppressWarnings("serial") // Conditionally serializable private final K k; + @SuppressWarnings("serial") // Conditionally serializable private final V v; SingletonMap(K key, V value) { @@ -5024,22 +5201,27 @@ public V merge(K key, V value, BiFunction remappingFunction) { throw new UnsupportedOperationException(); } + + @Override + public int hashCode() { + return Objects.hashCode(k) ^ Objects.hashCode(v); + } } // Miscellaneous /** - * Returns an immutable list consisting of n copies of the + * Returns an immutable list consisting of {@code n} copies of the * specified object. The newly allocated data object is tiny (it contains * a single reference to the data object). This method is useful in - * combination with the List.addAll method to grow lists. + * combination with the {@code List.addAll} method to grow lists. * The returned list is serializable. * * @param the class of the object to copy and of the objects * in the returned list. * @param n the number of elements in the returned list. * @param o the element to appear repeatedly in the returned list. - * @return an immutable list consisting of n copies of the + * @return an immutable list consisting of {@code n} copies of the * specified object. * @throws IllegalArgumentException if {@code n < 0} * @see List#addAll(Collection) @@ -5058,9 +5240,11 @@ private static class CopiesList extends AbstractList implements RandomAccess, Serializable { + @java.io.Serial private static final long serialVersionUID = 2739099268398711800L; final int n; + @SuppressWarnings("serial") // Conditionally serializable final E element; CopiesList(int n, E e) { @@ -5126,6 +5310,55 @@ public List subList(int fromIndex, int toIndex) { return new CopiesList<>(toIndex - fromIndex, element); } + @Override + public int hashCode() { + if (n == 0) return 1; + // hashCode of n repeating elements is 31^n + elementHash * Sum(31^k, k = 0..n-1) + // this implementation completes in O(log(n)) steps taking advantage of + // 31^(2*n) = (31^n)^2 and Sum(31^k, k = 0..(2*n-1)) = Sum(31^k, k = 0..n-1) * (31^n + 1) + int pow = 31; + int sum = 1; + for (int i = Integer.numberOfLeadingZeros(n) + 1; i < Integer.SIZE; i++) { + sum *= pow + 1; + pow *= pow; + if ((n << i) < 0) { + pow *= 31; + sum = sum * 31 + 1; + } + } + return pow + sum * (element == null ? 0 : element.hashCode()); + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + // Android-changed: (b/247094511) instanceof pattern variable is not yet supported. + // if (o instanceof CopiesList other) { + if (o instanceof CopiesList) { + CopiesList other = (CopiesList) o; + return n == other.n && (n == 0 || eq(element, other.element)); + } + if (!(o instanceof List)) + return false; + + int remaining = n; + E e = element; + Iterator itr = ((List) o).iterator(); + if (e == null) { + while (itr.hasNext() && remaining-- > 0) { + if (itr.next() != null) + return false; + } + } else { + while (itr.hasNext() && remaining-- > 0) { + if (!e.equals(itr.next())) + return false; + } + } + return remaining == 0 && !itr.hasNext(); + } + // Override default methods in Collection @Override public Stream stream() { @@ -5141,6 +5374,13 @@ public Stream parallelStream() { public Spliterator spliterator() { return stream().spliterator(); } + + @java.io.Serial + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // sun.misc.SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, n); + } } /** @@ -5160,7 +5400,7 @@ public Spliterator spliterator() { * @param the class of the objects compared by the comparator * @return A comparator that imposes the reverse of the natural * ordering on a collection of objects that implement - * the Comparable interface. + * the {@code Comparable} interface. * @see Comparable */ @SuppressWarnings("unchecked") @@ -5174,6 +5414,7 @@ public static Comparator reverseOrder() { private static class ReverseComparator implements Comparator>, Serializable { + @java.io.Serial private static final long serialVersionUID = 7207038068494060240L; static final ReverseComparator REVERSE_ORDER @@ -5183,6 +5424,7 @@ public int compare(Comparable c1, Comparable c2) { return c2.compareTo(c1); } + @java.io.Serial private Object readResolve() { return Collections.reverseOrder(); } @Override @@ -5208,14 +5450,19 @@ public Comparator> reversed() { * specified comparator. * @since 1.5 */ + @SuppressWarnings("unchecked") public static Comparator reverseOrder(Comparator cmp) { - if (cmp == null) - return reverseOrder(); - - if (cmp instanceof ReverseComparator2) - return ((ReverseComparator2)cmp).cmp; - - return new ReverseComparator2<>(cmp); + if (cmp == null) { + return (Comparator) ReverseComparator.REVERSE_ORDER; + } else if (cmp == ReverseComparator.REVERSE_ORDER) { + return (Comparator) Comparators.NaturalOrderComparator.INSTANCE; + } else if (cmp == Comparators.NaturalOrderComparator.INSTANCE) { + return (Comparator) ReverseComparator.REVERSE_ORDER; + } else if (cmp instanceof ReverseComparator2) { + return ((ReverseComparator2) cmp).cmp; + } else { + return new ReverseComparator2<>(cmp); + } } /** @@ -5224,6 +5471,7 @@ public static Comparator reverseOrder(Comparator cmp) { private static class ReverseComparator2 implements Comparator, Serializable { + @java.io.Serial private static final long serialVersionUID = 4374092139857L; /** @@ -5233,6 +5481,7 @@ private static class ReverseComparator2 implements Comparator, * * @serial */ + @SuppressWarnings("serial") // Conditionally serializable final Comparator cmp; ReverseComparator2(Comparator cmp) { @@ -5265,6 +5514,11 @@ public Comparator reversed() { * interoperability with legacy APIs that require an enumeration * as input. * + *

    The iterator returned from a call to {@link Enumeration#asIterator()} + * does not support removal of elements from the specified collection. This + * is necessary to avoid unintentionally increasing the capabilities of the + * returned enumeration. + * * @param the class of the objects in the collection * @param c the collection for which an enumeration is to be returned. * @return an enumeration over the specified collection. @@ -5319,14 +5573,14 @@ static boolean eq(Object o1, Object o2) { /** * Returns the number of elements in the specified collection equal to the * specified object. More formally, returns the number of elements - * e in the collection such that - * (o == null ? e == null : o.equals(e)). + * {@code e} in the collection such that + * {@code Objects.equals(o, e)}. * * @param c the collection in which to determine the frequency - * of o + * of {@code o} * @param o the object whose frequency is to be determined * @return the number of elements in {@code c} equal to {@code o} - * @throws NullPointerException if c is null + * @throws NullPointerException if {@code c} is null * @since 1.5 */ public static int frequency(Collection c, Object o) { @@ -5436,9 +5690,8 @@ public static boolean disjoint(Collection c1, Collection c2) { /** * Adds all of the specified elements to the specified collection. * Elements to be added may be specified individually or as an array. - * The behavior of this convenience method is identical to that of - * c.addAll(Arrays.asList(elements)), but this method is likely - * to run significantly faster under most implementations. + * The behaviour of this convenience method is similar to that of + * {@code cc.addAll(Collections.unmodifiableList(Arrays.asList(elements)))}. * *

    When elements are specified individually, this method provides a * convenient way to add a few elements to an existing collection: @@ -5447,16 +5700,16 @@ public static boolean disjoint(Collection c1, Collection c2) { * * * @param the class of the elements to add and of the collection - * @param c the collection into which elements are to be inserted - * @param elements the elements to insert into c - * @return true if the collection changed as a result of the call - * @throws UnsupportedOperationException if c does not support - * the add operation - * @throws NullPointerException if elements contains one or more - * null values and c does not permit null elements, or - * if c or elements are null + * @param c the collection into which {@code elements} are to be inserted + * @param elements the elements to insert into {@code c} + * @return {@code true} if the collection changed as a result of the call + * @throws UnsupportedOperationException if {@code c} does not support + * the {@code add} operation + * @throws NullPointerException if {@code elements} contains one or more + * null values and {@code c} does not permit null elements, or + * if {@code c} or {@code elements} are {@code null} * @throws IllegalArgumentException if some property of a value in - * elements prevents it from being added to c + * {@code elements} prevents it from being added to {@code c} * @see Collection#addAll(Collection) * @since 1.5 */ @@ -5478,9 +5731,9 @@ public static boolean addAll(Collection c, T... elements) { * HashMap} or {@link TreeMap}). * *

    Each method invocation on the set returned by this method results in - * exactly one method invocation on the backing map or its keySet - * view, with one exception. The addAll method is implemented - * as a sequence of put invocations on the backing map. + * exactly one method invocation on the backing map or its {@code keySet} + * view, with one exception. The {@code addAll} method is implemented + * as a sequence of {@code put} invocations on the backing map. * *

    The specified map must be empty at the time this method is invoked, * and should not be accessed directly after this method returns. These @@ -5496,7 +5749,7 @@ public static boolean addAll(Collection c, T... elements) { * returned set * @param map the backing map * @return the set backed by the map - * @throws IllegalArgumentException if map is not empty + * @throws IllegalArgumentException if {@code map} is not empty * @since 1.6 */ public static Set newSetFromMap(Map map) { @@ -5509,6 +5762,7 @@ public static Set newSetFromMap(Map map) { private static class SetFromMap extends AbstractSet implements Set, Serializable { + @SuppressWarnings("serial") // Conditionally serializable private final Map m; // The backing map private transient Set s; // Its keySet @@ -5553,8 +5807,10 @@ public boolean removeIf(Predicate filter) { @Override public Stream parallelStream() {return s.parallelStream();} + @java.io.Serial private static final long serialVersionUID = 2454657854757543876L; + @java.io.Serial private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { @@ -5565,10 +5821,10 @@ private void readObject(java.io.ObjectInputStream stream) /** * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo) - * {@link Queue}. Method add is mapped to push, - * remove is mapped to pop and so on. This + * {@link Queue}. Method {@code add} is mapped to {@code push}, + * {@code remove} is mapped to {@code pop} and so on. This * view can be useful when you would like to use a method - * requiring a Queue but you need Lifo ordering. + * requiring a {@code Queue} but you need Lifo ordering. * *

    Each method invocation on the queue returned by this method * results in exactly one method invocation on the backing deque, with @@ -5582,7 +5838,7 @@ private void readObject(java.io.ObjectInputStream stream) * @since 1.6 */ public static Queue asLifoQueue(Deque deque) { - return new AsLIFOQueue<>(deque); + return new AsLIFOQueue<>(Objects.requireNonNull(deque)); } /** @@ -5590,27 +5846,30 @@ public static Queue asLifoQueue(Deque deque) { */ static class AsLIFOQueue extends AbstractQueue implements Queue, Serializable { + @java.io.Serial private static final long serialVersionUID = 1802017725587941708L; + @SuppressWarnings("serial") // Conditionally serializable private final Deque q; - AsLIFOQueue(Deque q) { this.q = q; } - public boolean add(E e) { q.addFirst(e); return true; } - public boolean offer(E e) { return q.offerFirst(e); } - public E poll() { return q.pollFirst(); } - public E remove() { return q.removeFirst(); } - public E peek() { return q.peekFirst(); } - public E element() { return q.getFirst(); } - public void clear() { q.clear(); } - public int size() { return q.size(); } - public boolean isEmpty() { return q.isEmpty(); } - public boolean contains(Object o) { return q.contains(o); } - public boolean remove(Object o) { return q.remove(o); } - public Iterator iterator() { return q.iterator(); } - public Object[] toArray() { return q.toArray(); } - public T[] toArray(T[] a) { return q.toArray(a); } - public String toString() { return q.toString(); } - public boolean containsAll(Collection c) {return q.containsAll(c);} - public boolean removeAll(Collection c) {return q.removeAll(c);} - public boolean retainAll(Collection c) {return q.retainAll(c);} + AsLIFOQueue(Deque q) { this.q = q; } + public boolean add(E e) { q.addFirst(e); return true; } + public boolean offer(E e) { return q.offerFirst(e); } + public E poll() { return q.pollFirst(); } + public E remove() { return q.removeFirst(); } + public E peek() { return q.peekFirst(); } + public E element() { return q.getFirst(); } + public void clear() { q.clear(); } + public int size() { return q.size(); } + public boolean isEmpty() { return q.isEmpty(); } + public boolean contains(Object o) { return q.contains(o); } + public boolean remove(Object o) { return q.remove(o); } + public Iterator iterator() { return q.iterator(); } + public Object[] toArray() { return q.toArray(); } + public T[] toArray(T[] a) { return q.toArray(a); } + // public T[] toArray(IntFunction f) { return q.toArray(f); } + public String toString() { return q.toString(); } + public boolean containsAll(Collection c) { return q.containsAll(c); } + public boolean removeAll(Collection c) { return q.removeAll(c); } + public boolean retainAll(Collection c) { return q.retainAll(c); } // We use inherited addAll; forwarding addAll would be wrong // Override default methods in Collection diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ComparableTimSort.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ComparableTimSort.java index 36c8d90f0f..7b90807722 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ComparableTimSort.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ComparableTimSort.java @@ -305,7 +305,7 @@ private static void binarySort(Object[] a, int lo, int hi, int start) { * @param a the array in which a run is to be counted and possibly reversed * @param lo index of the first element in the run * @param hi index after the last element that may be contained in the run. - It is required that {@code lo < hi}. + * It is required that {@code lo < hi}. * @return the length of the run beginning at the specified position in * the specified array */ @@ -394,19 +394,23 @@ private void pushRun(int runBase, int runLen) { * This method is called each time a new run is pushed onto the stack, * so the invariants are guaranteed to hold for i < stackSize upon * entry to the method. + * + * Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer, + * Richard Bubel and Reiner Hahnle, this is fixed with respect to + * the analysis in "On the Worst-Case Complexity of TimSort" by + * Nicolas Auger, Vincent Jug, Cyril Nicaud, and Carine Pivoteau. */ private void mergeCollapse() { while (stackSize > 1) { int n = stackSize - 2; - if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) { + if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] || + n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) { if (runLen[n - 1] < runLen[n + 1]) n--; - mergeAt(n); - } else if (runLen[n] <= runLen[n + 1]) { - mergeAt(n); - } else { + } else if (n < 0 || runLen[n] > runLen[n + 1]) { break; // Invariant is established } + mergeAt(n); } } @@ -883,12 +887,7 @@ private void mergeHi(int base1, int len1, int base2, int len2) { private Object[] ensureCapacity(int minCapacity) { if (tmpLen < minCapacity) { // Compute smallest power of 2 > minCapacity - int newSize = minCapacity; - newSize |= newSize >> 1; - newSize |= newSize >> 2; - newSize |= newSize >> 4; - newSize |= newSize >> 8; - newSize |= newSize >> 16; + int newSize = -1 >>> Integer.numberOfLeadingZeros(minCapacity); newSize++; if (newSize < 0) // Not bloody likely! diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparator.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparator.java index ecf8d64ea9..0516559574 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparator.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -42,20 +42,20 @@ * SortedMap sorted maps}), or to provide an ordering for collections of * objects that don't have a {@link Comparable natural ordering}.

    * - * The ordering imposed by a comparator c on a set of elements - * S is said to be consistent with equals if and only if - * c.compare(e1, e2)==0 has the same boolean value as - * e1.equals(e2) for every e1 and e2 in - * S.

    + * The ordering imposed by a comparator {@code c} on a set of elements + * {@code S} is said to be consistent with equals if and only if + * {@code c.compare(e1, e2)==0} has the same boolean value as + * {@code e1.equals(e2)} for every {@code e1} and {@code e2} in + * {@code S}.

    * * Caution should be exercised when using a comparator capable of imposing an * ordering inconsistent with equals to order a sorted set (or sorted map). - * Suppose a sorted set (or sorted map) with an explicit comparator c - * is used with elements (or keys) drawn from a set S. If the - * ordering imposed by c on S is inconsistent with equals, + * Suppose a sorted set (or sorted map) with an explicit comparator {@code c} + * is used with elements (or keys) drawn from a set {@code S}. If the + * ordering imposed by {@code c} on {@code S} is inconsistent with equals, * the sorted set (or sorted map) will behave "strangely." In particular the * sorted set (or sorted map) will violate the general contract for set (or - * map), which is defined in terms of equals.

    + * map), which is defined in terms of {@code equals}.

    * * For example, suppose one adds two elements {@code a} and {@code b} such that * {@code (a.equals(b) && c.compare(a, b) != 0)} @@ -67,23 +67,23 @@ * {@link Set#add Set.add} method.

    * * Note: It is generally a good idea for comparators to also implement - * java.io.Serializable, as they may be used as ordering methods in + * {@code java.io.Serializable}, as they may be used as ordering methods in * serializable data structures (like {@link TreeSet}, {@link TreeMap}). In * order for the data structure to serialize successfully, the comparator (if - * provided) must implement Serializable.

    + * provided) must implement {@code Serializable}.

    * * For the mathematically inclined, the relation that defines the - * imposed ordering that a given comparator c imposes on a - * given set of objects S is:

    + * imposed ordering that a given comparator {@code c} imposes on a
    + * given set of objects {@code S} is:
      *       {(x, y) such that c.compare(x, y) <= 0}.
      * 
    The quotient for this total order is:
      *       {(x, y) such that c.compare(x, y) == 0}.
      * 
    * - * It follows immediately from the contract for compare that the - * quotient is an equivalence relation on S, and that the - * imposed ordering is a total order on S. When we say that - * the ordering imposed by c on S is consistent with + * It follows immediately from the contract for {@code compare} that the + * quotient is an equivalence relation on {@code S}, and that the + * imposed ordering is a total order on {@code S}. When we say that + * the ordering imposed by {@code c} on {@code S} is consistent with * equals, we mean that the quotient for the ordering is the equivalence * relation defined by the objects' {@link Object#equals(Object) * equals(Object)} method(s):
    @@ -94,7 +94,7 @@
      * an equivalence relation.
      *
      * 

    This interface is a member of the - * + * * Java Collections Framework. * * @param the type of objects that may be compared by this comparator @@ -112,30 +112,30 @@ public interface Comparator { * zero, or a positive integer as the first argument is less than, equal * to, or greater than the second.

    * - * In the foregoing description, the notation - * sgn(expression) designates the mathematical - * signum function, which is defined to return one of -1, - * 0, or 1 according to whether the value of - * expression is negative, zero or positive.

    - * - * The implementor must ensure that sgn(compare(x, y)) == - * -sgn(compare(y, x)) for all x and y. (This - * implies that compare(x, y) must throw an exception if and only - * if compare(y, x) throws an exception.)

    + * The implementor must ensure that {@code sgn(compare(x, y)) == + * -sgn(compare(y, x))} for all {@code x} and {@code y}. (This + * implies that {@code compare(x, y)} must throw an exception if and only + * if {@code compare(y, x)} throws an exception.)

    * * The implementor must also ensure that the relation is transitive: - * ((compare(x, y)>0) && (compare(y, z)>0)) implies - * compare(x, z)>0.

    + * {@code ((compare(x, y)>0) && (compare(y, z)>0))} implies + * {@code compare(x, z)>0}.

    * - * Finally, the implementor must ensure that compare(x, y)==0 - * implies that sgn(compare(x, z))==sgn(compare(y, z)) for all - * z.

    + * Finally, the implementor must ensure that {@code compare(x, y)==0} + * implies that {@code sgn(compare(x, z))==sgn(compare(y, z))} for all + * {@code z}.

    * * It is generally the case, but not strictly required that - * (compare(x, y)==0) == (x.equals(y)). Generally speaking, + * {@code (compare(x, y)==0) == (x.equals(y))}. Generally speaking, * any comparator that violates this condition should clearly indicate * this fact. The recommended language is "Note: this comparator - * imposes orderings that are inconsistent with equals." + * imposes orderings that are inconsistent with equals."

    + * + * In the foregoing description, the notation + * {@code sgn(}expression{@code )} designates the mathematical + * signum function, which is defined to return one of {@code -1}, + * {@code 0}, or {@code 1} according to whether the value of + * expression is negative, zero, or positive, respectively. * * @param o1 the first object to be compared. * @param o2 the second object to be compared. @@ -153,19 +153,19 @@ public interface Comparator { * Indicates whether some other object is "equal to" this * comparator. This method must obey the general contract of * {@link Object#equals(Object)}. Additionally, this method can return - * true only if the specified object is also a comparator + * {@code true} only if the specified object is also a comparator * and it imposes the same ordering as this comparator. Thus, - * comp1.equals(comp2) implies that sgn(comp1.compare(o1, - * o2))==sgn(comp2.compare(o1, o2)) for every object reference - * o1 and o2.

    + * {@code comp1.equals(comp2)} implies that {@code sgn(comp1.compare(o1, + * o2))==sgn(comp2.compare(o1, o2))} for every object reference + * {@code o1} and {@code o2}.

    * * Note that it is always safe not to override - * Object.equals(Object). However, overriding this method may, + * {@code Object.equals(Object)}. However, overriding this method may, * in some cases, improve performance by allowing programs to determine * that two distinct comparators impose the same order. * * @param obj the reference object with which to compare. - * @return true only if the specified object is also + * @return {@code true} only if the specified object is also * a comparator and it imposes the same ordering as this * comparator. * @see Object#equals(Object) @@ -267,7 +267,7 @@ default > Comparator thenComparing( /** * Returns a lexicographic-order comparator with a function that - * extracts a {@code int} sort key. + * extracts an {@code int} sort key. * * @implSpec This default implementation behaves as if {@code * thenComparing(comparingInt(keyExtractor))}. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparators.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparators.java index ee806798d7..8104f99046 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparators.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Comparators.java @@ -61,7 +61,7 @@ public Comparator> reversed() { /** * Null-friendly comparators */ - final static class NullComparator implements Comparator, Serializable { + static final class NullComparator implements Comparator, Serializable { private static final long serialVersionUID = -7569533591570686392L; private final boolean nullFirst; // if null, non-null Ts are considered equal diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Currency.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Currency.java index b6146d0037..acf6a5663b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Currency.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Currency.java @@ -1,28 +1,54 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 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 com.google.j2objc.LibraryNotLinkedError; import com.google.j2objc.util.CurrencyNumericCodes; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; +import java.io.IOException; import java.io.Serializable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.stream.Collectors; + +import sun.util.logging.PlatformLogger; + import libcore.icu.ICU; import libcore.icu.LocaleData; +// BEGIN Android-changed: Removed docs about superseding runtime currency data. +// Doing so via a properties file is not supported on Android. /** * Represents a currency. Currencies are identified by their ISO 4217 currency * codes. Visit the @@ -33,9 +59,17 @@ * no public constructor. You obtain a Currency instance using * the getInstance methods. * + *

    + * It is recommended to use {@link java.math.BigDecimal} class while dealing + * with {@code Currency} or monetary values as it provides better handling of floating + * point numbers and their operations. + * + * @see java.math.BigDecimal * @since 1.4 */ +// END Android-changed: Removed docs about superseding runtime currency data. public final class Currency implements Serializable { + private static final long serialVersionUID = -158308464356906721L; private static final HashMap codesToCurrencies = new HashMap(); @@ -51,6 +85,186 @@ public final class Currency implements Serializable { */ private final String currencyCode; + // BEGIN Android-changed: Use ICU. + // We do not keep track of defaultFractionDigits and numericCode separately. + /* + /** + * Default fraction digits for this currency. + * Set from currency data tables. + * + private final transient int defaultFractionDigits; + */ + + /* + * ISO 4217 numeric code for this currency. + * Set from currency data tables. + * + private final transient int numericCode; + */ + // private transient final android.icu.util.Currency icuCurrency; + // END Android-changed: Use ICU. + + + // class data: instance map + + private static ConcurrentMap instances = new ConcurrentHashMap<>(7); + private static HashSet available; + + // BEGIN Android-removed: Use ICU. + // We don't need any of these static fields nor the static initializer. + /* + // Class data: currency data obtained from currency.data file. + // Purpose: + // - determine valid country codes + // - determine valid currency codes + // - map country codes to currency codes + // - obtain default fraction digits for currency codes + // + // sc = special case; dfd = default fraction digits + // Simple countries are those where the country code is a prefix of the + // currency code, and there are no known plans to change the currency. + // + // table formats: + // - mainTable: + // - maps country code to 32-bit int + // - 26*26 entries, corresponding to [A-Z]*[A-Z] + // - \u007F -> not valid country + // - bits 20-31: unused + // - bits 10-19: numeric code (0 to 1023) + // - bit 9: 1 - special case, bits 0-4 indicate which one + // 0 - simple country, bits 0-4 indicate final char of currency code + // - bits 5-8: fraction digits for simple countries, 0 for special cases + // - bits 0-4: final char for currency code for simple country, or ID of special case + // - special case IDs: + // - 0: country has no currency + // - other: index into specialCasesList + + static int formatVersion; + static int dataVersion; + static int[] mainTable; + static List specialCasesList; + static List otherCurrenciesList; + + // handy constants - must match definitions in GenerateCurrencyData + // magic number + private static final int MAGIC_NUMBER = 0x43757244; + // number of characters from A to Z + private static final int A_TO_Z = ('Z' - 'A') + 1; + // entry for invalid country codes + private static final int INVALID_COUNTRY_ENTRY = 0x0000007F; + // entry for countries without currency + private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200; + // mask for simple case country entries + private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000; + // mask for simple case country entry final character + private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F; + // mask for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0; + // shift count for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5; + // maximum number for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9; + // mask for special case country entries + private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200; + // mask for special case country index + private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F; + // delta from entry index component in main table to index into special case tables + private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1; + // mask for distinguishing simple and special case countries + private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK; + // mask for the numeric code of the currency + private static final int NUMERIC_CODE_MASK = 0x000FFC00; + // shift count for the numeric code of the currency + private static final int NUMERIC_CODE_SHIFT = 10; + + // Currency data format version + private static final int VALID_FORMAT_VERSION = 3; + + static { + AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public Void run() { + try { + try (InputStream in = getClass().getResourceAsStream("/java/util/currency.data")) { + if (in == null) { + throw new InternalError("Currency data not found"); + } + DataInputStream dis = new DataInputStream(new BufferedInputStream(in)); + if (dis.readInt() != MAGIC_NUMBER) { + throw new InternalError("Currency data is possibly corrupted"); + } + formatVersion = dis.readInt(); + if (formatVersion != VALID_FORMAT_VERSION) { + throw new InternalError("Currency data format is incorrect"); + } + dataVersion = dis.readInt(); + mainTable = readIntArray(dis, A_TO_Z * A_TO_Z); + int scCount = dis.readInt(); + specialCasesList = readSpecialCases(dis, scCount); + int ocCount = dis.readInt(); + otherCurrenciesList = readOtherCurrencies(dis, ocCount); + } + } catch (IOException e) { + throw new InternalError(e); + } + + // look for the properties file for overrides + String propsFile = System.getProperty("java.util.currency.data"); + if (propsFile == null) { + propsFile = StaticProperty.javaHome() + File.separator + "lib" + + File.separator + "currency.properties"; + } + try { + File propFile = new File(propsFile); + if (propFile.exists()) { + Properties props = new Properties(); + try (FileReader fr = new FileReader(propFile)) { + props.load(fr); + } + Pattern propertiesPattern = + Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*" + + "(\\d+)\\s*,?\\s*(\\d{4}-\\d{2}-\\d{2}T\\d{2}:" + + "\\d{2}:\\d{2})?"); + List currencyEntries + = getValidCurrencyData(props, propertiesPattern); + currencyEntries.forEach(Currency::replaceCurrencyData); + } + } catch (IOException e) { + CurrencyProperty.info("currency.properties is ignored" + + " because of an IOException", e); + } + return null; + } + }); + } + + /** + * Constants for retrieving localized names from the name providers. + * + private static final int SYMBOL = 0; + private static final int DISPLAYNAME = 1; + */ + // END Android-removed: Use ICU. + + /** + * Constructs a Currency instance. The constructor is private + * so that we can insure that there's never more than one instance for a + * given currency. + */ + // BEGIN Android-changed: Use ICU. + // We do not keep track of defaultFractionDigits and numericCode separately. + /* + private Currency(String currencyCode, int defaultFractionDigits, int numericCode) { + this.currencyCode = currencyCode; + this.defaultFractionDigits = defaultFractionDigits; + this.numericCode = numericCode; + } + */ + // private Currency(android.icu.util.Currency icuCurrency) { + // this.icuCurrency = icuCurrency; + // this.currencyCode = icuCurrency.getCurrencyCode(); + // } + // END Android-changed: Use ICU. private Currency(String currencyCode) { this.currencyCode = currencyCode; if (!availableCurrencyCodes.contains(currencyCode)) { @@ -68,6 +282,61 @@ private Currency(String currencyCode) { * @exception IllegalArgumentException if currencyCode is not * a supported ISO 4217 code. */ + // public static Currency getInstance(String currencyCode) { + // // BEGIN Android-changed: Use ICU. + // // Upstream uses a private static helper method, implemented differently. + // Currency instance = instances.get(currencyCode); + // if (instance != null) { + // return instance; + // } + // android.icu.util.Currency icuInstance = + // android.icu.util.Currency.getInstance(currencyCode); + // if (icuInstance == null) { + // return null; + // } + // /* + // if (defaultFractionDigits == Integer.MIN_VALUE) { + // // Currency code not internally generated, need to verify first + // // A currency code must have 3 characters and exist in the main table + // // or in the list of other currencies. + // boolean found = false; + // if (currencyCode.length() != 3) { + // throw new IllegalArgumentException(); + // } + // char char1 = currencyCode.charAt(0); + // char char2 = currencyCode.charAt(1); + // int tableEntry = getMainTableEntry(char1, char2); + // if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK + // && tableEntry != INVALID_COUNTRY_ENTRY + // && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) { + // defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT; + // numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT; + // found = true; + // } else { //special case + // int[] fractionAndNumericCode = SpecialCaseEntry.findEntry(currencyCode); + // if (fractionAndNumericCode != null) { + // defaultFractionDigits = fractionAndNumericCode[0]; + // numericCode = fractionAndNumericCode[1]; + // found = true; + // } + // } + + // if (!found) { + // OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode); + // if (ocEntry == null) { + // throw new IllegalArgumentException(); + // } + // defaultFractionDigits = ocEntry.fraction; + // numericCode = ocEntry.numericCode; + // } + // } + // */ + + // Currency currencyVal = new Currency(icuInstance); + // // END Android-changed: Use ICU. + // instance = instances.putIfAbsent(currencyCode, currencyVal); + // return (instance != null ? instance : currencyVal); + // } public static Currency getInstance(String currencyCode) { synchronized (codesToCurrencies) { Currency currency = codesToCurrencies.get(currencyCode); @@ -79,6 +348,7 @@ public static Currency getInstance(String currencyCode) { } } + // Android-changed: Remove "rg" support in the javadoc. See http://b/228322300. /** * Returns the Currency instance for the country of the * given locale. The language and variant components of the locale @@ -88,6 +358,11 @@ public static Currency getInstance(String currencyCode) { * until December 31, 2001, and the Euro from January 1, 2002, local time * of the respective countries. *

    + * If the specified {@code locale} contains "cu" + * Unicode extensions, + * the instance returned from this method reflects + * the values specified with those extensions. + *

    * The method returns null for territories that don't * have a currency, such as Antarctica. * @@ -95,8 +370,8 @@ public static Currency getInstance(String currencyCode) { * instance is needed * @return the Currency instance for the country of the given * locale, or {@code null} - * @exception NullPointerException if locale or its country - * code is {@code null} + * @exception NullPointerException if locale + * is {@code null} * @exception IllegalArgumentException if the country of the given {@code locale} * is not a supported ISO 3166 country code. */ @@ -161,6 +436,7 @@ public String getCurrencyCode() { return currencyCode; } + // Android-changed: Remove "rg" support in the javadoc. See http://b/228322300. /** * Gets the symbol of this currency for the default * {@link Locale.Category#DISPLAY DISPLAY} locale. @@ -179,6 +455,7 @@ public String getSymbol() { return getSymbol(Locale.getDefault(Locale.Category.DISPLAY)); } + // Android-changed: Remove "rg" support in the javadoc. See http://b/228322300. /** * Gets the symbol of this currency for the specified locale. * For example, for the US Dollar, the symbol is "$" if the specified @@ -191,6 +468,21 @@ public String getSymbol() { * @exception NullPointerException if locale is null */ public String getSymbol(Locale locale) { + // BEGIN Android-changed: Use ICU. + /* + LocaleServiceProviderPool pool = + LocaleServiceProviderPool.getPool(CurrencyNameProvider.class); + locale = CalendarDataUtility.findRegionOverride(locale); + String symbol = pool.getLocalizedObject( + CurrencyNameGetter.INSTANCE, + locale, currencyCode, SYMBOL); + if (symbol != null) { + return symbol; + } + + // use currency code as symbol of last resort + return currencyCode; + */ if (locale == null) { throw new NullPointerException("locale == null"); } @@ -207,13 +499,15 @@ public String getSymbol(Locale locale) { /** * Gets the default number of fraction digits used with this currency. + * Note that the number of fraction digits is the same as ISO 4217's + * minor unit for the currency. * For example, the default number of fraction digits for the Euro is 2, * while for the Japanese Yen it's 0. * In the case of pseudo-currencies, such as IMF Special Drawing Rights, * -1 is returned. * * @return the default number of fraction digits used with this currency - */ + */ public int getDefaultFractionDigits() { // In some places the code XXX is used as the fall back currency. // The RI returns -1, but ICU defaults to 2 for unknown currencies. @@ -240,6 +534,35 @@ public int getNumericCode() { } } + /** + * Returns the 3 digit ISO 4217 numeric code of this currency as a {@code String}. + * Unlike {@link #getNumericCode()}, which returns the numeric code as {@code int}, + * this method always returns the numeric code as a 3 digit string. + * e.g. a numeric value of 32 would be returned as "032", + * and a numeric value of 6 would be returned as "006". + * + * @return the 3 digit ISO 4217 numeric code of this currency as a {@code String} + * @since 9 + */ + public String getNumericCodeAsString() { + // Android-added: We don't store the code as a field. Call getNumericCode(). + int numericCode = getNumericCode(); + /* numeric code could be returned as a 3 digit string simply by using + String.format("%03d",numericCode); which uses regex to parse the format, + "%03d" in this case. Parsing a regex gives an extra performance overhead, + so String.format() approach is avoided in this scenario. + */ + if (numericCode < 100) { + StringBuilder sb = new StringBuilder(); + sb.append('0'); + if (numericCode < 10) { + sb.append('0'); + } + return sb.append(numericCode).toString(); + } + return String.valueOf(numericCode); + } + /** * Gets the name that is suitable for displaying this currency for * the default {@link Locale.Category#DISPLAY DISPLAY} locale. @@ -289,4 +612,538 @@ public String toString() { private Object readResolve() { return getInstance(currencyCode); } + + // Android-removed: Use ICU. + // Removed a bunch of private helper methods that are unused on Android. + /** + * Gets the main table entry for the country whose country code consists + * of char1 and char2. + * + private static int getMainTableEntry(char char1, char char2) { + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { + throw new IllegalArgumentException(); + } + return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')]; + } + + /** + * Sets the main table entry for the country whose country code consists + * of char1 and char2. + * + private static void setMainTableEntry(char char1, char char2, int entry) { + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { + throw new IllegalArgumentException(); + } + mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry; + } + + /** + * Obtains a localized currency names from a CurrencyNameProvider + * implementation. + * + private static class CurrencyNameGetter + implements LocaleServiceProviderPool.LocalizedObjectGetter { + private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter(); + + @Override + public String getObject(CurrencyNameProvider currencyNameProvider, + Locale locale, + String key, + Object... params) { + assert params.length == 1; + int type = (Integer)params[0]; + + switch(type) { + case SYMBOL: + return currencyNameProvider.getSymbol(key, locale); + case DISPLAYNAME: + return currencyNameProvider.getDisplayName(key, locale); + default: + assert false; // shouldn't happen + } + + return null; + } + } + + private static int[] readIntArray(DataInputStream dis, int count) throws IOException { + int[] ret = new int[count]; + for (int i = 0; i < count; i++) { + ret[i] = dis.readInt(); + } + + return ret; + } + + private static List readSpecialCases(DataInputStream dis, + int count) + throws IOException { + + List list = new ArrayList<>(count); + long cutOverTime; + String oldCurrency; + String newCurrency; + int oldCurrencyFraction; + int newCurrencyFraction; + int oldCurrencyNumericCode; + int newCurrencyNumericCode; + + for (int i = 0; i < count; i++) { + cutOverTime = dis.readLong(); + oldCurrency = dis.readUTF(); + newCurrency = dis.readUTF(); + oldCurrencyFraction = dis.readInt(); + newCurrencyFraction = dis.readInt(); + oldCurrencyNumericCode = dis.readInt(); + newCurrencyNumericCode = dis.readInt(); + SpecialCaseEntry sc = new SpecialCaseEntry(cutOverTime, + oldCurrency, newCurrency, + oldCurrencyFraction, newCurrencyFraction, + oldCurrencyNumericCode, newCurrencyNumericCode); + list.add(sc); + } + return list; + } + + private static List readOtherCurrencies(DataInputStream dis, + int count) + throws IOException { + + List list = new ArrayList<>(count); + String currencyCode; + int fraction; + int numericCode; + + for (int i = 0; i < count; i++) { + currencyCode = dis.readUTF(); + fraction = dis.readInt(); + numericCode = dis.readInt(); + OtherCurrencyEntry oc = new OtherCurrencyEntry(currencyCode, + fraction, + numericCode); + list.add(oc); + } + return list; + } + + /** + * Parse currency data found in the properties file (that + * java.util.currency.data designates) to a List of CurrencyProperty + * instances. Also, remove invalid entries and the multiple currency + * code inconsistencies. + * + * @param props properties containing currency data + * @param pattern regex pattern for the properties entry + * @return list of parsed property entries + * + private static List getValidCurrencyData(Properties props, + Pattern pattern) { + + Set keys = props.stringPropertyNames(); + List propertyEntries = new ArrayList<>(); + + // remove all invalid entries and parse all valid currency properties + // entries to a group of CurrencyProperty, classified by currency code + Map> currencyCodeGroup = keys.stream() + .map(k -> CurrencyProperty + .getValidEntry(k.toUpperCase(Locale.ROOT), + props.getProperty(k).toUpperCase(Locale.ROOT), + pattern)).flatMap(o -> o.stream()) + .collect(Collectors.groupingBy(entry -> entry.currencyCode)); + + // check each group for inconsistencies + currencyCodeGroup.forEach((curCode, list) -> { + boolean inconsistent = CurrencyProperty + .containsInconsistentInstances(list); + if (inconsistent) { + list.forEach(prop -> CurrencyProperty.info("The property" + + " entry for " + prop.country + " is inconsistent." + + " Ignored.", null)); + } else { + propertyEntries.addAll(list); + } + }); + + return propertyEntries; + } + + /** + * Replaces currency data found in the properties file that + * java.util.currency.data designates. This method is invoked for + * each valid currency entry. + * + * @param prop CurrencyProperty instance of the valid property entry + * + private static void replaceCurrencyData(CurrencyProperty prop) { + + + String ctry = prop.country; + String code = prop.currencyCode; + int numeric = prop.numericCode; + int fraction = prop.fraction; + int entry = numeric << NUMERIC_CODE_SHIFT; + + int index = SpecialCaseEntry.indexOf(code, fraction, numeric); + + + // If a new entry changes the numeric code/dfd of an existing + // currency code, update it in the sc list at the respective + // index and also change it in the other currencies list and + // main table (if that currency code is also used as a + // simple case). + + // If all three components do not match with the new entry, + // but the currency code exists in the special case list + // update the sc entry with the new entry + int scCurrencyCodeIndex = -1; + if (index == -1) { + scCurrencyCodeIndex = SpecialCaseEntry.currencyCodeIndex(code); + if (scCurrencyCodeIndex != -1) { + //currency code exists in sc list, then update the old entry + specialCasesList.set(scCurrencyCodeIndex, + new SpecialCaseEntry(code, fraction, numeric)); + + // also update the entry in other currencies list + OtherCurrencyEntry oe = OtherCurrencyEntry.findEntry(code); + if (oe != null) { + int oIndex = otherCurrenciesList.indexOf(oe); + otherCurrenciesList.set(oIndex, new OtherCurrencyEntry( + code, fraction, numeric)); + } + } + } + + /* If a country switches from simple case to special case or + * one special case to other special case which is not present + * in the sc arrays then insert the new entry in special case arrays. + * If an entry with given currency code exists, update with the new + * entry. + * + if (index == -1 && (ctry.charAt(0) != code.charAt(0) + || ctry.charAt(1) != code.charAt(1))) { + + if(scCurrencyCodeIndex == -1) { + specialCasesList.add(new SpecialCaseEntry(code, fraction, + numeric)); + index = specialCasesList.size() - 1; + } else { + index = scCurrencyCodeIndex; + } + + // update the entry in main table if it exists as a simple case + updateMainTableEntry(code, fraction, numeric); + } + + if (index == -1) { + // simple case + entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) + | (code.charAt(2) - 'A'); + } else { + // special case + entry = SPECIAL_CASE_COUNTRY_MASK + | (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA); + } + setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry); + } + + // update the entry in maintable for any simple case found, if a new + // entry as a special case updates the entry in sc list with + // existing currency code + private static void updateMainTableEntry(String code, int fraction, + int numeric) { + // checking the existence of currency code in mainTable + int tableEntry = getMainTableEntry(code.charAt(0), code.charAt(1)); + int entry = numeric << NUMERIC_CODE_SHIFT; + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK + && tableEntry != INVALID_COUNTRY_ENTRY + && code.charAt(2) - 'A' == (tableEntry + & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) { + + int numericCode = (tableEntry & NUMERIC_CODE_MASK) + >> NUMERIC_CODE_SHIFT; + int defaultFractionDigits = (tableEntry + & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) + >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT; + if (numeric != numericCode || fraction != defaultFractionDigits) { + // update the entry in main table + entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) + | (code.charAt(2) - 'A'); + setMainTableEntry(code.charAt(0), code.charAt(1), entry); + } + } + } + + /* Used to represent a special case currency entry + * - cutOverTime: cut-over time in millis as returned by + * System.currentTimeMillis for special case countries that are changing + * currencies; Long.MAX_VALUE for countries that are not changing currencies + * - oldCurrency: old currencies for special case countries + * - newCurrency: new currencies for special case countries that are + * changing currencies; null for others + * - oldCurrencyFraction: default fraction digits for old currencies + * - newCurrencyFraction: default fraction digits for new currencies, 0 for + * countries that are not changing currencies + * - oldCurrencyNumericCode: numeric code for old currencies + * - newCurrencyNumericCode: numeric code for new currencies, 0 for countries + * that are not changing currencies + * + private static class SpecialCaseEntry { + + final private long cutOverTime; + final private String oldCurrency; + final private String newCurrency; + final private int oldCurrencyFraction; + final private int newCurrencyFraction; + final private int oldCurrencyNumericCode; + final private int newCurrencyNumericCode; + + private SpecialCaseEntry(long cutOverTime, String oldCurrency, String newCurrency, + int oldCurrencyFraction, int newCurrencyFraction, + int oldCurrencyNumericCode, int newCurrencyNumericCode) { + this.cutOverTime = cutOverTime; + this.oldCurrency = oldCurrency; + this.newCurrency = newCurrency; + this.oldCurrencyFraction = oldCurrencyFraction; + this.newCurrencyFraction = newCurrencyFraction; + this.oldCurrencyNumericCode = oldCurrencyNumericCode; + this.newCurrencyNumericCode = newCurrencyNumericCode; + } + + private SpecialCaseEntry(String currencyCode, int fraction, + int numericCode) { + this(Long.MAX_VALUE, currencyCode, "", fraction, 0, numericCode, 0); + } + + //get the index of the special case entry + private static int indexOf(String code, int fraction, int numeric) { + int size = specialCasesList.size(); + for (int index = 0; index < size; index++) { + SpecialCaseEntry scEntry = specialCasesList.get(index); + if (scEntry.oldCurrency.equals(code) + && scEntry.oldCurrencyFraction == fraction + && scEntry.oldCurrencyNumericCode == numeric + && scEntry.cutOverTime == Long.MAX_VALUE) { + return index; + } + } + return -1; + } + + // get the fraction and numericCode of the sc currencycode + private static int[] findEntry(String code) { + int[] fractionAndNumericCode = null; + int size = specialCasesList.size(); + for (int index = 0; index < size; index++) { + SpecialCaseEntry scEntry = specialCasesList.get(index); + if (scEntry.oldCurrency.equals(code) && (scEntry.cutOverTime == Long.MAX_VALUE + || System.currentTimeMillis() < scEntry.cutOverTime)) { + //consider only when there is no new currency or cutover time is not passed + fractionAndNumericCode = new int[2]; + fractionAndNumericCode[0] = scEntry.oldCurrencyFraction; + fractionAndNumericCode[1] = scEntry.oldCurrencyNumericCode; + break; + } else if (scEntry.newCurrency.equals(code) + && System.currentTimeMillis() >= scEntry.cutOverTime) { + //consider only if the cutover time is passed + fractionAndNumericCode = new int[2]; + fractionAndNumericCode[0] = scEntry.newCurrencyFraction; + fractionAndNumericCode[1] = scEntry.newCurrencyNumericCode; + break; + } + } + return fractionAndNumericCode; + } + + // get the index based on currency code + private static int currencyCodeIndex(String code) { + int size = specialCasesList.size(); + for (int index = 0; index < size; index++) { + SpecialCaseEntry scEntry = specialCasesList.get(index); + if (scEntry.oldCurrency.equals(code) && (scEntry.cutOverTime == Long.MAX_VALUE + || System.currentTimeMillis() < scEntry.cutOverTime)) { + //consider only when there is no new currency or cutover time is not passed + return index; + } else if (scEntry.newCurrency.equals(code) + && System.currentTimeMillis() >= scEntry.cutOverTime) { + //consider only if the cutover time is passed + return index; + } + } + return -1; + } + + + // convert the special case entry to sc arrays index + private static int toIndex(int tableEntry) { + return (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA; + } + + } + + /* Used to represent Other currencies + * - currencyCode: currency codes that are not the main currency + * of a simple country + * - otherCurrenciesDFD: decimal format digits for other currencies + * - otherCurrenciesNumericCode: numeric code for other currencies + * + private static class OtherCurrencyEntry { + + final private String currencyCode; + final private int fraction; + final private int numericCode; + + private OtherCurrencyEntry(String currencyCode, int fraction, + int numericCode) { + this.currencyCode = currencyCode; + this.fraction = fraction; + this.numericCode = numericCode; + } + + //get the instance of the other currency code + private static OtherCurrencyEntry findEntry(String code) { + int size = otherCurrenciesList.size(); + for (int index = 0; index < size; index++) { + OtherCurrencyEntry ocEntry = otherCurrenciesList.get(index); + if (ocEntry.currencyCode.equalsIgnoreCase(code)) { + return ocEntry; + } + } + return null; + } + + } + + + /* + * Used to represent an entry of the properties file that + * java.util.currency.data designates + * + * - country: country representing the currency entry + * - currencyCode: currency code + * - fraction: default fraction digit + * - numericCode: numeric code + * - date: cutover date + * + private static class CurrencyProperty { + final private String country; + final private String currencyCode; + final private int fraction; + final private int numericCode; + final private String date; + + private CurrencyProperty(String country, String currencyCode, + int fraction, int numericCode, String date) { + this.country = country; + this.currencyCode = currencyCode; + this.fraction = fraction; + this.numericCode = numericCode; + this.date = date; + } + + /** + * Check the valid currency data and create/return an Optional instance + * of CurrencyProperty + * + * @param ctry country representing the currency data + * @param curData currency data of the given {@code ctry} + * @param pattern regex pattern for the properties entry + * @return Optional containing CurrencyProperty instance, If valid; + * empty otherwise + * + private static Optional getValidEntry(String ctry, + String curData, + Pattern pattern) { + + CurrencyProperty prop = null; + + if (ctry.length() != 2) { + // Invalid country code. Ignore the entry. + } else { + + prop = parseProperty(ctry, curData, pattern); + // if the property entry failed any of the below checked + // criteria it is ignored + if (prop == null + || (prop.date == null && curData.chars() + .map(c -> c == ',' ? 1 : 0).sum() >= 3)) { + // format is not recognized. ignore the data if date + // string is null and we've 4 values, bad date value + prop = null; + } else if (prop.fraction + > SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS) { + prop = null; + } else { + try { + if (prop.date != null + && !isPastCutoverDate(prop.date)) { + prop = null; + } + } catch (ParseException ex) { + prop = null; + } + } + } + + if (prop == null) { + info("The property entry for " + ctry + " is invalid." + + " Ignored.", null); + } + + return Optional.ofNullable(prop); + } + + /* + * Parse properties entry and return CurrencyProperty instance + * + private static CurrencyProperty parseProperty(String ctry, + String curData, Pattern pattern) { + Matcher m = pattern.matcher(curData); + if (!m.find()) { + return null; + } else { + return new CurrencyProperty(ctry, m.group(1), + Integer.parseInt(m.group(3)), + Integer.parseInt(m.group(2)), m.group(4)); + } + } + + /** + * Checks if the given list contains multiple inconsistent currency instances + * + private static boolean containsInconsistentInstances( + List list) { + int numCode = list.get(0).numericCode; + int fractionDigit = list.get(0).fraction; + return list.stream().anyMatch(prop -> prop.numericCode != numCode + || prop.fraction != fractionDigit); + } + + private static boolean isPastCutoverDate(String s) + throws ParseException { + SimpleDateFormat format = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + format.setLenient(false); + long time = format.parse(s.trim()).getTime(); + return System.currentTimeMillis() > time; + + } + + private static void info(String message, Throwable t) { + PlatformLogger logger = PlatformLogger + .getLogger("java.util.Currency"); + if (logger.isLoggable(PlatformLogger.Level.INFO)) { + if (t != null) { + logger.info(message, t); + } else { + logger.info(message); + } + } + } + + } + */ } + + diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Dictionary.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Dictionary.java index 4c4574bd38..c9825b4cc6 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Dictionary.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Dictionary.java @@ -26,14 +26,14 @@ package java.util; /** - * The Dictionary class is the abstract parent of any - * class, such as Hashtable, which maps keys to values. - * Every key and every value is an object. In any one Dictionary + * The {@code Dictionary} class is the abstract parent of any + * class, such as {@code Hashtable}, which maps keys to values. + * Every key and every value is an object. In any one {@code Dictionary} * object, every key is associated with at most one value. Given a - * Dictionary and a key, the associated element can be looked up. - * Any non-null object can be used as a key and as a value. + * {@code Dictionary} and a key, the associated element can be looked up. + * Any non-{@code null} object can be used as a key and as a value. *

    - * As a rule, the equals method should be used by + * As a rule, the {@code equals} method should be used by * implementations of this class to decide if two keys are the same. *

    * NOTE: This class is obsolete. New implementations should @@ -44,7 +44,7 @@ * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.Object#hashCode() * @see java.util.Hashtable - * @since JDK1.0 + * @since 1.0 */ public abstract class Dictionary { @@ -60,21 +60,21 @@ public Dictionary() { * * @return the number of keys in this dictionary. */ - abstract public int size(); + public abstract int size(); /** * Tests if this dictionary maps no keys to value. The general contract - * for the isEmpty method is that the result is true if and only + * for the {@code isEmpty} method is that the result is true if and only * if this dictionary contains no entries. * - * @return true if this dictionary maps no keys to values; - * false otherwise. + * @return {@code true} if this dictionary maps no keys to values; + * {@code false} otherwise. */ - abstract public boolean isEmpty(); + public abstract boolean isEmpty(); /** * Returns an enumeration of the keys in this dictionary. The general - * contract for the keys method is that an Enumeration object + * contract for the keys method is that an {@code Enumeration} object * is returned that will generate all the keys for which this dictionary * contains entries. * @@ -82,74 +82,74 @@ public Dictionary() { * @see java.util.Dictionary#elements() * @see java.util.Enumeration */ - abstract public Enumeration keys(); + public abstract Enumeration keys(); /** * Returns an enumeration of the values in this dictionary. The general - * contract for the elements method is that an - * Enumeration is returned that will generate all the elements + * contract for the {@code elements} method is that an + * {@code Enumeration} is returned that will generate all the elements * contained in entries in this dictionary. * * @return an enumeration of the values in this dictionary. * @see java.util.Dictionary#keys() * @see java.util.Enumeration */ - abstract public Enumeration elements(); + public abstract Enumeration elements(); /** * Returns the value to which the key is mapped in this dictionary. - * The general contract for the isEmpty method is that if this + * The general contract for the {@code isEmpty} method is that if this * dictionary contains an entry for the specified key, the associated - * value is returned; otherwise, null is returned. + * value is returned; otherwise, {@code null} is returned. * * @return the value to which the key is mapped in this dictionary; * @param key a key in this dictionary. - * null if the key is not mapped to any value in + * {@code null} if the key is not mapped to any value in * this dictionary. - * @exception NullPointerException if the key is null. + * @exception NullPointerException if the {@code key} is {@code null}. * @see java.util.Dictionary#put(java.lang.Object, java.lang.Object) */ - abstract public V get(Object key); + public abstract V get(Object key); /** - * Maps the specified key to the specified - * value in this dictionary. Neither the key nor the - * value can be null. + * Maps the specified {@code key} to the specified + * {@code value} in this dictionary. Neither the key nor the + * value can be {@code null}. *

    * If this dictionary already contains an entry for the specified - * key, the value already in this dictionary for that - * key is returned, after modifying the entry to contain the + * {@code key}, the value already in this dictionary for that + * {@code key} is returned, after modifying the entry to contain the * new element.

    If this dictionary does not already have an entry - * for the specified key, an entry is created for the - * specified key and value, and null is + * for the specified {@code key}, an entry is created for the + * specified {@code key} and {@code value}, and {@code null} is * returned. *

    - * The value can be retrieved by calling the - * get method with a key that is equal to - * the original key. + * The {@code value} can be retrieved by calling the + * {@code get} method with a {@code key} that is equal to + * the original {@code key}. * * @param key the hashtable key. * @param value the value. - * @return the previous value to which the key was mapped - * in this dictionary, or null if the key did not + * @return the previous value to which the {@code key} was mapped + * in this dictionary, or {@code null} if the key did not * have a previous mapping. - * @exception NullPointerException if the key or - * value is null. + * @exception NullPointerException if the {@code key} or + * {@code value} is {@code null}. * @see java.lang.Object#equals(java.lang.Object) * @see java.util.Dictionary#get(java.lang.Object) */ - abstract public V put(K key, V value); + public abstract V put(K key, V value); /** - * Removes the key (and its corresponding - * value) from this dictionary. This method does nothing - * if the key is not in this dictionary. + * Removes the {@code key} (and its corresponding + * {@code value}) from this dictionary. This method does nothing + * if the {@code key} is not in this dictionary. * * @param key the key that needs to be removed. - * @return the value to which the key had been mapped in this - * dictionary, or null if the key did not have a + * @return the value to which the {@code key} had been mapped in this + * dictionary, or {@code null} if the key did not have a * mapping. - * @exception NullPointerException if key is null. + * @exception NullPointerException if {@code key} is {@code null}. */ - abstract public V remove(Object key); + public abstract V remove(Object key); } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DoubleSummaryStatistics.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DoubleSummaryStatistics.java index 599bd18218..192a5bcb98 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DoubleSummaryStatistics.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DoubleSummaryStatistics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -25,6 +25,8 @@ package java.util; import java.util.function.DoubleConsumer; +import java.util.stream.Collector; +import java.util.stream.DoubleStream; /** * A state object for collecting statistics such as count, min, max, sum, and @@ -53,7 +55,7 @@ * * @implNote This implementation is not thread safe. However, it is safe to use * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction) - * Collectors.toDoubleStatistics()} on a parallel stream, because the parallel + * Collectors.summarizingDouble()} on a parallel stream, because the parallel * implementation of {@link java.util.stream.Stream#collect Stream.collect()} * provides the necessary partitioning, isolation, and merging of results for * safe and efficient parallel execution. @@ -68,12 +70,65 @@ public class DoubleSummaryStatistics implements DoubleConsumer { private double max = Double.NEGATIVE_INFINITY; /** - * Construct an empty instance with zero count, zero sum, + * Constructs an empty instance with zero count, zero sum, * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY} * max and zero average. */ public DoubleSummaryStatistics() { } + /** + * Constructs a non-empty instance with the specified {@code count}, + * {@code min}, {@code max}, and {@code sum}. + * + *

    If {@code count} is zero then the remaining arguments are ignored and + * an empty instance is constructed. + * + *

    If the arguments are inconsistent then an {@code IllegalArgumentException} + * is thrown. The necessary consistent argument conditions are: + *

      + *
    • {@code count >= 0}
    • + *
    • {@code (min <= max && !isNaN(sum)) || (isNaN(min) && isNaN(max) && isNaN(sum))}
    • + *
    + * @apiNote + * The enforcement of argument correctness means that the retrieved set of + * recorded values obtained from a {@code DoubleSummaryStatistics} source + * instance may not be a legal set of arguments for this constructor due to + * arithmetic overflow of the source's recorded count of values. + * The consistent argument conditions are not sufficient to prevent the + * creation of an internally inconsistent instance. An example of such a + * state would be an instance with: {@code count} = 2, {@code min} = 1, + * {@code max} = 2, and {@code sum} = 0. + * + * @param count the count of values + * @param min the minimum value + * @param max the maximum value + * @param sum the sum of all values + * @throws IllegalArgumentException if the arguments are inconsistent + * @since 10 + */ + public DoubleSummaryStatistics(long count, double min, double max, double sum) + throws IllegalArgumentException { + if (count < 0L) { + throw new IllegalArgumentException("Negative count value"); + } else if (count > 0L) { + if (min > max) + throw new IllegalArgumentException("Minimum greater than maximum"); + + // All NaN or non NaN + var ncount = DoubleStream.of(min, max, sum).filter(Double::isNaN).count(); + if (ncount > 0 && ncount < 3) + throw new IllegalArgumentException("Some, not all, of the minimum, maximum, or sum is NaN"); + + this.count = count; + this.sum = sum; + this.simpleSum = sum; + this.sumCompensation = 0.0d; + this.min = min; + this.max = max; + } + // Use default field values if count == 0 + } + /** * Records another value into the summary information. * @@ -128,9 +183,6 @@ public final long getCount() { * Returns the sum of values recorded, or zero if no values have been * recorded. * - * If any recorded value is a NaN or the sum is at any point a NaN - * then the sum will be NaN. - * *

    The value of a floating-point sum is a function both of the * input values as well as the order of addition operations. The * order of addition operations of this method is intentionally @@ -142,6 +194,44 @@ public final long getCount() { * numerical sum compared to a simple summation of {@code double} * values. * + * Because of the unspecified order of operations and the + * possibility of using differing summation schemes, the output of + * this method may vary on the same input values. + * + *

    Various conditions can result in a non-finite sum being + * computed. This can occur even if the all the recorded values + * being summed are finite. If any recorded value is non-finite, + * the sum will be non-finite: + * + *

      + * + *
    • If any recorded value is a NaN, then the final sum will be + * NaN. + * + *
    • If the recorded values contain one or more infinities, the + * sum will be infinite or NaN. + * + *
        + * + *
      • If the recorded values contain infinities of opposite sign, + * the sum will be NaN. + * + *
      • If the recorded values contain infinities of one sign and + * an intermediate sum overflows to an infinity of the opposite + * sign, the sum may be NaN. + * + *
      + * + *
    + * + * It is possible for intermediate sums of finite values to + * overflow into opposite-signed infinities; if that occurs, the + * final sum will be NaN even if the recorded values are all + * finite. + * + * If all the recorded values are zero, the sign of zero is + * not guaranteed to be preserved in the final sum. + * * @apiNote Values sorted by increasing absolute magnitude tend to yield * more accurate results. * @@ -192,15 +282,9 @@ public final double getMax() { * Returns the arithmetic mean of values recorded, or zero if no * values have been recorded. * - * If any recorded value is a NaN or the sum is at any point a NaN - * then the average will be code NaN. - * - *

    The average returned can vary depending upon the order in - * which values are recorded. - * - * This method may be implemented using compensated summation or - * other technique to reduce the error bound in the {@link #getSum - * numerical sum} used to compute the average. + *

    The computed average can vary numerically and have the + * special case behavior as computing the sum; see {@link #getSum} + * for details. * * @apiNote Values sorted by increasing absolute magnitude tend to yield * more accurate results. @@ -212,8 +296,6 @@ public final double getAverage() { } /** - * {@inheritDoc} - * * Returns a non-empty string representation of this object suitable for * debugging. The exact presentation format is unspecified and may vary * between implementations and versions. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java index 0dcdf3762c..ec016a59e5 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java @@ -29,7 +29,7 @@ * Unchecked exception thrown when duplicate flags are provided in the format * specifier. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EmptyStackException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EmptyStackException.java index 1f1e878351..53dcacd574 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EmptyStackException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EmptyStackException.java @@ -26,19 +26,19 @@ package java.util; /** - * Thrown by methods in the Stack class to indicate + * Thrown by methods in the {@code Stack} class to indicate * that the stack is empty. * * @author Jonathan Payne * @see java.util.Stack - * @since JDK1.0 + * @since 1.0 */ public class EmptyStackException extends RuntimeException { private static final long serialVersionUID = 5084686378493302095L; /** - * Constructs a new EmptyStackException with null + * Constructs a new {@code EmptyStackException} with {@code null} * as its error message string. */ public EmptyStackException() { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumMap.java index 86d1a850ed..b3baf6189e 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumMap.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -28,7 +28,7 @@ import com.google.j2objc.annotations.WeakOuter; -import java.util.Map.Entry; +// import java.util.Map.Entry; /*-[ #include "JreRetainedWith.h" @@ -56,7 +56,7 @@ * presence of a null key or to remove one will, however, function properly. * Null values are permitted. - *

    Like most collection implementations EnumMap is not + *

    Like most collection implementations {@code EnumMap} is not * synchronized. If multiple threads access an enum map concurrently, and at * least one of the threads modifies the map, it should be synchronized * externally. This is typically accomplished by synchronizing on some @@ -75,7 +75,7 @@ * {@link HashMap} counterparts. * *

    This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -86,7 +86,7 @@ public class EnumMap, V> extends AbstractMap implements java.io.Serializable, Cloneable { /** - * The Class object for the enum type of all the keys of this map. + * The {@code Class} object for the enum type of all the keys of this map. * * @serial */ @@ -131,13 +131,11 @@ private V unmaskNull(Object value) { return (V)(value == NULL ? null : value); } - private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; - /** * Creates an empty enum map with the specified key type. * * @param keyType the class object of the key type for this enum map - * @throws NullPointerException if keyType is null + * @throws NullPointerException if {@code keyType} is null */ public EnumMap(Class keyType) { this.keyType = keyType; @@ -150,7 +148,7 @@ public EnumMap(Class keyType) { * map, initially containing the same mappings (if any). * * @param m the enum map from which to initialize this enum map - * @throws NullPointerException if m is null + * @throws NullPointerException if {@code m} is null */ public EnumMap(EnumMap m) { keyType = m.keyType; @@ -161,15 +159,15 @@ public EnumMap(EnumMap m) { /** * Creates an enum map initialized from the specified map. If the - * specified map is an EnumMap instance, this constructor behaves + * specified map is an {@code EnumMap} instance, this constructor behaves * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map * must contain at least one mapping (in order to determine the new * enum map's key type). * * @param m the map from which to initialize this enum map - * @throws IllegalArgumentException if m is not an - * EnumMap instance and contains no mappings - * @throws NullPointerException if m is null + * @throws IllegalArgumentException if {@code m} is not an + * {@code EnumMap} instance and contains no mappings + * @throws NullPointerException if {@code m} is null */ public EnumMap(Map m) { if (m instanceof EnumMap) { @@ -205,11 +203,11 @@ public int size() { } /** - * Returns true if this map maps one or more keys to the + * Returns {@code true} if this map maps one or more keys to the * specified value. * * @param value the value whose presence in this map is to be tested - * @return true if this map maps one or more keys to this value + * @return {@code true} if this map maps one or more keys to this value */ public boolean containsValue(Object value) { value = maskNull(value); @@ -222,11 +220,11 @@ public boolean containsValue(Object value) { } /** - * Returns true if this map contains a mapping for the specified + * Returns {@code true} if this map contains a mapping for the specified * key. * * @param key the key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified + * @return {@code true} if this map contains a mapping for the specified * key */ public boolean containsKey(Object key) { @@ -269,9 +267,9 @@ public V get(Object key) { * @param value the value to be associated with the specified key * * @return the previous value associated with specified key, or - * null if there was no mapping for key. (A null + * {@code null} if there was no mapping for key. (A {@code null} * return can also indicate that the map previously associated - * null with the specified key.) + * {@code null} with the specified key.) * @throws NullPointerException if the specified key is null */ public V put(K key, V value) { @@ -290,9 +288,9 @@ public V put(K key, V value) { * * @param key the key whose mapping is to be removed from the map * @return the previous value associated with specified key, or - * null if there was no entry for key. (A null + * {@code null} if there was no entry for key. (A {@code null} * return can also indicate that the map previously associated - * null with the specified key.) + * {@code null} with the specified key.) */ public V remove(Object key) { if (!isValidKey(key)) @@ -378,7 +376,7 @@ public void clear() { * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns a {@link Set} view of the keys contained in this map. @@ -398,7 +396,6 @@ public Set keySet() { return ks; } - @WeakOuter private class KeySet extends AbstractSet { public Iterator iterator() { return new KeyIterator(); @@ -668,12 +665,12 @@ private void checkIndexForEntryUse() { /** * Compares the specified object with this map for equality. Returns - * true if the given object is also a map and the two maps + * {@code true} if the given object is also a map and the two maps * represent the same mappings, as specified in the {@link * Map#equals(Object)} contract. * * @param o the object to be compared for equality with this map - * @return true if the specified object is equal to this map + * @return {@code true} if the specified object is equal to this map */ public boolean equals(Object o) { if (this == o) @@ -705,8 +702,11 @@ public boolean equals(Object o) { } private boolean equals(EnumMap em) { + if (em.size != size) + return false; + if (em.keyType != keyType) - return size == 0 && em.size == 0; + return size == 0; // Key types match, compare each value for (int i = 0; i < keyUniverse.length; i++) { @@ -740,7 +740,7 @@ private int entryHashCode(int index) { } /** - * Returns a shallow copy of this enum map. (The values themselves + * Returns a shallow copy of this enum map. The values themselves * are not cloned. * * @return a shallow copy of this enum map @@ -780,7 +780,7 @@ private static > K[] getKeyUniverse(Class keyType) { private static final long serialVersionUID = 458661240069192865L; /** - * Save the state of the EnumMap instance to a stream (i.e., + * Save the state of the {@code EnumMap} instance to a stream (i.e., * serialize it). * * @serialData The size of the enum map (the number of key-value @@ -809,7 +809,7 @@ private void writeObject(java.io.ObjectOutputStream s) } /** - * Reconstitute the EnumMap instance from a stream (i.e., + * Reconstitute the {@code EnumMap} instance from a stream (i.e., * deserialize it). */ @SuppressWarnings("unchecked") diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumSet.java index d4fcff82c0..ffed3a3213 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EnumSet.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -33,11 +33,11 @@ * are represented internally as bit vectors. This representation is * extremely compact and efficient. The space and time performance of this * class should be good enough to allow its use as a high-quality, typesafe - * alternative to traditional int-based "bit flags." Even bulk - * operations (such as containsAll and retainAll) should + * alternative to traditional {@code int}-based "bit flags." Even bulk + * operations (such as {@code containsAll} and {@code retainAll}) should * run very quickly if their argument is also an enum set. * - *

    The iterator returned by the iterator method traverses the + *

    The iterator returned by the {@code iterator} method traverses the * elements in their natural order (the order in which the enum * constants are declared). The returned iterator is weakly * consistent: it will never throw {@link ConcurrentModificationException} @@ -49,7 +49,7 @@ * presence of a null element or to remove one will, however, function * properly. * - *

    Like most collection implementations, EnumSet is not + *

    Like most collection implementations, {@code EnumSet} is not * synchronized. If multiple threads access an enum set concurrently, and at * least one of the threads modifies the set, it should be synchronized * externally. This is typically accomplished by synchronizing on some @@ -68,29 +68,34 @@ * constant time if their argument is also an enum set. * *

    This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch * @since 1.5 * @see EnumMap - * @serial exclude */ +@SuppressWarnings("serial") // No serialVersionUID declared public abstract class EnumSet> extends AbstractSet implements Cloneable, java.io.Serializable { + // The following must be present in order to preserve the same computed + // serialVersionUID value as JDK 8, and to prevent the appearance of + // the fields in the Serialized Form documentation. See JDK-8227368. + static Enum[] access$000() { return null; } + private static final java.io.ObjectStreamField[] serialPersistentFields + = new java.io.ObjectStreamField[0]; + /** * The class of all the elements of this set. */ final Class elementType; /** - * All of the values comprising T. (Cached for performance.) + * All of the values comprising E. (Cached for performance.) */ final Enum[] universe; - private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; - EnumSet(ClasselementType, Enum[] universe) { this.elementType = elementType; this.universe = universe; @@ -103,7 +108,7 @@ public abstract class EnumSet> extends AbstractSet * @param elementType the class object of the element type for this enum * set * @return An empty enum set of the specified type. - * @throws NullPointerException if elementType is null + * @throws NullPointerException if {@code elementType} is null */ public static > EnumSet noneOf(Class elementType) { Enum[] universe = getUniverse(elementType); @@ -124,7 +129,7 @@ public static > EnumSet noneOf(Class elementType) { * @param elementType the class object of the element type for this enum * set * @return An enum set containing all the elements in the specified type. - * @throws NullPointerException if elementType is null + * @throws NullPointerException if {@code elementType} is null */ public static > EnumSet allOf(Class elementType) { EnumSet result = noneOf(elementType); @@ -145,7 +150,7 @@ public static > EnumSet allOf(Class elementType) { * @param The class of the elements in the set * @param s the enum set from which to initialize this enum set * @return A copy of the specified enum set. - * @throws NullPointerException if s is null + * @throws NullPointerException if {@code s} is null */ public static > EnumSet copyOf(EnumSet s) { return s.clone(); @@ -153,7 +158,7 @@ public static > EnumSet copyOf(EnumSet s) { /** * Creates an enum set initialized from the specified collection. If - * the specified collection is an EnumSet instance, this static + * the specified collection is an {@code EnumSet} instance, this static * factory method behaves identically to {@link #copyOf(EnumSet)}. * Otherwise, the specified collection must contain at least one element * (in order to determine the new enum set's element type). @@ -161,9 +166,9 @@ public static > EnumSet copyOf(EnumSet s) { * @param The class of the elements in the collection * @param c the collection from which to initialize this enum set * @return An enum set initialized from the given collection. - * @throws IllegalArgumentException if c is not an - * EnumSet instance and contains no elements - * @throws NullPointerException if c is null + * @throws IllegalArgumentException if {@code c} is not an + * {@code EnumSet} instance and contains no elements + * @throws NullPointerException if {@code c} is null */ public static > EnumSet copyOf(Collection c) { if (c instanceof EnumSet) { @@ -193,7 +198,7 @@ public static > EnumSet copyOf(Collection c) { * @param The class of the elements in the enum set * @param s the enum set from whose complement to initialize this enum set * @return The complement of the specified set in this set - * @throws NullPointerException if s is null + * @throws NullPointerException if {@code s} is null */ public static > EnumSet complementOf(EnumSet s) { EnumSet result = copyOf(s); @@ -212,7 +217,7 @@ public static > EnumSet complementOf(EnumSet s) { * * @param The class of the specified element and of the set * @param e the element that this set is to contain initially - * @throws NullPointerException if e is null + * @throws NullPointerException if {@code e} is null * @return an enum set initially containing the specified element */ public static > EnumSet of(E e) { @@ -334,7 +339,7 @@ public static > EnumSet of(E e1, E e2, E e3, E e4, * @param first an element that the set is to contain initially * @param rest the remaining elements the set is to contain initially * @throws NullPointerException if any of the specified elements are null, - * or if rest is null + * or if {@code rest} is null * @return an enum set initially containing the specified elements */ @SafeVarargs @@ -407,6 +412,9 @@ final void typeCheck(E e) { * The result is uncloned, cached, and shared by all callers. */ private static > E[] getUniverse(Class elementType) { + // // Android-changed: Use getEnumConstantsShared directly instead of going + // // through SharedSecrets. + // return elementType.getEnumConstantsShared(); TODO // Android-changed: Use JavaLangAccess directly instead of going via // SharedSecrets. return java.lang.JavaLangAccess.getEnumConstantsShared(elementType); @@ -421,9 +429,12 @@ private static > E[] getUniverse(Class elementType) { * * @serial include */ - private static class SerializationProxy > + private static class SerializationProxy> implements java.io.Serializable { + + private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; + /** * The element type of this enum set. * @@ -443,10 +454,18 @@ private static class SerializationProxy > elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY); } - // instead of cast to E, we should perhaps use elementType.cast() - // to avoid injection of forged stream, but it will slow the implementation + /** + * Returns an {@code EnumSet} object with initial state + * held by this proxy. + * + * @return a {@code EnumSet} object with initial state + * held by this proxy + */ @SuppressWarnings("unchecked") private Object readResolve() { + // instead of cast to E, we should perhaps use elementType.cast() + // to avoid injection of forged stream, but it will slow the + // implementation EnumSet result = EnumSet.noneOf(elementType); for (Enum e : elements) result.add((E)e); @@ -456,13 +475,24 @@ private Object readResolve() { private static final long serialVersionUID = 362491234563181265L; } + /** + * Returns a + * + * SerializationProxy + * representing the state of this instance. + * + * @return a {@link SerializationProxy} + * representing the state of this instance + */ Object writeReplace() { return new SerializationProxy<>(this); } - // readObject method for the serialization proxy pattern - // See Effective Java, Second Ed., Item 78. - private void readObject(java.io.ObjectInputStream stream) + /** + * @param s the stream + * @throws java.io.InvalidObjectException always + */ + private void readObject(java.io.ObjectInputStream s) throws java.io.InvalidObjectException { throw new java.io.InvalidObjectException("Proxy required"); } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Enumeration.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Enumeration.java index 8aebb5c2a4..96aa3a9007 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Enumeration.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Enumeration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, 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 @@ -28,10 +28,10 @@ /** * An object that implements the Enumeration interface generates a * series of elements, one at a time. Successive calls to the - * nextElement method return successive elements of the + * {@code nextElement} method return successive elements of the * series. *

    - * For example, to print all elements of a Vector<E> v: + * For example, to print all elements of a {@code Vector} v: *

      *   for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
      *       System.out.println(e.nextElement());
    @@ -39,12 +39,15 @@ * Methods are provided to enumerate through the elements of a * vector, the keys of a hashtable, and the values in a hashtable. * Enumerations are also used to specify the input streams to a - * SequenceInputStream. - *

    - * NOTE: The functionality of this interface is duplicated by the Iterator - * interface. In addition, Iterator adds an optional remove operation, and - * has shorter method names. New implementations should consider using - * Iterator in preference to Enumeration. + * {@code SequenceInputStream}. + * + * @apiNote + * The functionality of this interface is duplicated by the {@link Iterator} + * interface. In addition, {@code Iterator} adds an optional remove operation, + * and has shorter method names. New implementations should consider using + * {@code Iterator} in preference to {@code Enumeration}. It is possible to + * adapt an {@code Enumeration} to an {@code Iterator} by using the + * {@link #asIterator} method. * * @see java.util.Iterator * @see java.io.SequenceInputStream @@ -56,15 +59,15 @@ * @see java.util.Vector#elements() * * @author Lee Boynton - * @since JDK1.0 + * @since 1.0 */ public interface Enumeration { /** * Tests if this enumeration contains more elements. * - * @return true if and only if this enumeration object + * @return {@code true} if and only if this enumeration object * contains at least one more element to provide; - * false otherwise. + * {@code false} otherwise. */ boolean hasMoreElements(); @@ -76,4 +79,49 @@ public interface Enumeration { * @exception NoSuchElementException if no more elements exist. */ E nextElement(); + + /** + * Returns an {@link Iterator} that traverses the remaining elements + * covered by this enumeration. Traversal is undefined if any methods + * are called on this enumeration after the call to {@code asIterator}. + * + * @apiNote + * This method is intended to help adapt code that produces + * {@code Enumeration} instances to code that consumes {@code Iterator} + * instances. For example, the {@link java.util.jar.JarFile#entries + * JarFile.entries()} method returns an {@code Enumeration}. + * This can be turned into an {@code Iterator}, and then the + * {@code forEachRemaining()} method can be used: + * + *

    {@code
    +     *     JarFile jarFile = ... ;
    +     *     jarFile.entries().asIterator().forEachRemaining(entry -> { ... });
    +     * }
    + * + * (Note that there is also a {@link java.util.jar.JarFile#stream + * JarFile.stream()} method that returns a {@code Stream} of entries, + * which may be more convenient in some cases.) + * + * @implSpec + * The default implementation returns an {@code Iterator} whose + * {@link Iterator#hasNext hasNext} method calls this Enumeration's + * {@code hasMoreElements} method, whose {@link Iterator#next next} + * method calls this Enumeration's {@code nextElement} method, and + * whose {@link Iterator#remove remove} method throws + * {@code UnsupportedOperationException}. + * + * @return an Iterator representing the remaining elements of this Enumeration + * + * @since 9 + */ + default Iterator asIterator() { + return new Iterator<>() { + @Override public boolean hasNext() { + return hasMoreElements(); + } + @Override public E next() { + return nextElement(); + } + }; + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventListener.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventListener.java index 1daf446c30..9e51158956 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventListener.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventListener.java @@ -27,7 +27,7 @@ /** * A tagging interface that all event listener interfaces must extend. - * @since JDK1.1 + * @since 1.1 */ public interface EventListener { } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventObject.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventObject.java index 3bccae191a..ff89754a18 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventObject.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/EventObject.java @@ -33,7 +33,7 @@ * that is logically deemed to be the object upon which the Event in question * initially occurred upon. * - * @since JDK1.1 + * @since 1.1 */ public class EventObject implements java.io.Serializable { @@ -43,13 +43,13 @@ public class EventObject implements java.io.Serializable { /** * The object on which the Event initially occurred. */ - protected transient Object source; + protected transient Object source; /** * Constructs a prototypical Event. * - * @param source The object on which the Event initially occurred. - * @exception IllegalArgumentException if source is null. + * @param source the object on which the Event initially occurred + * @throws IllegalArgumentException if source is null */ public EventObject(Object source) { if (source == null) @@ -61,7 +61,7 @@ public EventObject(Object source) { /** * The object on which the Event initially occurred. * - * @return The object on which the Event initially occurred. + * @return the object on which the Event initially occurred */ public Object getSource() { return source; @@ -70,7 +70,7 @@ public Object getSource() { /** * Returns a String representation of this EventObject. * - * @return A a String representation of this EventObject. + * @return a String representation of this EventObject */ public String toString() { return getClass().getName() + "[source=" + source + "]"; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java index 58f593ebc2..664cd39855 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java @@ -28,7 +28,7 @@ /** * Unchecked exception thrown when a conversion and flag are incompatible. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formattable.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formattable.java index f7e1e509d1..2caabaedfa 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formattable.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formattable.java @@ -28,22 +28,22 @@ import java.io.IOException; /** - * The Formattable interface must be implemented by any class that - * needs to perform custom formatting using the 's' conversion + * The {@code Formattable} interface must be implemented by any class that + * needs to perform custom formatting using the {@code 's'} conversion * specifier of {@link java.util.Formatter}. This interface allows basic * control for formatting arbitrary objects. * * For example, the following class prints out different representations of a * stock's name depending on the flags and length constraints: * - * {@code + *

     {@code
      *   import java.nio.CharBuffer;
      *   import java.util.Formatter;
      *   import java.util.Formattable;
      *   import java.util.Locale;
      *   import static java.util.FormattableFlags.*;
      *
    - *  ...
    + *   ...
      *
      *   public class StockName implements Formattable {
      *       private String symbol, companyName, frenchCompanyName;
    @@ -89,12 +89,12 @@
      *           return String.format("%s - %s", symbol, companyName);
      *       }
      *   }
    - * }
    + * }
    * *

    When used in conjunction with the {@link java.util.Formatter}, the above * class produces the following output for various format strings. * - * {@code + *

     {@code
      *   Formatter fmt = new Formatter();
      *   StockName sn = new StockName("HUGE", "Huge Fruit, Inc.",
      *                                "Fruit Titanesque, Inc.");
    @@ -104,13 +104,13 @@
      *   fmt.format("%-10.8s", sn);              //   -> "HUGE      "
      *   fmt.format("%.12s", sn);                //   -> "Huge Fruit,*"
      *   fmt.format(Locale.FRANCE, "%25s", sn);  //   -> "   Fruit Titanesque, Inc."
    - * }
    + * }
    * *

    Formattables are not necessarily safe for multithreaded access. Thread * safety is optional and may be enforced by classes that extend and implement * this interface. * - *

    Unless otherwise specified, passing a null argument to + *

    Unless otherwise specified, passing a {@code null} argument to * any method in this interface will cause a {@link * NullPointerException} to be thrown. * @@ -126,7 +126,7 @@ public interface Formattable { * {@link Formatter#out() formatter.out()} or {@link * Formatter#locale() formatter.locale()} to obtain the {@link * Appendable} or {@link Locale} used by this - * formatter respectively. + * {@code formatter} respectively. * * @param flags * The flags modify the output format. The value is interpreted as @@ -139,19 +139,19 @@ public interface Formattable { * @param width * The minimum number of characters to be written to the output. * If the length of the converted value is less than the - * width then the output will be padded by - * '  ' until the total number of characters + * {@code width} then the output will be padded by + * '  ' until the total number of characters * equals width. The padding is at the beginning by default. If * the {@link FormattableFlags#LEFT_JUSTIFY} flag is set then the - * padding will be at the end. If width is -1 + * padding will be at the end. If {@code width} is {@code -1} * then there is no minimum. * * @param precision * The maximum number of characters to be written to the output. * The precision is applied before the width, thus the output will - * be truncated to precision characters even if the - * width is greater than the precision. If - * precision is -1 then there is no explicit + * be truncated to {@code precision} characters even if the + * {@code width} is greater than the {@code precision}. If + * {@code precision} is {@code -1} then there is no explicit * limit on the number of characters. * * @throws IllegalFormatException diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormattableFlags.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormattableFlags.java index 11a10ddfc4..92c020f999 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormattableFlags.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormattableFlags.java @@ -26,7 +26,7 @@ package java.util; /** - * FomattableFlags are passed to the {@link Formattable#formatTo + * FormattableFlags are passed to the {@link Formattable#formatTo * Formattable.formatTo()} method and modify the output format for {@linkplain * Formattable Formattables}. Implementations of {@link Formattable} are * responsible for interpreting and validating any flags. @@ -39,12 +39,12 @@ public class FormattableFlags { private FormattableFlags() {} /** - * Left-justifies the output. Spaces ('\u0020') will be added + * Left-justifies the output. Spaces ('\u0020') will be added * at the end of the converted value as required to fill the minimum width * of the field. If this flag is not set then the output will be * right-justified. * - *

    This flag corresponds to '-' ('\u002d') in + *

    This flag corresponds to {@code '-'} ('\u002d') in * the format specifier. */ public static final int LEFT_JUSTIFY = 1<<0; // '-' @@ -52,23 +52,23 @@ private FormattableFlags() {} /** * Converts the output to upper case according to the rules of the * {@linkplain java.util.Locale locale} given during creation of the - * formatter argument of the {@link Formattable#formatTo + * {@code formatter} argument of the {@link Formattable#formatTo * formatTo()} method. The output should be equivalent the following * invocation of {@link String#toUpperCase(java.util.Locale)} * *

          *     out.toUpperCase() 
    * - *

    This flag corresponds to 'S' ('\u0053') in + *

    This flag corresponds to {@code 'S'} ('\u0053') in * the format specifier. */ public static final int UPPERCASE = 1<<1; // 'S' /** * Requires the output to use an alternate form. The definition of the - * form is specified by the Formattable. + * form is specified by the {@code Formattable}. * - *

    This flag corresponds to '#' ('\u0023') in + *

    This flag corresponds to {@code '#'} ('\u0023') in * the format specifier. */ public static final int ALTERNATE = 1<<2; // '#' diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formatter.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formatter.java index 2f1511ce3a..8b0a15d332 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formatter.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Formatter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -26,6 +26,12 @@ package java.util; +/* J2ObjC removed +import libcore.icu.DecimalFormatData; +import jdk.internal.math.DoubleConsts; +import jdk.internal.math.FormattedFloatingDecimal; +*/ + import java.io.BufferedWriter; import java.io.Closeable; import java.io.IOException; @@ -48,12 +54,22 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; +// TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset +// import java.time.DateTimeException; +// import java.time.Instant; +// import java.time.ZoneId; +// import java.time.ZoneOffset; +// import java.time.temporal.ChronoField; +// import java.time.temporal.TemporalAccessor; +// import java.time.temporal.TemporalQueries; +// import java.time.temporal.UnsupportedTemporalTypeException; import libcore.icu.LocaleData; import sun.misc.FpUtils; import sun.misc.DoubleConsts; import sun.misc.FormattedFloatingDecimal; +// Android-changed: Use localized exponent separator for %e. /** * An interpreter for printf-style format strings. This class provides support * for layout justification and alignment, common formats for numeric, string, @@ -128,7 +144,7 @@ * // -> s == "Duke's Birthday: May 23, 1995" *

    * - *

    Organization

    + *

    Organization

    * *

    This specification is divided into two sections. The first section, Summary, covers the basic formatting concepts. This @@ -138,13 +154,13 @@ * details. It is intended for users who want more precise specification of * formatting behavior. * - *

    Summary

    + *

    Summary

    * *

    This section is intended to provide a brief overview of formatting * concepts. For precise behavioral details, refer to the Details section. * - *

    Format String Syntax

    + *

    Format String Syntax

    * *

    Every method which produces formatted output requires a format * string and an argument list. The format string is a {@link @@ -259,107 +275,112 @@ * {@link Date} and {@link TemporalAccessor TemporalAccessor} * *

  • Percent - produces a literal {@code '%'} - * ('\u0025') + * ('\u0025') * *
  • Line Separator - produces the platform-specific line separator * * * + *

    For category General, Character, Numberic, + * Integral and Date/Time conversion, unless otherwise specified, + * if the argument arg is {@code null}, then the result is "{@code null}". + * *

    The following table summarizes the supported conversions. Conversions * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'}, * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'}, * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding * lower-case conversion characters except that the result is converted to * upper case according to the rules of the prevailing {@link java.util.Locale - * Locale}. The result is equivalent to the following invocation of {@link - * String#toUpperCase()} - * - *

    - *    out.toUpperCase() 
    - * - * - * - *
    Conversion - * Argument Category - * Description - * - *
    {@code 'b'}, {@code 'B'} - * general + * Locale}. If there is no explicit locale specified, either at the + * construction of the instance or as a parameter to its method + * invocation, then the {@link java.util.Locale.Category#FORMAT default locale} + * is used. + * + * + * + * + * + * + * + * *
    genConv
    Conversion + * Argument Category + * Description + *
    {@code 'b'}, {@code 'B'} + * general * If the argument arg is {@code null}, then the result is * "{@code false}". If arg is a {@code boolean} or {@link * Boolean}, then the result is the string returned by {@link * String#valueOf(boolean) String.valueOf(arg)}. Otherwise, the result is * "true". * - *
    {@code 'h'}, {@code 'H'} - * general - * If the argument arg is {@code null}, then the result is - * "{@code null}". Otherwise, the result is obtained by invoking + *
    {@code 'h'}, {@code 'H'} + * general + * The result is obtained by invoking * {@code Integer.toHexString(arg.hashCode())}. * - *
    {@code 's'}, {@code 'S'} - * general - * If the argument arg is {@code null}, then the result is - * "{@code null}". If arg implements {@link Formattable}, then + *
    {@code 's'}, {@code 'S'} + * general + * If arg implements {@link Formattable}, then * {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the * result is obtained by invoking {@code arg.toString()}. * - *
    {@code 'c'}, {@code 'C'} - * character + *
    {@code 'c'}, {@code 'C'} + * character * The result is a Unicode character * - *
    {@code 'd'} - * integral + *
    {@code 'd'} + * integral * The result is formatted as a decimal integer * - *
    {@code 'o'} - * integral + *
    {@code 'o'} + * integral * The result is formatted as an octal integer * - *
    {@code 'x'}, {@code 'X'} - * integral + *
    {@code 'x'}, {@code 'X'} + * integral * The result is formatted as a hexadecimal integer * - *
    {@code 'e'}, {@code 'E'} - * floating point + *
    {@code 'e'}, {@code 'E'} + * floating point * The result is formatted as a decimal number in computerized * scientific notation * - *
    {@code 'f'} - * floating point + *
    {@code 'f'} + * floating point * The result is formatted as a decimal number * - *
    {@code 'g'}, {@code 'G'} - * floating point + *
    {@code 'g'}, {@code 'G'} + * floating point * The result is formatted using computerized scientific notation or * decimal format, depending on the precision and the value after rounding. * - *
    {@code 'a'}, {@code 'A'} - * floating point + *
    {@code 'a'}, {@code 'A'} + * floating point * The result is formatted as a hexadecimal floating-point number with * a significand and an exponent. This conversion is not supported * for the {@code BigDecimal} type despite the latter's being in the * floating point argument category. * - *
    {@code 't'}, {@code 'T'} - * date/time + *
    {@code 't'}, {@code 'T'} + * date/time * Prefix for date and time conversion characters. See Date/Time Conversions. * - *
    {@code '%'} - * percent - * The result is a literal {@code '%'} ('\u0025') + *
    {@code '%'} + * percent + * The result is a literal {@code '%'} ('\u0025') * - *
    {@code 'n'} - * line separator + *
    {@code 'n'} + * line separator * The result is the platform-specific line separator * + *
    * *

    Any characters not explicitly defined as conversions are illegal and are * reserved for future extensions. * - *

    Date/Time Conversions

    + *

    Date/Time Conversions

    * *

    The following date and time conversion suffix characters are defined for * the {@code 't'} and {@code 'T'} conversions. The types are similar to but @@ -370,46 +391,47 @@ * *

    The following conversion characters are used for formatting times: * - * - * - *
    {@code 'H'} + * + * + * + * *
    time
    {@code 'H'} * Hour of the day for the 24-hour clock, formatted as two digits with * a leading zero as necessary i.e. {@code 00 - 23}. * - *
    {@code 'I'} + *
    {@code 'I'} * Hour for the 12-hour clock, formatted as two digits with a leading * zero as necessary, i.e. {@code 01 - 12}. * - *
    {@code 'k'} + *
    {@code 'k'} * Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}. * - *
    {@code 'l'} + *
    {@code 'l'} * Hour for the 12-hour clock, i.e. {@code 1 - 12}. * - *
    {@code 'M'} + *
    {@code 'M'} * Minute within the hour formatted as two digits with a leading zero * as necessary, i.e. {@code 00 - 59}. * - *
    {@code 'S'} + *
    {@code 'S'} * Seconds within the minute, formatted as two digits with a leading * zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special * value required to support leap seconds). * - *
    {@code 'L'} + *
    {@code 'L'} * Millisecond within the second formatted as three digits with * leading zeros as necessary, i.e. {@code 000 - 999}. * - *
    {@code 'N'} + *
    {@code 'N'} * Nanosecond within the second, formatted as nine digits with leading * zeros as necessary, i.e. {@code 000000000 - 999999999}. * - *
    {@code 'p'} + *
    {@code 'p'} * Locale-specific {@linkplain * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker * in lower case, e.g."{@code am}" or "{@code pm}". Use of the conversion * prefix {@code 'T'} forces this output to upper case. * - *
    {@code 'z'} + *
    {@code 'z'} * RFC 822 * style numeric time zone offset from GMT, e.g. {@code -0800}. This * value will be adjusted as necessary for Daylight Saving Time. For @@ -417,7 +439,7 @@ * the {@linkplain TimeZone#getDefault() default time zone} for this * instance of the Java virtual machine. * - *
    {@code 'Z'} + *
    {@code 'Z'} * A string representing the abbreviation for the time zone. This * value will be adjusted as necessary for Daylight Saving Time. For * {@code long}, {@link Long}, and {@link Date} the time zone used is @@ -425,101 +447,108 @@ * instance of the Java virtual machine. The Formatter's locale will * supersede the locale of the argument (if any). * - *
    {@code 's'} + *
    {@code 's'} * Seconds since the beginning of the epoch starting at 1 January 1970 * {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to * {@code Long.MAX_VALUE/1000}. * - *
    {@code 'Q'} + *
    {@code 'Q'} * Milliseconds since the beginning of the epoch starting at 1 January * 1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to * {@code Long.MAX_VALUE}. * + *
    * *

    The following conversion characters are used for formatting dates: * - * + *
    + * + * * - * *
    date
    {@code 'B'} + *
    {@code 'B'} * Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths * full month name}, e.g. {@code "January"}, {@code "February"}. * - *
    {@code 'b'} + *
    {@code 'b'} * Locale-specific {@linkplain * java.text.DateFormatSymbols#getShortMonths abbreviated month name}, * e.g. {@code "Jan"}, {@code "Feb"}. * - *
    {@code 'h'} + *
    {@code 'h'} * Same as {@code 'b'}. * - *
    {@code 'A'} + *
    {@code 'A'} * Locale-specific full name of the {@linkplain * java.text.DateFormatSymbols#getWeekdays day of the week}, * e.g. {@code "Sunday"}, {@code "Monday"} * - *
    {@code 'a'} + *
    {@code 'a'} * Locale-specific short name of the {@linkplain * java.text.DateFormatSymbols#getShortWeekdays day of the week}, * e.g. {@code "Sun"}, {@code "Mon"} * - *
    {@code 'C'} + *
    {@code 'C'} * Four-digit year divided by {@code 100}, formatted as two digits * with leading zero as necessary, i.e. {@code 00 - 99} * - *
    {@code 'Y'} + *
    {@code 'Y'} * Year, formatted as at least four digits with leading zeros as * necessary, e.g. {@code 0092} equals {@code 92} CE for the Gregorian * calendar. * - *
    {@code 'y'} + *
    {@code 'y'} * Last two digits of the year, formatted with leading zeros as * necessary, i.e. {@code 00 - 99}. * - *
    {@code 'j'} + *
    {@code 'j'} * Day of year, formatted as three digits with leading zeros as * necessary, e.g. {@code 001 - 366} for the Gregorian calendar. * - *
    {@code 'm'} + *
    {@code 'm'} * Month, formatted as two digits with leading zeros as necessary, * i.e. {@code 01 - 13}. * - *
    {@code 'd'} + *
    {@code 'd'} * Day of month, formatted as two digits with leading zeros as * necessary, i.e. {@code 01 - 31} * - *
    {@code 'e'} + *
    {@code 'e'} * Day of month, formatted as two digits, i.e. {@code 1 - 31}. * + *
    * *

    The following conversion characters are used for formatting common * date/time compositions. * - * + *
    + * + * * - * *
    composites
    {@code 'R'} + *
    {@code 'R'} * Time formatted for the 24-hour clock as {@code "%tH:%tM"} * - *
    {@code 'T'} + *
    {@code 'T'} * Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}. * - *
    {@code 'r'} + *
    {@code 'r'} * Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS %Tp"}. * The location of the morning or afternoon marker ({@code '%Tp'}) may be * locale-dependent. * - *
    {@code 'D'} + *
    {@code 'D'} * Date formatted as {@code "%tm/%td/%ty"}. * - *
    {@code 'F'} + *
    {@code 'F'} * ISO 8601 * complete date formatted as {@code "%tY-%tm-%td"}. * - *
    {@code 'c'} + *
    {@code 'c'} * Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"}, * e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}. * + *
    * *

    Any characters not explicitly defined as date/time conversion suffixes @@ -530,64 +559,67 @@ *

    The following table summarizes the supported flags. y means the * flag is supported for the indicated argument types. * - * - * - *
    Flag General - * Character Integral - * Floating Point - * Date/Time - * Description - * - *
    '-' y - * y - * y - * y - * y + * + * + * + * + * + * *
    genConv
    Flag General + * Character Integral + * Floating Point + * Date/Time + * Description + *
    '-' y + * y + * y + * y + * y * The result will be left-justified. * - *
    '#' y1 - * - - * y3 - * y - * - + *
    '#' y1 + * - + * y3 + * y + * - * The result should use a conversion-dependent alternate form * - *
    '+' - - * - - * y4 - * y - * - + *
    '+' - + * - + * y4 + * y + * - * The result will always include a sign * - *
    '  ' - - * - - * y4 - * y - * - + *
    '  ' - + * - + * y4 + * y + * - * The result will include a leading space for positive values * - *
    '0' - - * - - * y - * y - * - + *
    '0' - + * - + * y + * y + * - * The result will be zero-padded * - *
    ',' - - * - - * y2 - * y5 - * - + *
    ',' - + * - + * y2 + * y5 + * - * The result will include locale-specific {@linkplain * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators} * - *
    '(' - - * - - * y4 - * y5 - * - + *
    '(' - + * - + * y4 + * y5 + * - * The result will enclose negative numbers in parentheses * + *
    * *

    1 Depends on the definition of {@link Formattable}. @@ -636,7 +668,7 @@ * "{@code 1$}", the second by "{@code 2$}", etc. * *

    Another way to reference arguments by position is to use the - * {@code '<'} ('\u003c') flag, which causes the argument for + * {@code '<'} ('\u003c') flag, which causes the argument for * the previous format specifier to be re-used. For example, the following two * statements would produce identical strings: * @@ -648,7 +680,7 @@ * * *


    - *

    Details

    + *

    Details

    * *

    This section is intended to provide behavioral details for formatting, * including conditions and exceptions, supported data types, localization, and @@ -675,25 +707,30 @@ * methods such as {@link String#format(String,Object...) String.format} and * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}. * + *

    For category General, Character, Numberic, + * Integral and Date/Time conversion, unless otherwise specified, + * if the argument arg is {@code null}, then the result is "{@code null}". + * *

    Conversions denoted by an upper-case character (i.e. {@code 'B'}, * {@code 'H'}, {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, * {@code 'G'}, {@code 'A'}, and {@code 'T'}) are the same as those for the * corresponding lower-case conversion characters except that the result is * converted to upper case according to the rules of the prevailing {@link - * java.util.Locale Locale}. The result is equivalent to the following - * invocation of {@link String#toUpperCase()} + * java.util.Locale Locale}. If there is no explicit locale specified, + * either at the construction of the instance or as a parameter to its method + * invocation, then the {@link java.util.Locale.Category#FORMAT default locale} + * is used. * - *

    - *    out.toUpperCase() 
    - * - *

    General

    + *

    General

    * *

    The following general conversions may be applied to any argument type: * - * + *
    + * + * * - * *
    dgConv
    {@code 'b'} - * '\u0062' + *
    {@code 'b'} + * '\u0062' * Produces either "{@code true}" or "{@code false}" as returned by * {@link Boolean#toString(boolean)}. * @@ -706,31 +743,29 @@ *

    If the {@code '#'} flag is given, then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'B'} - * '\u0042' + *
    {@code 'B'} + * '\u0042' * The upper-case variant of {@code 'b'}. * - *
    {@code 'h'} - * '\u0068' + *
    {@code 'h'} + * '\u0068' * Produces a string representing the hash code value of the object. * - *

    If the argument, arg is {@code null}, then the - * result is "{@code null}". Otherwise, the result is obtained - * by invoking {@code Integer.toHexString(arg.hashCode())}. + *

    The result is obtained by invoking + * {@code Integer.toHexString(arg.hashCode())}. * *

    If the {@code '#'} flag is given, then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'H'} - * '\u0048' + *
    {@code 'H'} + * '\u0048' * The upper-case variant of {@code 'h'}. * - *
    {@code 's'} - * '\u0073' + *
    {@code 's'} + * '\u0073' * Produces a string. * - *

    If the argument is {@code null}, then the result is - * "{@code null}". If the argument implements {@link Formattable}, then + *

    If the argument implements {@link Formattable}, then * its {@link Formattable#formatTo formatTo} method is invoked. * Otherwise, the result is obtained by invoking the argument's * {@code toString()} method. @@ -739,35 +774,39 @@ * Formattable} , then a {@link FormatFlagsConversionMismatchException} * will be thrown. * - *

    {@code 'S'} - * '\u0053' + *
    {@code 'S'} + * '\u0053' * The upper-case variant of {@code 's'}. * + *
    * - *

    The following flags apply to general conversions: + *

    The following flags apply to general conversions: * - * + *
    + * + * * - * *
    dFlags
    {@code '-'} - * '\u002d' - * Left justifies the output. Spaces ('\u0020') will be + *
    {@code '-'} + * '\u002d' + * Left justifies the output. Spaces ('\u0020') will be * added at the end of the converted value as required to fill the minimum * width of the field. If the width is not provided, then a {@link * MissingFormatWidthException} will be thrown. If this flag is not given * then the output will be right-justified. * - *
    {@code '#'} - * '\u0023' + *
    {@code '#'} + * '\u0023' * Requires the output use an alternate form. The definition of the * form is specified by the conversion. * + *
    * - *

    The width is the minimum number of characters to + *

    The width is the minimum number of characters to * be written to the * output. If the length of the converted value is less than the width then - * the output will be padded by '  ' ('\u0020') + * the output will be padded by '  ' ('\u0020') * until the total number of characters equals the width. The padding is on * the left by default. If the {@code '-'} flag is given, then the padding * will be on the right. If the width is not specified then there is no @@ -779,7 +818,7 @@ * the precision. If the precision is not specified then there is no explicit * limit on the number of characters. * - *

    Character

    + *

    Character

    * * This conversion may be applied to {@code char} and {@link Character}. It * may also be applied to the types {@code byte}, {@link Byte}, @@ -788,10 +827,12 @@ * {@code false} then an {@link IllegalFormatCodePointException} will be * thrown. * - * + *
    + * + * * - * *
    charConv
    {@code 'c'} - * '\u0063' + *
    {@code 'c'} + * '\u0063' * Formats the argument as a Unicode character as described in Unicode Character * Representation. This may be more than one 16-bit {@code char} in @@ -800,10 +841,11 @@ *

    If the {@code '#'} flag is given, then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'C'} - * '\u0043' + *
    {@code 'C'} + * '\u0043' * The upper-case variant of {@code 'c'}. * + *
    * *

    The {@code '-'} flag defined for General @@ -815,7 +857,7 @@ *

    The precision is not applicable. If the precision is specified then an * {@link IllegalFormatPrecisionException} will be thrown. * - *

    Numeric

    + *

    Numeric

    * *

    Numeric conversions are divided into the following categories: * @@ -833,7 +875,7 @@ * *

    Numeric types will be formatted according to the following algorithm: * - *

    Number Localization Algorithm + *

    Number Localization Algorithm * *

    After digits are obtained for the integer part, fractional part, and * exponent (as appropriate for the data type), the following transformation @@ -851,8 +893,8 @@ * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is * substituted. * - *

  • If the {@code ','} ('\u002c') - * flag is given, then the locale-specific {@linkplain + *
  • If the {@code ','} ('\u002c') + * flag is given, then the locale-specific {@linkplain * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is * inserted by scanning the integer part of the string from least significant * to most significant digits and inserting a separator at intervals defined by @@ -865,15 +907,15 @@ * the length of the string is equal to the requested field width. * *
  • If the value is negative and the {@code '('} flag is given, then a - * {@code '('} ('\u0028') is prepended and a {@code ')'} - * ('\u0029') is appended. + * {@code '('} ('\u0028') is prepended and a {@code ')'} + * ('\u0029') is appended. * *
  • If the value is negative (or floating-point negative zero) and - * {@code '('} flag is not given, then a {@code '-'} ('\u002d') + * {@code '('} flag is not given, then a {@code '-'} ('\u002d') * is prepended. * *
  • If the {@code '+'} flag is given and the value is positive or zero (or - * floating-point positive zero), then a {@code '+'} ('\u002b') + * floating-point positive zero), then a {@code '+'} ('\u002b') * will be prepended. * * @@ -883,16 +925,18 @@ * then the output will be "(Infinity)" if the {@code '('} flag is given * otherwise the output will be "-Infinity". These values are not localized. * - *

    Byte, Short, Integer, and Long + *

    Byte, Short, Integer, and Long * *

    The following conversions may be applied to {@code byte}, {@link Byte}, * {@code short}, {@link Short}, {@code int} and {@link Integer}, * {@code long}, and {@link Long}. * - * + *
    + * + * * - * *
    IntConv
    {@code 'd'} - * '\u0064' + *
    {@code 'd'} + * '\u0064' * Formats the argument as a decimal integer. The localization algorithm is applied. * @@ -902,8 +946,8 @@ *

    If the {@code '#'} flag is given then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'o'} - * '\u006f' + *
    {@code 'o'} + * '\u006f' * Formats the argument as an integer in base eight. No localization * is applied. * @@ -924,8 +968,8 @@ * are given then a {@link FormatFlagsConversionMismatchException} will be * thrown. * - *
    {@code 'x'} - * '\u0078' + *
    {@code 'x'} + * '\u0078' * Formats the argument as an integer in base sixteen. No * localization is applied. * @@ -943,18 +987,19 @@ * the field width with leading zeros after the radix indicator or sign (if * present). * - *

    If {@code '('}, '  ', {@code '+'}, or + *

    If {@code '('}, '  ', {@code '+'}, or * {@code ','} flags are given then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'X'} - * '\u0058' + *
    {@code 'X'} + * '\u0058' * The upper-case variant of {@code 'x'}. The entire string * representing the number will be converted to {@linkplain * String#toUpperCase upper case} including the {@code 'x'} (if any) and * all hexadecimal digits {@code 'a'} - {@code 'f'} - * ('\u0061' - '\u0066'). + * ('\u0061' - '\u0066'). * + *
    * *

    If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and @@ -966,30 +1011,32 @@ *

    If the {@code '-'} flag is not given, then the space padding will occur * before the sign. * - *

    The following flags apply to numeric integral + *

    The following flags apply to numeric integral * conversions: * - * + *
    + * + * * - * *
    intFlags
    {@code '+'} - * '\u002b' + *
    {@code '+'} + * '\u002b' * Requires the output to include a positive sign for all positive * numbers. If this flag is not given then only negative values will * include a sign. * - *

    If both the {@code '+'} and '  ' flags are given + *

    If both the {@code '+'} and '  ' flags are given * then an {@link IllegalFormatFlagsException} will be thrown. * - *

    '  ' - * '\u0020' + *
    '  ' + * '\u0020' * Requires the output to include a single extra space - * ('\u0020') for non-negative values. + * ('\u0020') for non-negative values. * - *

    If both the {@code '+'} and '  ' flags are given + *

    If both the {@code '+'} and '  ' flags are given * then an {@link IllegalFormatFlagsException} will be thrown. * - *

    {@code '0'} - * '\u0030' + *
    {@code '0'} + * '\u0030' * Requires the output to be padded with leading {@linkplain * java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field * width following any sign or radix indicator except when converting NaN @@ -999,29 +1046,30 @@ *

    If both the {@code '-'} and {@code '0'} flags are given then an * {@link IllegalFormatFlagsException} will be thrown. * - *

    {@code ','} - * '\u002c' + *
    {@code ','} + * '\u002c' * Requires the output to include the locale-specific {@linkplain * java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as * described in the "group" section of the * localization algorithm. * - *
    {@code '('} - * '\u0028' + *
    {@code '('} + * '\u0028' * Requires the output to prepend a {@code '('} - * ('\u0028') and append a {@code ')'} - * ('\u0029') to negative values. + * ('\u0028') and append a {@code ')'} + * ('\u0029') to negative values. * + *
    * - *

    If no flags are given the default formatting is + *

    If no flags are given the default formatting is * as follows: * *

      * *
    • The output is right-justified within the {@code width} * - *
    • Negative numbers begin with a {@code '-'} ('\u002d') + *
    • Negative numbers begin with a {@code '-'} ('\u002d') * *
    • Positive numbers and zero do not include a sign or extra leading * space @@ -1030,11 +1078,11 @@ * *
    * - *

    The width is the minimum number of characters to + *

    The width is the minimum number of characters to * be written to the output. This includes any signs, digits, grouping * separators, radix indicator, and parentheses. If the length of the * converted value is less than the width then the output will be padded by - * spaces ('\u0020') until the total number of characters equals + * spaces ('\u0020') until the total number of characters equals * width. The padding is on the left by default. If {@code '-'} flag is * given then the padding will be on the right. If width is not specified then * there is no minimum. @@ -1042,34 +1090,36 @@ *

    The precision is not applicable. If precision is specified then an * {@link IllegalFormatPrecisionException} will be thrown. * - *

    BigInteger + *

    BigInteger * *

    The following conversions may be applied to {@link * java.math.BigInteger}. * - * + *
    + * + * * - * *
    bIntConv
    {@code 'd'} - * '\u0064' + *
    {@code 'd'} + * '\u0064' * Requires the output to be formatted as a decimal integer. The localization algorithm is applied. * *

    If the {@code '#'} flag is given {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'o'} - * '\u006f' + *
    {@code 'o'} + * '\u006f' * Requires the output to be formatted as an integer in base eight. * No localization is applied. * *

    If x is negative then the result will be a signed value - * beginning with {@code '-'} ('\u002d'). Signed output is + * beginning with {@code '-'} ('\u002d'). Signed output is * allowed for this type because unlike the primitive types it is not * possible to create an unsigned equivalent without assuming an explicit * data-type size. * *

    If x is positive or zero and the {@code '+'} flag is given - * then the result will begin with {@code '+'} ('\u002b'). + * then the result will begin with {@code '+'} ('\u002b'). * *

    If the {@code '#'} flag is given then the output will always begin * with {@code '0'} prefix. @@ -1080,19 +1130,19 @@ *

    If the {@code ','} flag is given then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'x'} - * '\u0078' + *
    {@code 'x'} + * '\u0078' * Requires the output to be formatted as an integer in base * sixteen. No localization is applied. * *

    If x is negative then the result will be a signed value - * beginning with {@code '-'} ('\u002d'). Signed output is + * beginning with {@code '-'} ('\u002d'). Signed output is * allowed for this type because unlike the primitive types it is not * possible to create an unsigned equivalent without assuming an explicit * data-type size. * *

    If x is positive or zero and the {@code '+'} flag is given - * then the result will begin with {@code '+'} ('\u002b'). + * then the result will begin with {@code '+'} ('\u002b'). * *

    If the {@code '#'} flag is given then the output will always begin * with the radix indicator {@code "0x"}. @@ -1104,14 +1154,15 @@ *

    If the {@code ','} flag is given then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'X'} - * '\u0058' + *
    {@code 'X'} + * '\u0058' * The upper-case variant of {@code 'x'}. The entire string * representing the number will be converted to {@linkplain * String#toUpperCase upper case} including the {@code 'x'} (if any) and * all hexadecimal digits {@code 'a'} - {@code 'f'} - * ('\u0061' - '\u0066'). + * ('\u0061' - '\u0066'). * + *
    * *

    If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and @@ -1136,17 +1187,19 @@ *

    The precision is not applicable. If precision is specified then an * {@link IllegalFormatPrecisionException} will be thrown. * - *

    Float and Double + *

    Float and Double * *

    The following conversions may be applied to {@code float}, {@link * Float}, {@code double} and {@link Double}. * - * + *
    + * + * * - * *
    floatConv
    {@code 'e'} - * '\u0065' + *
    {@code 'e'} + * '\u0065' * Requires the output to be formatted using computerized scientific notation. The computerized scientific notation. The localization algorithm is applied. * *

    The formatting of the magnitude m depends upon its value. @@ -1183,7 +1236,7 @@ * than the number of digits which would appear after the decimal point in * the string returned by {@link Float#toString(float)} or {@link * Double#toString(double)} respectively, then the value will be rounded - * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up + * using the {@linkplain java.math.RoundingMode#HALF_UP round half up * algorithm}. Otherwise, zeros may be appended to reach the precision. * For a canonical representation of the value, use {@link * Float#toString(float)} or {@link Double#toString(double)} as @@ -1192,15 +1245,15 @@ *

    If the {@code ','} flag is given, then an {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'E'} - * '\u0045' + *
    {@code 'E'} + * '\u0045' * The upper-case variant of {@code 'e'}. The exponent symbol * will be the upper-case locale-specific {@linkplain * java.text.DecimalFormatSymbols#getExponentSeparator exponent separator} * (e.g. {@code 'E'}). * - *
    {@code 'g'} - * '\u0067' + *
    {@code 'g'} + * '\u0067' * Requires the output to be formatted in general scientific notation * as described below. The localization * algorithm is applied. @@ -1224,13 +1277,13 @@ *

    If the {@code '#'} flag is given then an {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'G'} - * '\u0047' + *
    {@code 'G'} + * '\u0047' * The upper-case variant of {@code 'g'}. * - *
    {@code 'f'} - * '\u0066' - * Requires the output to be formatted using decimal + *
    {@code 'f'} + * '\u0066' + * Requires the output to be formatted using decimal * format. The localization algorithm is * applied. * @@ -1254,14 +1307,14 @@ * than the number of digits which would appear after the decimal point in * the string returned by {@link Float#toString(float)} or {@link * Double#toString(double)} respectively, then the value will be rounded - * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up + * using the {@linkplain java.math.RoundingMode#HALF_UP round half up * algorithm}. Otherwise, zeros may be appended to reach the precision. * For a canonical representation of the value, use {@link * Float#toString(float)} or {@link Double#toString(double)} as * appropriate. * - *
    {@code 'a'} - * '\u0061' + *
    {@code 'a'} + * '\u0061' * Requires the output to be formatted in hexadecimal exponential * form. No localization is applied. * @@ -1269,11 +1322,11 @@ * (absolute value) of the argument x. * *

    If x is negative or a negative-zero value then the result - * will begin with {@code '-'} ('\u002d'). + * will begin with {@code '-'} ('\u002d'). * *

    If x is positive or a positive-zero value and the * {@code '+'} flag is given then the result will begin with {@code '+'} - * ('\u002b'). + * ('\u002b'). * *

    The formatting of the magnitude m depends upon its value. * @@ -1290,7 +1343,7 @@ * exponent fields. The significand is represented by the characters * {@code "0x1."} followed by the hexadecimal representation of the rest * of the significand as a fraction. The exponent is represented by - * {@code 'p'} ('\u0070') followed by a decimal string of the + * {@code 'p'} ('\u0070') followed by a decimal string of the * unbiased exponent as if produced by invoking {@link * Integer#toString(int) Integer.toString} on the exponent value. If the * precision is specified, the value is rounded to the given number of @@ -1313,14 +1366,15 @@ *

    If the {@code '('} or {@code ','} flags are given, then a {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'A'} - * '\u0041' + *
    {@code 'A'} + * '\u0041' * The upper-case variant of {@code 'a'}. The entire string * representing the number will be converted to upper case including the - * {@code 'x'} ('\u0078') and {@code 'p'} - * ('\u0070' and all hexadecimal digits {@code 'a'} - - * {@code 'f'} ('\u0061' - '\u0066'). + * {@code 'x'} ('\u0078') and {@code 'p'} + * ('\u0070' and all hexadecimal digits {@code 'a'} - + * {@code 'f'} ('\u0061' - '\u0066'). * + *
    * *

    All flags defined for Byte, Short, Integer, and @@ -1329,7 +1383,7 @@ *

    If the {@code '#'} flag is given, then the decimal separator will * always be present. * - *

    If no flags are given the default formatting + *

    If no flags are given the default formatting * is as follows: * *

      @@ -1347,17 +1401,17 @@ * *
    * - *

    The width is the minimum number of characters + *

    The width is the minimum number of characters * to be written to the output. This includes any signs, digits, grouping * separators, decimal separators, exponential symbol, radix indicator, * parentheses, and strings representing infinity and NaN as applicable. If * the length of the converted value is less than the width then the output - * will be padded by spaces ('\u0020') until the total number of + * will be padded by spaces ('\u0020') until the total number of * characters equals width. The padding is on the left by default. If the * {@code '-'} flag is given then the padding will be on the right. If width * is not specified then there is no minimum. * - *

    If the conversion is {@code 'e'}, + *

    If the conversion is {@code 'e'}, * {@code 'E'} or {@code 'f'}, then the precision is the number of digits * after the decimal separator. If the precision is not specified, then it is * assumed to be {@code 6}. @@ -1373,17 +1427,19 @@ * precision is not provided, then all of the digits as returned by {@link * Double#toHexString(double)} will be output. * - *

    BigDecimal + *

    BigDecimal * *

    The following conversions may be applied {@link java.math.BigDecimal * BigDecimal}. * - * + *
    + * + * * - * *
    floatConv
    {@code 'e'} - * '\u0065' + *
    {@code 'e'} + * '\u0065' * Requires the output to be formatted using computerized scientific notation. The computerized scientific notation. The localization algorithm is applied. * *

    The formatting of the magnitude m depends upon its value. @@ -1404,7 +1460,7 @@ * integer part of a, as a single decimal digit, followed by the * decimal separator followed by decimal digits representing the fractional * part of a, followed by the exponent symbol {@code 'e'} - * ('\u0065'), followed by the sign of the exponent, followed + * ('\u0065'), followed by the sign of the exponent, followed * by a representation of n as a decimal integer, as produced by the * method {@link Long#toString(long, int)}, and zero-padded to include at * least two digits. @@ -1414,7 +1470,7 @@ * specified then the default value is {@code 6}. If the precision is * less than the number of digits to the right of the decimal point then * the value will be rounded using the - * {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up + * {@linkplain java.math.RoundingMode#HALF_UP round half up * algorithm}. Otherwise, zeros may be appended to reach the precision. * For a canonical representation of the value, use {@link * BigDecimal#toString()}. @@ -1422,13 +1478,13 @@ *

    If the {@code ','} flag is given, then an {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'E'} - * '\u0045' + *
    {@code 'E'} + * '\u0045' * The upper-case variant of {@code 'e'}. The exponent symbol - * will be {@code 'E'} ('\u0045'). + * will be {@code 'E'} ('\u0045'). * - *
    {@code 'g'} - * '\u0067' + *
    {@code 'g'} + * '\u0067' * Requires the output to be formatted in general scientific notation * as described below. The localization * algorithm is applied. @@ -1452,13 +1508,13 @@ *

    If the {@code '#'} flag is given then an {@link * FormatFlagsConversionMismatchException} will be thrown. * - *

    {@code 'G'} - * '\u0047' + *
    {@code 'G'} + * '\u0047' * The upper-case variant of {@code 'g'}. * - *
    {@code 'f'} - * '\u0066' - * Requires the output to be formatted using decimal + *
    {@code 'f'} + * '\u0066' + * Requires the output to be formatted using decimal * format. The localization algorithm is * applied. * @@ -1477,11 +1533,12 @@ * specified then the default value is {@code 6}. If the precision is * less than the number of digits to the right of the decimal point * then the value will be rounded using the - * {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up + * {@linkplain java.math.RoundingMode#HALF_UP round half up * algorithm}. Otherwise, zeros may be appended to reach the precision. * For a canonical representation of the value, use {@link * BigDecimal#toString()}. * + *
    * *

    All flags defined for Byte, Short, Integer, and @@ -1497,20 +1554,23 @@ * href="#floatDPrec">precision is the same as defined for Float and * Double. * - *

    Date/Time

    + *

    Date/Time

    * *

    This conversion may be applied to {@code long}, {@link Long}, {@link * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor} * - * + *
    + * + * * - * *
    DTConv
    {@code 't'} - * '\u0074' + *
    {@code 't'} + * '\u0074' * Prefix for date and time conversion characters. - *
    {@code 'T'} - * '\u0054' + *
    {@code 'T'} + * '\u0054' * The upper-case variant of {@code 't'}. * + *
    * *

    The following date and time conversion character suffixes are defined @@ -1522,55 +1582,57 @@ * *

    The following conversion characters are used for formatting times: * - * + *
    + * + * * - * *
    time
    {@code 'H'} - * '\u0048' + *
    {@code 'H'} + * '\u0048' * Hour of the day for the 24-hour clock, formatted as two digits with * a leading zero as necessary i.e. {@code 00 - 23}. {@code 00} * corresponds to midnight. * - *
    {@code 'I'} - * '\u0049' + *
    {@code 'I'} + * '\u0049' * Hour for the 12-hour clock, formatted as two digits with a leading * zero as necessary, i.e. {@code 01 - 12}. {@code 01} corresponds to * one o'clock (either morning or afternoon). * - *
    {@code 'k'} - * '\u006b' + *
    {@code 'k'} + * '\u006b' * Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}. * {@code 0} corresponds to midnight. * - *
    {@code 'l'} - * '\u006c' + *
    {@code 'l'} + * '\u006c' * Hour for the 12-hour clock, i.e. {@code 1 - 12}. {@code 1} * corresponds to one o'clock (either morning or afternoon). * - *
    {@code 'M'} - * '\u004d' + *
    {@code 'M'} + * '\u004d' * Minute within the hour formatted as two digits with a leading zero * as necessary, i.e. {@code 00 - 59}. * - *
    {@code 'S'} - * '\u0053' + *
    {@code 'S'} + * '\u0053' * Seconds within the minute, formatted as two digits with a leading * zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special * value required to support leap seconds). * - *
    {@code 'L'} - * '\u004c' + *
    {@code 'L'} + * '\u004c' * Millisecond within the second formatted as three digits with * leading zeros as necessary, i.e. {@code 000 - 999}. * - *
    {@code 'N'} - * '\u004e' + *
    {@code 'N'} + * '\u004e' * Nanosecond within the second, formatted as nine digits with leading * zeros as necessary, i.e. {@code 000000000 - 999999999}. The precision * of this value is limited by the resolution of the underlying operating * system or hardware. * - *
    {@code 'p'} - * '\u0070' + *
    {@code 'p'} + * '\u0070' * Locale-specific {@linkplain * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker * in lower case, e.g."{@code am}" or "{@code pm}". Use of the @@ -1579,8 +1641,8 @@ * GNU {@code date} and POSIX {@code strftime(3c)} which produce * upper-case output.) * - *
    {@code 'z'} - * '\u007a' + *
    {@code 'z'} + * '\u007a' * RFC 822 * style numeric time zone offset from GMT, e.g. {@code -0800}. This * value will be adjusted as necessary for Daylight Saving Time. For @@ -1588,8 +1650,8 @@ * the {@linkplain TimeZone#getDefault() default time zone} for this * instance of the Java virtual machine. * - *
    {@code 'Z'} - * '\u005a' + *
    {@code 'Z'} + * '\u005a' * A string representing the abbreviation for the time zone. This * value will be adjusted as necessary for Daylight Saving Time. For * {@code long}, {@link Long}, and {@link Date} the time zone used is @@ -1597,126 +1659,133 @@ * instance of the Java virtual machine. The Formatter's locale will * supersede the locale of the argument (if any). * - *
    {@code 's'} - * '\u0073' + *
    {@code 's'} + * '\u0073' * Seconds since the beginning of the epoch starting at 1 January 1970 * {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to * {@code Long.MAX_VALUE/1000}. * - *
    {@code 'Q'} - * '\u004f' + *
    {@code 'Q'} + * '\u004f' * Milliseconds since the beginning of the epoch starting at 1 January * 1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to * {@code Long.MAX_VALUE}. The precision of this value is limited by * the resolution of the underlying operating system or hardware. * + *
    * *

    The following conversion characters are used for formatting dates: * - * + *
    + * + * * - * *
    date
    {@code 'B'} - * '\u0042' + *
    {@code 'B'} + * '\u0042' * Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths * full month name}, e.g. {@code "January"}, {@code "February"}. * - *
    {@code 'b'} - * '\u0062' + *
    {@code 'b'} + * '\u0062' * Locale-specific {@linkplain * java.text.DateFormatSymbols#getShortMonths abbreviated month name}, * e.g. {@code "Jan"}, {@code "Feb"}. * - *
    {@code 'h'} - * '\u0068' + *
    {@code 'h'} + * '\u0068' * Same as {@code 'b'}. * - *
    {@code 'A'} - * '\u0041' + *
    {@code 'A'} + * '\u0041' * Locale-specific full name of the {@linkplain * java.text.DateFormatSymbols#getWeekdays day of the week}, * e.g. {@code "Sunday"}, {@code "Monday"} * - *
    {@code 'a'} - * '\u0061' + *
    {@code 'a'} + * '\u0061' * Locale-specific short name of the {@linkplain * java.text.DateFormatSymbols#getShortWeekdays day of the week}, * e.g. {@code "Sun"}, {@code "Mon"} * - *
    {@code 'C'} - * '\u0043' + *
    {@code 'C'} + * '\u0043' * Four-digit year divided by {@code 100}, formatted as two digits * with leading zero as necessary, i.e. {@code 00 - 99} * - *
    {@code 'Y'} - * '\u0059' Year, formatted to at least + *
    {@code 'Y'} + * '\u0059' Year, formatted to at least * four digits with leading zeros as necessary, e.g. {@code 0092} equals * {@code 92} CE for the Gregorian calendar. * - *
    {@code 'y'} - * '\u0079' + *
    {@code 'y'} + * '\u0079' * Last two digits of the year, formatted with leading zeros as * necessary, i.e. {@code 00 - 99}. * - *
    {@code 'j'} - * '\u006a' + *
    {@code 'j'} + * '\u006a' * Day of year, formatted as three digits with leading zeros as * necessary, e.g. {@code 001 - 366} for the Gregorian calendar. * {@code 001} corresponds to the first day of the year. * - *
    {@code 'm'} - * '\u006d' + *
    {@code 'm'} + * '\u006d' * Month, formatted as two digits with leading zeros as necessary, * i.e. {@code 01 - 13}, where "{@code 01}" is the first month of the * year and ("{@code 13}" is a special value required to support lunar * calendars). * - *
    {@code 'd'} - * '\u0064' + *
    {@code 'd'} + * '\u0064' * Day of month, formatted as two digits with leading zeros as * necessary, i.e. {@code 01 - 31}, where "{@code 01}" is the first day * of the month. * - *
    {@code 'e'} - * '\u0065' + *
    {@code 'e'} + * '\u0065' * Day of month, formatted as two digits, i.e. {@code 1 - 31} where * "{@code 1}" is the first day of the month. * + *
    * *

    The following conversion characters are used for formatting common * date/time compositions. * - * + *
    + * + * * - * *
    composites
    {@code 'R'} - * '\u0052' + *
    {@code 'R'} + * '\u0052' * Time formatted for the 24-hour clock as {@code "%tH:%tM"} * - *
    {@code 'T'} - * '\u0054' + *
    {@code 'T'} + * '\u0054' * Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}. * - *
    {@code 'r'} - * '\u0072' + *
    {@code 'r'} + * '\u0072' * Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS * %Tp"}. The location of the morning or afternoon marker * ({@code '%Tp'}) may be locale-dependent. * - *
    {@code 'D'} - * '\u0044' + *
    {@code 'D'} + * '\u0044' * Date formatted as {@code "%tm/%td/%ty"}. * - *
    {@code 'F'} - * '\u0046' + *
    {@code 'F'} + * '\u0046' * ISO 8601 * complete date formatted as {@code "%tY-%tm-%td"}. * - *
    {@code 'c'} - * '\u0063' + *
    {@code 'c'} + * '\u0063' * Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"}, * e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}. * + *
    * *

    The {@code '-'} flag defined for General @@ -1726,7 +1795,7 @@ *

    The width is the minimum number of characters to * be written to the output. If the length of the converted value is less than * the {@code width} then the output will be padded by spaces - * ('\u0020') until the total number of characters equals width. + * ('\u0020') until the total number of characters equals width. * The padding is on the left by default. If the {@code '-'} flag is given * then the padding will be on the right. If width is not specified then there * is no minimum. @@ -1734,19 +1803,21 @@ *

    The precision is not applicable. If the precision is specified then an * {@link IllegalFormatPrecisionException} will be thrown. * - *

    Percent

    + *

    Percent

    * *

    The conversion does not correspond to any argument. * - * + *
    + * + * * - * *
    DTConv
    {@code '%'} - * The result is a literal {@code '%'} ('\u0025') + *
    {@code '%'} + * The result is a literal {@code '%'} ('\u0025') * *

    The width is the minimum number of characters to * be written to the output including the {@code '%'}. If the length of the * converted value is less than the {@code width} then the output will be - * padded by spaces ('\u0020') until the total number of + * padded by spaces ('\u0020') until the total number of * characters equals width. The padding is on the left. If width is not * specified then just the {@code '%'} is output. * @@ -1757,25 +1828,29 @@ *

    The precision is not applicable. If the precision is specified an * {@link IllegalFormatPrecisionException} will be thrown. * + *

    * - *

    Line Separator

    + *

    Line Separator

    * *

    The conversion does not correspond to any argument. * - * + *
    + * + * * - * *
    DTConv
    {@code 'n'} + *
    {@code 'n'} * the platform-specific line separator as returned by {@link - * System#getProperty System.getProperty("line.separator")}. + * System#lineSeparator()}. * + *
    * *

    Flags, width, and precision are not applicable. If any are provided an * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException}, * and {@link IllegalFormatPrecisionException}, respectively will be thrown. * - *

    Argument Index

    + *

    Argument Index

    * *

    Format specifiers can reference arguments in three ways: * @@ -1796,7 +1871,7 @@ * * *

  • Relative indexing is used when the format specifier contains a - * {@code '<'} ('\u003c') flag which causes the argument for + * {@code '<'} ('\u003c') flag which causes the argument for * the previous format specifier to be re-used. If there is no previous * argument, then a {@link MissingFormatArgumentException} is thrown. * @@ -1831,7 +1906,7 @@ *

    The maximum number of arguments is limited by the maximum dimension of a * Java array as defined by * The Java™ Virtual Machine Specification. - * If the argument index is does not correspond to an + * If the argument index does not correspond to an * available argument, then a {@link MissingFormatArgumentException} is thrown. * *

    If there are more arguments than format specifiers, the extra arguments @@ -2070,6 +2145,40 @@ public Formatter(String fileName, String csn, Locale l) this(toCharset(csn), l, new File(fileName)); } + /** + * Constructs a new formatter with the specified file name, charset, and + * locale. + * + * @param fileName + * The name of the file to use as the destination of this + * formatter. If the file exists then it will be truncated to + * zero size; otherwise, a new file will be created. The output + * will be written to the file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If {@code l} is {@code null} then no localization + * is applied. + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(fileName)} denies write + * access to the file + * + * @throws NullPointerException + * if {@code fileName} or {@code charset} is {@code null}. + */ + // public Formatter(String fileName, Charset charset, Locale l) throws IOException { + // this(Objects.requireNonNull(charset, "charset"), l, new File(fileName)); + // } + // TODO + /** * Constructs a new formatter with the specified file. * @@ -2181,6 +2290,41 @@ public Formatter(File file, String csn, Locale l) this(toCharset(csn), l, file); } + /** + * Constructs a new formatter with the specified file, charset, and + * locale. + * + * @param file + * The file to use as the destination of this formatter. If the + * file exists then it will be truncated to zero size; otherwise, + * a new file will be created. The output will be written to the + * file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If {@code l} is {@code null} then no localization + * is applied. + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(file.getPath())} denies + * write access to the file + * + * @throws NullPointerException + * if {@code file} or {@code charset} is {@code null}. + */ + // public Formatter(File file, Charset charset, Locale l) throws IOException { + // this(Objects.requireNonNull(charset, "charset"), l, file); + // } + // TODO + + /** * Constructs a new formatter with the specified print stream. * @@ -2274,6 +2418,30 @@ public Formatter(OutputStream os, String csn, Locale l) this(l, new BufferedWriter(new OutputStreamWriter(os, csn))); } + /** + * Constructs a new formatter with the specified output stream, charset, + * and locale. + * + * @param os + * The output stream to use as the destination of this formatter. + * The output will be buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If {@code l} is {@code null} then no localization + * is applied. + * + * @throws NullPointerException + * if {@code os} or {@code charset} is {@code null}. + */ + // public Formatter(OutputStream os, Charset charset, Locale l) { + // this(l, new BufferedWriter(new OutputStreamWriter(os, charset))); + // } + // TODO + private static char getZero(Locale l) { if ((l != null) && !l.equals(Locale.US)) { DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); @@ -2494,9 +2662,8 @@ public Formatter format(Locale l, String format, Object ... args) { // last ordinary index int lasto = -1; - FormatString[] fsa = parse(format); - for (int i = 0; i < fsa.length; i++) { - FormatString fs = fsa[i]; + List fsa = parse(format); + for (FormatString fs : fsa) { int index = fs.index(); try { switch (index) { @@ -2533,7 +2700,7 @@ public Formatter format(Locale l, String format, Object ... args) { /** * Finds format specifiers in the format string. */ - private FormatString[] parse(String s) { + private List parse(String s) { ArrayList al = new ArrayList<>(); for (int i = 0, len = s.length(); i < len; ) { int nextPercent = s.indexOf('%', i); @@ -2542,8 +2709,7 @@ private FormatString[] parse(String s) { // sequence and store it. int plainTextStart = i; int plainTextEnd = (nextPercent == -1) ? len: nextPercent; - al.add(new FixedString(s.substring(plainTextStart, - plainTextEnd))); + al.add(new FixedString(s, plainTextStart, plainTextEnd)); i = plainTextEnd; } else { // We have a format specifier @@ -2552,7 +2718,7 @@ private FormatString[] parse(String s) { i = fsp.getEndIdx(); } } - return al.toArray(new FormatString[al.size()]); + return al; } /** @@ -2669,11 +2835,17 @@ private interface FormatString { private class FixedString implements FormatString { private String s; - FixedString(String s) { this.s = s; } + private int start; + private int end; + FixedString(String s, int start, int end) { + this.s = s; + this.start = start; + this.end = end; + } public int index() { return -2; } public void print(Object arg, Locale l) - throws IOException { a.append(s); } - public String toString() { return s; } + throws IOException { a.append(s, start, end); } + public String toString() { return s.substring(start, end); } } /** @@ -2699,11 +2871,15 @@ private class FormatSpecifier implements FormatString { private boolean dt = false; private char c; + // Android-changed: entire String is always consumed. + // private int index(String s, int start, int end) { private int index(String s) { + // if (start >= 0) { if (s != null) { try { // Android-changed: FormatSpecifierParser passes in correct String. - // index = Integer.parseInt(s.substring(0, s.length() - 1)); + // skip the trailing '$' + // index = Integer.parseInt(s, start, end - 1, 10); index = Integer.parseInt(s); } catch (NumberFormatException x) { /* J2ObjC: Allow fall through. @@ -2719,22 +2895,25 @@ public int index() { return index; } + // Android-changed: entire String is always consumed. + // private Flags flags(String s, int start, int end) { private Flags flags(String s) { - f = Flags.parse(s); + // f = Flags.parse(s, start, end); + f = Flags.parse(s, 0, s.length()); if (f.contains(Flags.PREVIOUS)) index = -1; return f; } - Flags flags() { - return f; - } - + // Android-changed: entire String is always consumed. + // private int width(String s, int start, int end) { private int width(String s) { width = -1; + // if (start >= 0) { if (s != null) { try { - width = Integer.parseInt(s); + // width = Integer.parseInt(s, start, end, 10); + width = Integer.parseInt(s); if (width < 0) throw new IllegalFormatWidthException(width); } catch (NumberFormatException x) { @@ -2745,16 +2924,16 @@ private int width(String s) { return width; } - int width() { - return width; - } - + // Android-changed: entire String is always consumed. + // private int precision(String s, int start, int end) { private int precision(String s) { precision = -1; + // if (start >= 0) { if (s != null) { try { // Android-changed: FormatSpecifierParser passes in correct String. - // precision = Integer.parseInt(s.substring(1)); + // skip the leading '.' + // precision = Integer.parseInt(s, start + 1, end, 10); precision = Integer.parseInt(s); if (precision < 0) throw new IllegalFormatPrecisionException(precision); @@ -2766,33 +2945,26 @@ private int precision(String s) { return precision; } - int precision() { - return precision; - } - - private char conversion(String s) { - c = s.charAt(0); + private char conversion(char conv) { + c = conv; if (!dt) { - if (!Conversion.isValid(c)) + if (!Conversion.isValid(c)) { throw new UnknownFormatConversionException(String.valueOf(c)); - if (Character.isUpperCase(c)) + } + if (Character.isUpperCase(c)) { f.add(Flags.UPPERCASE); - c = Character.toLowerCase(c); - if (Conversion.isText(c)) + c = Character.toLowerCase(c); + } + if (Conversion.isText(c)) { index = -2; + } } return c; } - private char conversion() { - return c; - } - // BEGIN Android-changed: FormatSpecifierParser passes in the values instead of a Matcher. FormatSpecifier(String indexStr, String flagsStr, String widthStr, String precisionStr, String tTStr, String convStr) { - int idx = 1; - index(indexStr); flags(flagsStr); width(widthStr); @@ -2800,11 +2972,12 @@ private char conversion() { if (tTStr != null) { dt = true; - if (tTStr.equals("T")) + if (tTStr.equals("T")) { f.add(Flags.UPPERCASE); + } } - conversion(convStr); + conversion(convStr.charAt(0)); // END Android-changed: FormatSpecifierParser passes in the values instead of a Matcher. if (dt) checkDateTime(); @@ -2841,22 +3014,22 @@ public void print(Object arg, Locale l) throws IOException { break; case Conversion.CHARACTER: case Conversion.CHARACTER_UPPER: - printCharacter(arg); + printCharacter(arg, l); break; case Conversion.BOOLEAN: - printBoolean(arg); + printBoolean(arg, l); break; case Conversion.STRING: printString(arg, l); break; case Conversion.HASHCODE: - printHashCode(arg); + printHashCode(arg, l); break; case Conversion.LINE_SEPARATOR: a.append(System.lineSeparator()); break; case Conversion.PERCENT_SIGN: - a.append('%'); + print("%", l); break; default: assert false; @@ -2865,7 +3038,7 @@ public void print(Object arg, Locale l) throws IOException { private void printInteger(Object arg, Locale l) throws IOException { if (arg == null) - print("null"); + print("null", l); else if (arg instanceof Byte) print(((Byte)arg).byteValue(), l); else if (arg instanceof Short) @@ -2882,7 +3055,7 @@ else if (arg instanceof BigInteger) private void printFloat(Object arg, Locale l) throws IOException { if (arg == null) - print("null"); + print("null", l); else if (arg instanceof Float) print(((Float)arg).floatValue(), l); else if (arg instanceof Double) @@ -2895,7 +3068,7 @@ else if (arg instanceof BigDecimal) private void printDateTime(Object arg, Locale l) throws IOException { if (arg == null) { - print("null"); + print("null", l); return; } Calendar cal = null; @@ -2915,6 +3088,10 @@ private void printDateTime(Object arg, Locale l) throws IOException { } else if (arg instanceof Calendar) { cal = (Calendar) ((Calendar) arg).clone(); cal.setLenient(true); + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // } else if (arg instanceof TemporalAccessor) { + // print((TemporalAccessor) arg, c, l); + // return; } else { failConversion(c, arg); } @@ -2923,9 +3100,9 @@ private void printDateTime(Object arg, Locale l) throws IOException { print(cal, c, l); } - private void printCharacter(Object arg) throws IOException { + private void printCharacter(Object arg, Locale l) throws IOException { if (arg == null) { - print("null"); + print("null", l); return; } String s = null; @@ -2952,7 +3129,7 @@ private void printCharacter(Object arg) throws IOException { } else { failConversion(c, arg); } - print(s); + print(s, l); } private void printString(Object arg, Locale l) throws IOException { @@ -2965,13 +3142,13 @@ private void printString(Object arg, Locale l) throws IOException { if (f.contains(Flags.ALTERNATE)) failMismatch(Flags.ALTERNATE, 's'); if (arg == null) - print("null"); + print("null", l); else - print(arg.toString()); + print(arg.toString(), l); } } - private void printBoolean(Object arg) throws IOException { + private void printBoolean(Object arg, Locale l) throws IOException { String s; if (arg != null) s = ((arg instanceof Boolean) @@ -2979,39 +3156,45 @@ private void printBoolean(Object arg) throws IOException { : Boolean.toString(true)); else s = Boolean.toString(false); - print(s); + print(s, l); } - private void printHashCode(Object arg) throws IOException { + private void printHashCode(Object arg, Locale l) throws IOException { String s = (arg == null ? "null" : Integer.toHexString(arg.hashCode())); - print(s); + print(s, l); } - private void print(String s) throws IOException { + private void print(String s, Locale l) throws IOException { if (precision != -1 && precision < s.length()) s = s.substring(0, precision); - if (f.contains(Flags.UPPERCASE)) { - // Android-changed: Use provided locale instead of default, if it is non-null. - // s = s.toUpperCase(); - s = s.toUpperCase(l != null ? l : Locale.getDefault()); - } - a.append(justify(s)); + if (f.contains(Flags.UPPERCASE)) + s = toUpperCaseWithLocale(s, l); + appendJustified(a, s); } - private String justify(String s) { - if (width == -1) - return s; - StringBuilder sb = new StringBuilder(); - boolean pad = f.contains(Flags.LEFT_JUSTIFY); - int sp = width - s.length(); - if (!pad) - for (int i = 0; i < sp; i++) sb.append(' '); - sb.append(s); - if (pad) - for (int i = 0; i < sp; i++) sb.append(' '); - return sb.toString(); + private String toUpperCaseWithLocale(String s, Locale l) { + return s.toUpperCase(Objects.requireNonNullElse(l, + Locale.getDefault(Locale.Category.FORMAT))); + } + + private Appendable appendJustified(Appendable a, CharSequence cs) throws IOException { + if (width == -1) { + return a.append(cs); + } + boolean padRight = f.contains(Flags.LEFT_JUSTIFY); + int sp = width - cs.length(); + if (padRight) { + a.append(cs); + } + for (int i = 0; i < sp; i++) { + a.append(' '); + } + if (!padRight) { + a.append(cs); + } + return a; } public String toString() { @@ -3079,9 +3262,9 @@ else if (c == Conversion.OCTAL_INTEGER) } private void checkBadFlags(Flags ... badFlags) { - for (int i = 0; i < badFlags.length; i++) - if (f.contains(badFlags[i])) - failMismatch(badFlags[i], c); + for (Flags badFlag : badFlags) + if (f.contains(badFlag)) + failMismatch(badFlag, c); } private void checkFloat() { @@ -3176,17 +3359,13 @@ private void print(long value, Locale l) throws IOException { if (c == Conversion.DECIMAL_INTEGER) { boolean neg = value < 0; - char[] va; - if (value < 0) - va = Long.toString(value, 10).substring(1).toCharArray(); - else - va = Long.toString(value, 10).toCharArray(); + String valueStr = Long.toString(value, 10); // leading sign indicator leadingSign(sb, neg); // the value - localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l); + localizedMagnitude(sb, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l); // trailing sign indicator trailingSign(sb, neg); @@ -3201,8 +3380,9 @@ private void print(long value, Locale l) throws IOException { // apply ALTERNATE (radix indicator for octal) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) sb.append('0'); - if (f.contains(Flags.ZERO_PAD)) - for (int i = 0; i < width - len; i++) sb.append('0'); + if (f.contains(Flags.ZERO_PAD)) { + trailingZeros(sb, width - len); + } sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, @@ -3215,15 +3395,16 @@ private void print(long value, Locale l) throws IOException { // apply ALTERNATE (radix indicator for hex) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); - if (f.contains(Flags.ZERO_PAD)) - for (int i = 0; i < width - len; i++) sb.append('0'); + if (f.contains(Flags.ZERO_PAD)) { + trailingZeros(sb, width - len); + } if (f.contains(Flags.UPPERCASE)) - s = s.toUpperCase(); + s = toUpperCaseWithLocale(s, l); sb.append(s); } // justify based on width - a.append(justify(sb.toString())); + appendJustified(a, sb); } // neg := val < 0 @@ -3260,8 +3441,7 @@ private void print(BigInteger value, Locale l) throws IOException { // the value if (c == Conversion.DECIMAL_INTEGER) { - char[] va = v.toString().toCharArray(); - localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l); + localizedMagnitude(sb, v.toString(), 0, f, adjustWidth(width, f, neg), l); } else if (c == Conversion.OCTAL_INTEGER) { String s = v.toString(8); @@ -3275,8 +3455,7 @@ private void print(BigInteger value, Locale l) throws IOException { sb.append('0'); } if (f.contains(Flags.ZERO_PAD)) { - for (int i = 0; i < width - len; i++) - sb.append('0'); + trailingZeros(sb, width - len); } sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { @@ -3291,11 +3470,11 @@ private void print(BigInteger value, Locale l) throws IOException { len += 2; sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); } - if (f.contains(Flags.ZERO_PAD)) - for (int i = 0; i < width - len; i++) - sb.append('0'); + if (f.contains(Flags.ZERO_PAD)) { + trailingZeros(sb, width - len); + } if (f.contains(Flags.UPPERCASE)) - s = s.toUpperCase(); + s = toUpperCaseWithLocale(s, l); sb.append(s); } @@ -3303,7 +3482,7 @@ private void print(BigInteger value, Locale l) throws IOException { trailingSign(sb, (value.signum() == -1)); // justify based on width - a.append(justify(sb.toString())); + appendJustified(a, sb); } private void print(float value, Locale l) throws IOException { @@ -3334,7 +3513,7 @@ private void print(double value, Locale l) throws IOException { } // justify based on width - a.append(justify(sb.toString())); + appendJustified(a, sb); } // !Double.isInfinite(value) && !Double.isNaN(value) @@ -3377,14 +3556,11 @@ private void print(StringBuilder sb, double value, Locale l, localeData.exponentSeparator.toLowerCase(separatorLocale)); // END Android-changed: Use localized exponent separator for %e. - Flags flags = f.dup().remove(Flags.GROUP); char sign = exp[0]; assert(sign == '+' || sign == '-'); sb.append(sign); - char[] tmp = new char[exp.length - 1]; - System.arraycopy(exp, 1, tmp, 0, exp.length - 1); - sb.append(localizedMagnitude(null, tmp, flags, -1, l)); + localizedMagnitudeExp(sb, exp, 1, l); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new FormattedFloatingDecimal with the desired // precision. @@ -3484,25 +3660,29 @@ else if (precision == 0) String s = hexDouble(value, prec); - char[] va; + StringBuilder va = new StringBuilder(); boolean upper = f.contains(Flags.UPPERCASE); sb.append(upper ? "0X" : "0x"); - if (f.contains(Flags.ZERO_PAD)) - for (int i = 0; i < width - s.length() - 2; i++) - sb.append('0'); + if (f.contains(Flags.ZERO_PAD)) { + trailingZeros(sb, width - s.length() - 2); + } int idx = s.indexOf('p'); - va = s.substring(0, idx).toCharArray(); if (upper) { - String tmp = new String(va); + String tmp = s.substring(0, idx); // don't localize hex - tmp = tmp.toUpperCase(Locale.US); - va = tmp.toCharArray(); + tmp = tmp.toUpperCase(Locale.ROOT); + va.append(tmp); + } else { + va.append(s, 0, idx); } - sb.append(prec != 0 ? addZeros(va, prec) : va); + if (prec != 0) { + addZeros(va, prec); + } + sb.append(va); sb.append(upper ? 'P' : 'p'); - sb.append(s.substring(idx+1)); + sb.append(s, idx+1, s.length()); } } @@ -3516,6 +3696,37 @@ private char[] mantissa(char[] v, int len) { System.arraycopy(v, 0, tmp, 0, i); return tmp; } + // Add zeros to the requested precision. + private void addZeros(StringBuilder sb, int prec) { + // Look for the dot. If we don't find one, the we'll need to add + // it before we add the zeros. + int len = sb.length(); + int i; + for (i = 0; i < len; i++) { + if (sb.charAt(i) == '.') { + break; + } + } + boolean needDot = false; + if (i == len) { + needDot = true; + } + + // Determine existing precision. + int outPrec = len - i - (needDot ? 0 : 1); + assert (outPrec <= prec); + if (outPrec == prec) { + return; + } + + // Add dot if previously determined to be necessary. + if (needDot) { + sb.append('.'); + } + + // Add zeros. + trailingZeros(sb, prec - outPrec); + } private char[] exponent(char[] v, int len) { int i; @@ -3529,7 +3740,7 @@ private char[] exponent(char[] v, int len) { System.arraycopy(v, i + 1, tmp, 0, len - i - 1); return tmp; } - + // Add zeros to the requested precision. private char[] addZeros(char[] v, int prec) { // Look for the dot. If we don't find one, the we'll need to add @@ -3568,30 +3779,30 @@ private char[] addZeros(char[] v, int prec) { return tmp; } - + // Method assumes that d > 0. private String hexDouble(double d, int prec) { // Let Double.toHexString handle simple cases - if(!FpUtils.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13) + if (!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13) { // remove "0x" return Double.toHexString(d).substring(2); - else { + } else { assert(prec >= 1 && prec <= 12); - int exponent = FpUtils.getExponent(d); + int exponent = Math.getExponent(d); boolean subnormal - = (exponent == DoubleConsts.MIN_EXPONENT - 1); + = (exponent == Double.MIN_EXPONENT - 1); // If this is subnormal input so normalize (could be faster to // do as integer operation). if (subnormal) { - scaleUp = FpUtils.scalb(1.0, 54); + scaleUp = Math.scalb(1.0, 54); d *= scaleUp; // Calculate the exponent. This is not just exponent + 54 // since the former is not the normalized exponent. - exponent = FpUtils.getExponent(d); - assert exponent >= DoubleConsts.MIN_EXPONENT && - exponent <= DoubleConsts.MAX_EXPONENT: exponent; + exponent = Math.getExponent(d); + assert exponent >= Double.MIN_EXPONENT && + exponent <= Double.MAX_EXPONENT: exponent; } int precision = 1 + prec*4; @@ -3668,7 +3879,7 @@ private void print(BigDecimal value, Locale l) throws IOException { trailingSign(sb, neg); // justify based on width - a.append(justify(sb.toString())); + appendJustified(a, sb); } // value > 0 @@ -3699,7 +3910,7 @@ private void print(StringBuilder sb, BigDecimal value, Locale l, = new BigDecimalLayout(v.unscaledValue(), v.scale(), BigDecimalLayoutForm.SCIENTIFIC); - char[] mant = bdl.mantissa(); + StringBuilder mant = bdl.mantissa(); // Add a decimal point if necessary. The mantissa may not // contain a decimal point if the scale is zero (the internal @@ -3707,29 +3918,29 @@ private void print(StringBuilder sb, BigDecimal value, Locale l, // precision is one. Append a decimal point if '#' is set or if // we require zero padding to get to the requested precision. if ((origPrec == 1 || !bdl.hasDot()) - && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) - mant = addDot(mant); + && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) { + mant.append('.'); + } // Add trailing zeros in the case precision is greater than // the number of available digits after the decimal separator. - mant = trailingZeros(mant, nzeros); + trailingZeros(mant, nzeros); - char[] exp = bdl.exponent(); + StringBuilder exp = bdl.exponent(); int newW = width; - if (width != -1) - newW = adjustWidth(width - exp.length - 1, f, neg); - localizedMagnitude(sb, mant, f, newW, l); + if (width != -1) { + newW = adjustWidth(width - exp.length() - 1, f, neg); + } + localizedMagnitude(sb, mant, 0, f, newW, l); sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); Flags flags = f.dup().remove(Flags.GROUP); - char sign = exp[0]; + char sign = exp.charAt(0); assert(sign == '+' || sign == '-'); - sb.append(exp[0]); + sb.append(sign); - char[] tmp = new char[exp.length - 1]; - System.arraycopy(exp, 1, tmp, 0, exp.length - 1); - sb.append(localizedMagnitude(null, tmp, flags, -1, l)); + sb.append(localizedMagnitude(null, exp, 1, flags, -1, l)); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new BigDecimal with the desired precision. int prec = (precision == -1 ? 6 : precision); @@ -3753,7 +3964,7 @@ private void print(StringBuilder sb, BigDecimal value, Locale l, value.scale(), BigDecimalLayoutForm.DECIMAL_FLOAT); - char mant[] = bdl.mantissa(); + StringBuilder mant = bdl.mantissa(); int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0); // Add a decimal point if necessary. The mantissa may not @@ -3761,14 +3972,16 @@ private void print(StringBuilder sb, BigDecimal value, Locale l, // representation has no fractional part). Append a decimal // point if '#' is set or we require zero padding to get to the // requested precision. - if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) || nzeros > 0)) - mant = addDot(bdl.mantissa()); + if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) + || nzeros > 0)) { + mant.append('.'); + } // Add trailing zeros if the precision is greater than the // number of available digits after the decimal separator. - mant = trailingZeros(mant, nzeros); + trailingZeros(mant, nzeros); - localizedMagnitude(sb, mant, f, adjustWidth(width, f, neg), l); + localizedMagnitude(sb, mant, 0, f, adjustWidth(width, f, neg), l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) @@ -3827,36 +4040,18 @@ public int scale() { return scale; } - // char[] with canonical string representation - public char[] layoutChars() { - StringBuilder sb = new StringBuilder(mant); - if (exp != null) { - sb.append('E'); - sb.append(exp); - } - return toCharArray(sb); - } - - public char[] mantissa() { - return toCharArray(mant); + public StringBuilder mantissa() { + return mant; } // The exponent will be formatted as a sign ('+' or '-') followed // by the exponent zero-padded to include at least two digits. - public char[] exponent() { - return toCharArray(exp); - } - - private char[] toCharArray(StringBuilder sb) { - if (sb == null) - return null; - char[] result = new char[sb.length()]; - sb.getChars(0, result.length, result, 0); - return result; + public StringBuilder exponent() { + return exp; } private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) { - char coeff[] = intVal.toString().toCharArray(); + String coeff = intVal.toString(); this.scale = scale; // Construct a buffer, with sufficient capacity for all cases. @@ -3864,71 +4059,74 @@ private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) { // if '.' needed, +2 for "E+", + up to 10 for adjusted // exponent. Otherwise it could have +1 if negative, plus // leading "0.00000" - mant = new StringBuilder(coeff.length + 14); + int len = coeff.length(); + mant = new StringBuilder(len + 14); if (scale == 0) { - int len = coeff.length; if (len > 1) { - mant.append(coeff[0]); + mant.append(coeff.charAt(0)); if (form == BigDecimalLayoutForm.SCIENTIFIC) { mant.append('.'); dot = true; - mant.append(coeff, 1, len - 1); + mant.append(coeff, 1, len); exp = new StringBuilder("+"); - if (len < 10) - exp.append("0").append(len - 1); - else + if (len < 10) { + exp.append('0').append(len - 1); + } else { exp.append(len - 1); + } } else { - mant.append(coeff, 1, len - 1); + mant.append(coeff, 1, len); } } else { mant.append(coeff); - if (form == BigDecimalLayoutForm.SCIENTIFIC) + if (form == BigDecimalLayoutForm.SCIENTIFIC) { exp = new StringBuilder("+00"); + } } - return; - } - long adjusted = -(long) scale + (coeff.length - 1); - if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { + } else if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { // count of padding zeros - int pad = scale - coeff.length; - if (pad >= 0) { + + if (scale >= len) { // 0.xxx form mant.append("0."); dot = true; - for (; pad > 0 ; pad--) mant.append('0'); + trailingZeros(mant, scale - len); mant.append(coeff); } else { - if (-pad < coeff.length) { + if (scale > 0) { // xx.xx form - mant.append(coeff, 0, -pad); + int pad = len - scale; + mant.append(coeff, 0, pad); mant.append('.'); dot = true; - mant.append(coeff, -pad, scale); - } else { + mant.append(coeff, pad, len); + } else { // scale < 0 // xx form - mant.append(coeff, 0, coeff.length); - for (int i = 0; i < -scale; i++) - mant.append('0'); + mant.append(coeff, 0, len); + if (intVal.signum() != 0) { + trailingZeros(mant, -scale); + } this.scale = 0; } } } else { // x.xxx form - mant.append(coeff[0]); - if (coeff.length > 1) { + mant.append(coeff.charAt(0)); + if (len > 1) { mant.append('.'); dot = true; - mant.append(coeff, 1, coeff.length-1); + mant.append(coeff, 1, len); } exp = new StringBuilder(); + long adjusted = -(long) scale + (len - 1); if (adjusted != 0) { long abs = Math.abs(adjusted); // require sign exp.append(adjusted < 0 ? '-' : '+'); - if (abs < 10) + if (abs < 10) { exp.append('0'); + } exp.append(abs); } else { exp.append("+00"); @@ -3952,38 +4150,28 @@ private char[] addDot(char[] mant) { tmp[tmp.length - 1] = '.'; return tmp; } - - // Add trailing zeros in the case precision is greater than the number - // of available digits after the decimal separator. - private char[] trailingZeros(char[] mant, int nzeros) { - char[] tmp = mant; - if (nzeros > 0) { - tmp = new char[mant.length + nzeros]; - System.arraycopy(mant, 0, tmp, 0, mant.length); - for (int i = mant.length; i < tmp.length; i++) - tmp[i] = '0'; + + // Add trailing zeros + private void trailingZeros(StringBuilder sb, int nzeros) { + for (int i = 0; i < nzeros; i++) { + sb.append('0'); } - return tmp; } - private void print(Calendar t, char c, Locale l) throws IOException - { + private void print(Calendar t, char c, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); print(sb, t, c, l); // justify based on width - String s = justify(sb.toString()); - if (f.contains(Flags.UPPERCASE)) - s = s.toUpperCase(); - - a.append(s); + if (f.contains(Flags.UPPERCASE)) { + appendJustified(a, toUpperCaseWithLocale(sb.toString(), l)); + } else { + appendJustified(a, sb); + } } - private Appendable print(StringBuilder sb, Calendar t, char c, - Locale l) - throws IOException - { - assert(width == -1); + private Appendable print(StringBuilder sb, Calendar t, char c, Locale l) + throws IOException { if (sb == null) sb = new StringBuilder(); switch (c) { @@ -4033,7 +4221,8 @@ private Appendable print(StringBuilder sb, Calendar t, char c, ampm = dfs.getAmPmStrings(); } String s = ampm[t.get(Calendar.AM_PM)]; - sb.append(s.toLowerCase(l != null ? l : Locale.US)); + sb.append(s.toLowerCase(Objects.requireNonNullElse(l, + Locale.getDefault(Locale.Category.FORMAT)))); break; } case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) @@ -4066,7 +4255,7 @@ private Appendable print(StringBuilder sb, Calendar t, char c, TimeZone tz = t.getTimeZone(); sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0), TimeZone.SHORT, - (l == null) ? Locale.US : l)); + Objects.requireNonNullElse(l, Locale.US))); break; } @@ -4074,7 +4263,7 @@ private Appendable print(StringBuilder sb, Calendar t, char c, case DateTime.NAME_OF_DAY_ABBREV: // 'a' case DateTime.NAME_OF_DAY: { // 'A' int i = t.get(Calendar.DAY_OF_WEEK); - Locale lt = ((l == null) ? Locale.US : l); + Locale lt = Objects.requireNonNullElse(l, Locale.US); DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); if (c == DateTime.NAME_OF_DAY) sb.append(dfs.getWeekdays()[i]); @@ -4086,7 +4275,7 @@ private Appendable print(StringBuilder sb, Calendar t, char c, case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b case DateTime.NAME_OF_MONTH: { // 'B' int i = t.get(Calendar.MONTH); - Locale lt = ((l == null) ? Locale.US : l); + Locale lt = Objects.requireNonNullElse(l, Locale.US); DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); if (c == DateTime.NAME_OF_MONTH) sb.append(dfs.getMonths()[i]); @@ -4156,7 +4345,8 @@ private Appendable print(StringBuilder sb, Calendar t, char c, // this may be in wrong place for some locales StringBuilder tsb = new StringBuilder(); print(tsb, t, DateTime.AM_PM, l); - sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US)); + + sb.append(toUpperCaseWithLocale(tsb.toString(), l)); break; } case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) @@ -4189,6 +4379,250 @@ private Appendable print(StringBuilder sb, Calendar t, char c, return sb; } + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // private void print(TemporalAccessor t, char c, Locale l) throws IOException { + // StringBuilder sb = new StringBuilder(); + // print(sb, t, c, l); + // // justify based on width + // if (f.contains(Flags.UPPERCASE)) { + // appendJustified(a, toUpperCaseWithLocale(sb.toString(), l)); + // } else { + // appendJustified(a, sb); + // } + // } + + // private Appendable print(StringBuilder sb, TemporalAccessor t, char c, + // Locale l) throws IOException { + // if (sb == null) + // sb = new StringBuilder(); + // try { + // switch (c) { + // case DateTime.HOUR_OF_DAY_0: { // 'H' (00 - 23) + // int i = t.get(ChronoField.HOUR_OF_DAY); + // sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); + // break; + // } + // case DateTime.HOUR_OF_DAY: { // 'k' (0 - 23) -- like H + // int i = t.get(ChronoField.HOUR_OF_DAY); + // sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); + // break; + // } + // case DateTime.HOUR_0: { // 'I' (01 - 12) + // int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); + // sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); + // break; + // } + // case DateTime.HOUR: { // 'l' (1 - 12) -- like I + // int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); + // sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); + // break; + // } + // case DateTime.MINUTE: { // 'M' (00 - 59) + // int i = t.get(ChronoField.MINUTE_OF_HOUR); + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, 2, l)); + // break; + // } + // case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) + // int i; + // try { + // i = t.get(ChronoField.NANO_OF_SECOND); + // } catch (UnsupportedTemporalTypeException u) { + // i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000; + // } + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, 9, l)); + // break; + // } + // case DateTime.MILLISECOND: { // 'L' (000 - 999) + // int i = t.get(ChronoField.MILLI_OF_SECOND); + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, 3, l)); + // break; + // } + // case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?) + // long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L + + // t.getLong(ChronoField.MILLI_OF_SECOND); + // Flags flags = Flags.NONE; + // sb.append(localizedMagnitude(null, i, flags, width, l)); + // break; + // } + // case DateTime.AM_PM: { // 'p' (am or pm) + // // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper + // String[] ampm = { "AM", "PM" }; + // if (l != null && l != Locale.US) { + // DateFormatSymbols dfs = DateFormatSymbols.getInstance(l); + // ampm = dfs.getAmPmStrings(); + // } + // String s = ampm[t.get(ChronoField.AMPM_OF_DAY)]; + // sb.append(s.toLowerCase(Objects.requireNonNullElse(l, + // Locale.getDefault(Locale.Category.FORMAT)))); + // break; + // } + // case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) + // long i = t.getLong(ChronoField.INSTANT_SECONDS); + // Flags flags = Flags.NONE; + // sb.append(localizedMagnitude(null, i, flags, width, l)); + // break; + // } + // case DateTime.SECOND: { // 'S' (00 - 60 - leap second) + // int i = t.get(ChronoField.SECOND_OF_MINUTE); + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, 2, l)); + // break; + // } + // case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus? + // int i = t.get(ChronoField.OFFSET_SECONDS); + // boolean neg = i < 0; + // sb.append(neg ? '-' : '+'); + // if (neg) + // i = -i; + // int min = i / 60; + // // combine minute and hour into a single integer + // int offset = (min / 60) * 100 + (min % 60); + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, offset, flags, 4, l)); + // break; + // } + // case DateTime.ZONE: { // 'Z' (symbol) + // ZoneId zid = t.query(TemporalQueries.zone()); + // if (zid == null) { + // throw new IllegalFormatConversionException(c, t.getClass()); + // } + // if (!(zid instanceof ZoneOffset) && + // t.isSupported(ChronoField.INSTANT_SECONDS)) { + // Instant instant = Instant.from(t); + // sb.append(TimeZone.getTimeZone(zid.getId()) + // .getDisplayName(zid.getRules().isDaylightSavings(instant), + // TimeZone.SHORT, + // Objects.requireNonNullElse(l, Locale.US))); + // break; + // } + // sb.append(zid.getId()); + // break; + // } + // // Date + // case DateTime.NAME_OF_DAY_ABBREV: // 'a' + // case DateTime.NAME_OF_DAY: { // 'A' + // int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1; + // Locale lt = Objects.requireNonNullElse(l, Locale.US); + // DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); + // if (c == DateTime.NAME_OF_DAY) + // sb.append(dfs.getWeekdays()[i]); + // else + // sb.append(dfs.getShortWeekdays()[i]); + // break; + // } + // case DateTime.NAME_OF_MONTH_ABBREV: // 'b' + // case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b + // case DateTime.NAME_OF_MONTH: { // 'B' + // int i = t.get(ChronoField.MONTH_OF_YEAR) - 1; + // Locale lt = Objects.requireNonNullElse(l, Locale.US); + // DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); + // if (c == DateTime.NAME_OF_MONTH) + // sb.append(dfs.getMonths()[i]); + // else + // sb.append(dfs.getShortMonths()[i]); + // break; + // } + // case DateTime.CENTURY: // 'C' (00 - 99) + // case DateTime.YEAR_2: // 'y' (00 - 99) + // case DateTime.YEAR_4: { // 'Y' (0000 - 9999) + // int i = t.get(ChronoField.YEAR_OF_ERA); + // int size = 2; + // switch (c) { + // case DateTime.CENTURY: + // i /= 100; + // break; + // case DateTime.YEAR_2: + // i %= 100; + // break; + // case DateTime.YEAR_4: + // size = 4; + // break; + // } + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, size, l)); + // break; + // } + // case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31) + // case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d + // int i = t.get(ChronoField.DAY_OF_MONTH); + // Flags flags = (c == DateTime.DAY_OF_MONTH_0 + // ? Flags.ZERO_PAD + // : Flags.NONE); + // sb.append(localizedMagnitude(null, i, flags, 2, l)); + // break; + // } + // case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366) + // int i = t.get(ChronoField.DAY_OF_YEAR); + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, 3, l)); + // break; + // } + // case DateTime.MONTH: { // 'm' (01 - 12) + // int i = t.get(ChronoField.MONTH_OF_YEAR); + // Flags flags = Flags.ZERO_PAD; + // sb.append(localizedMagnitude(null, i, flags, 2, l)); + // break; + // } + + // // Composites + // case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS) + // case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M) + // char sep = ':'; + // print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); + // print(sb, t, DateTime.MINUTE, l); + // if (c == DateTime.TIME) { + // sb.append(sep); + // print(sb, t, DateTime.SECOND, l); + // } + // break; + // } + // case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M) + // char sep = ':'; + // print(sb, t, DateTime.HOUR_0, l).append(sep); + // print(sb, t, DateTime.MINUTE, l).append(sep); + // print(sb, t, DateTime.SECOND, l).append(' '); + // // this may be in wrong place for some locales + // StringBuilder tsb = new StringBuilder(); + // print(tsb, t, DateTime.AM_PM, l); + // sb.append(toUpperCaseWithLocale(tsb.toString(), l)); + // break; + // } + // case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) + // char sep = ' '; + // print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); + // print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); + // print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + // print(sb, t, DateTime.TIME, l).append(sep); + // print(sb, t, DateTime.ZONE, l).append(sep); + // print(sb, t, DateTime.YEAR_4, l); + // break; + // } + // case DateTime.DATE: { // 'D' (mm/dd/yy) + // char sep = '/'; + // print(sb, t, DateTime.MONTH, l).append(sep); + // print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); + // print(sb, t, DateTime.YEAR_2, l); + // break; + // } + // case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d) + // char sep = '-'; + // print(sb, t, DateTime.YEAR_4, l).append(sep); + // print(sb, t, DateTime.MONTH, l).append(sep); + // print(sb, t, DateTime.DAY_OF_MONTH_0, l); + // break; + // } + // default: + // assert false; + // } + // } catch (DateTimeException x) { + // throw new IllegalFormatConversionException(c, t.getClass()); + // } + // return sb; + // } + // -- Methods to support throwing exceptions -- private void failMismatch(Flags f, char c) { @@ -4208,6 +4642,121 @@ private char getZero(Locale l) { return zero; } + // private StringBuilder localizedMagnitude(StringBuilder sb, + // long value, Flags f, int width, Locale l) { + // return localizedMagnitude(sb, Long.toString(value, 10), 0, f, width, l); + // } + + private StringBuilder localizedMagnitude(StringBuilder sb, + CharSequence value, final int offset, Flags f, int width, + Locale l) { + if (sb == null) { + sb = new StringBuilder(); + } + int begin = sb.length(); + + char zero = getZero(l); + + // determine localized grouping separator and size + char grpSep = '\0'; + int grpSize = -1; + char decSep = '\0'; + + int len = value.length(); + int dot = len; + for (int j = offset; j < len; j++) { + if (value.charAt(j) == '.') { + dot = j; + break; + } + } + + if (dot < len) { + if (l == null || l.equals(Locale.US)) { + decSep = '.'; + } else { + DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); + decSep = dfs.getDecimalSeparator(); + } + } + + if (f.contains(Flags.GROUP)) { + if (l == null || l.equals(Locale.US)) { + grpSep = ','; + grpSize = 3; + } else { + DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); + grpSep = dfs.getGroupingSeparator(); + // Android-removed: DecimalFormat is always returned. + /* + DecimalFormat df = null; + NumberFormat nf = NumberFormat.getNumberInstance(l); + if (nf instanceof DecimalFormat) { + df = (DecimalFormat) nf; + } else { + + // Use DecimalFormat constructor to obtain the instance, + // in case NumberFormat.getNumberInstance(l) + // returns instance other than DecimalFormat + LocaleProviderAdapter adapter = LocaleProviderAdapter + .getAdapter(NumberFormatProvider.class, l); + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + String[] all = adapter.getLocaleResources(l) + .getNumberPatterns(); + df = new DecimalFormat(all[0], dfs); + } + */ + DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l); + grpSize = df.getGroupingSize(); + + if (!df.isGroupingUsed() || grpSize == 0) { + grpSep = '\0'; + } + } + } + + // localize the digits inserting group separators as necessary + for (int j = offset; j < len; j++) { + if (j == dot) { + sb.append(decSep); + // no more group separators after the decimal separator + grpSep = '\0'; + continue; + } + + char c = value.charAt(j); + sb.append((char) ((c - '0') + zero)); + if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1)) { + sb.append(grpSep); + } + } + + // apply zero padding + if (width != -1 && f.contains(Flags.ZERO_PAD)) { + for (int k = sb.length(); k < width; k++) { + sb.insert(begin, zero); + } + } + + return sb; + } + + // Specialized localization of exponents, where the source value can only + // contain characters '0' through '9', starting at index offset, and no + // group separators is added for any locale. + private void localizedMagnitudeExp(StringBuilder sb, char[] value, + final int offset, Locale l) { + char zero = getZero(l); + + int len = value.length; + for (int j = offset; j < len; j++) { + char c = value[j]; + sb.append((char) ((c - '0') + zero)); + } + } + private StringBuilder localizedMagnitude(StringBuilder sb, long value, Flags f, int width, Locale l) @@ -4284,8 +4833,11 @@ private char getZero(Locale l) { return sb; } + } + + private static class Flags { private int flags; @@ -4332,11 +4884,11 @@ public Flags remove(Flags f) { return this; } - public static Flags parse(String s) { - char[] ca = s.toCharArray(); + public static Flags parse(String s, int start, int end) { Flags f = new Flags(0); - for (int i = 0; i < ca.length; i++) { - Flags v = parse(ca[i]); + for (int i = start; i < end; i++) { + char c = s.charAt(i); + Flags v = parse(c); if (f.contains(v)) throw new DuplicateFormatFlagsException(v.toString()); f.add(v); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatterClosedException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatterClosedException.java index b0aa872fa8..856dc974fc 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatterClosedException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/FormatterClosedException.java @@ -28,7 +28,7 @@ /** * Unchecked exception thrown when the formatter has been closed. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/GregorianCalendar.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/GregorianCalendar.java index 45989db6d8..2f07941d1c 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/GregorianCalendar.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/GregorianCalendar.java @@ -42,6 +42,9 @@ import com.google.j2objc.util.NativeTimeZone; import java.io.IOException; import java.io.ObjectInputStream; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; import sun.util.calendar.BaseCalendar; import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; @@ -89,7 +92,7 @@ * adjustment may be made if desired for dates that are prior to the Gregorian * changeover and which fall between January 1 and March 24. * - *

    Week Of Year and Week Year

    + *

    Week Of Year and Week Year

    * *

    Values calculated for the {@link Calendar#WEEK_OF_YEAR * WEEK_OF_YEAR} field range from 1 to 53. The first week of a @@ -106,7 +109,7 @@ *

    The {@code getFirstDayOfWeek()} and {@code * getMinimalDaysInFirstWeek()} values are initialized using * locale-dependent resources when constructing a {@code - * GregorianCalendar}. The week + * GregorianCalendar}. The week * determination is compatible with the ISO 8601 standard when {@code * getFirstDayOfWeek()} is {@code MONDAY} and {@code * getMinimalDaysInFirstWeek()} is 4, which values are used in locales @@ -115,7 +118,7 @@ * {@link Calendar#setMinimalDaysInFirstWeek(int) * setMinimalDaysInFirstWeek()}. * - *

    A week year is in sync with a + *

    A week year is in sync with a * {@code WEEK_OF_YEAR} cycle. All weeks between the first and last * weeks (inclusive) have the same week year value. * Therefore, the first and last days of a week year may have @@ -157,88 +160,89 @@ * undefined. GregorianCalendar uses the following * default value for each calendar field if its value is undefined. * - * - * + *
    + * + * * - * - * * + * + * * - * - * + * * * - * - * + * * * - * - * + * * * - * - * + * * * - * - * + * * * - * - * + * * * - * - * + * * * - * - * + * * * - * - * + * * * @@ -323,7 +327,7 @@ * * @see TimeZone * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu - * @since JDK1.1 + * @since 1.1 */ public class GregorianCalendar extends Calendar { /* @@ -422,7 +426,7 @@ public class GregorianCalendar extends Calendar { * DAY_OF_MONTH 1 1 28* 31 * DAY_OF_YEAR 1 1 365* 366 * DAY_OF_WEEK 1 1 7 7 - * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6 + * DAY_OF_WEEK_IN_MONTH 1 1 4* 6 * AM_PM 0 0 1 1 * HOUR 0 0 11 11 * HOUR_OF_DAY 0 0 23 23 @@ -728,7 +732,7 @@ public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay, * Constructs an empty GregorianCalendar. * * @param zone the given time zone - * @param locale the given locale + * @param aLocale the given locale * @param flag the flag requesting an empty instance */ GregorianCalendar(TimeZone zone, Locale locale, boolean flag) { @@ -736,12 +740,12 @@ public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay, gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone()); } - // BEGIN Android-added + // BEGIN Android-added: Constructor. GregorianCalendar(long milliseconds) { this(); setTimeInMillis(milliseconds); } - // END Android-added + // END Android-added: Constructor. ///////////////// // Public methods @@ -1077,7 +1081,7 @@ public void add(int field, int amount) { } fd += delta; // fd is the expected fixed date after the calculation - // BEGIN Android-changed: time zone related calculation via helper methods + // BEGIN Android-changed: time zone related calculation via helper methods. // Calculate the time in the UTC time zone. long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay; @@ -1090,7 +1094,7 @@ public void add(int field, int amount) { // Update the time and recompute the fields. setTimeInMillis(millis); - // END Android-changed: time zone related calculation via helper methods + // END Android-changed: time zone related calculation via helper methods. } } @@ -1195,37 +1199,33 @@ public void roll(int field, int amount) { case HOUR: case HOUR_OF_DAY: { - int unit = max + 1; // 12 or 24 hours - int h = internalGet(field); - int nh = (h + amount) % unit; - if (nh < 0) { - nh += unit; + int rolledValue = getRolledValue(internalGet(field), amount, min, max); + int hourOfDay = rolledValue; + if (field == HOUR && internalGet(AM_PM) == PM) { + hourOfDay += 12; } - time += ONE_HOUR * (nh - h); - // The day might have changed, which could happen if - // the daylight saving time transition brings it to - // the next day, although it's very unlikely. But we - // have to make sure not to change the larger fields. + // Create the current date/time value to perform wall-clock-based + // roll. CalendarDate d = calsys.getCalendarDate(time, getZone()); - if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) { - d.setDate(internalGet(YEAR), - internalGet(MONTH) + 1, - internalGet(DAY_OF_MONTH)); - if (field == HOUR) { - assert (internalGet(AM_PM) == PM); - d.addHours(+12); // restore PM + d.setHours(hourOfDay); + time = calsys.getTime(d); + + // If we stay on the same wall-clock time, try the next or previous hour. + if (internalGet(HOUR_OF_DAY) == d.getHours()) { + hourOfDay = getRolledValue(rolledValue, amount > 0 ? +1 : -1, min, max); + if (field == HOUR && internalGet(AM_PM) == PM) { + hourOfDay += 12; } + d.setHours(hourOfDay); time = calsys.getTime(d); } - int hourOfDay = d.getHours(); - internalSet(field, hourOfDay % unit); - if (field == HOUR) { - internalSet(HOUR_OF_DAY, hourOfDay); - } else { - internalSet(AM_PM, hourOfDay / 12); - internalSet(HOUR, hourOfDay % 12); - } + // Get the new hourOfDay value which might have changed due to a DST transition. + hourOfDay = d.getHours(); + // Update the hour related fields + internalSet(HOUR_OF_DAY, hourOfDay); + internalSet(AM_PM, hourOfDay / 12); + internalSet(HOUR, hourOfDay % 12); // Time zone offset and/or daylight saving might have changed. int zoneOffset = d.getZoneOffset(); @@ -2288,7 +2288,7 @@ public int getWeeksInWeekYear() { * Long.MIN_VALUE, the fixed date value is unknown. Currently, * Julian calendar dates are not cached. */ - transient private long cachedFixedDate = Long.MIN_VALUE; + private transient long cachedFixedDate = Long.MIN_VALUE; /** * Converts the time value (millisecond offset from the + * Since this object supports a Julian-Gregorian cutover date and + * {@code ZonedDateTime} does not, it is possible that the resulting year, + * month and day will have different values. The result will represent the + * correct date in the ISO calendar system, which will also be the same value + * for Modified Julian Days. + * + * @return a zoned date-time representing the same point on the time-line + * as this gregorian calendar + * @since 1.8 + */ + /* J2ObjC removed + public ZonedDateTime toZonedDateTime() { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(getTimeInMillis()), + getTimeZone().toZoneId()); + } + */ + + /** + * Obtains an instance of {@code GregorianCalendar} with the default locale + * from a {@code ZonedDateTime} object. + *

    + * Since {@code ZonedDateTime} does not support a Julian-Gregorian cutover + * date and uses ISO calendar system, the return GregorianCalendar is a pure + * Gregorian calendar and uses ISO 8601 standard for week definitions, + * which has {@code MONDAY} as the {@link Calendar#getFirstDayOfWeek() + * FirstDayOfWeek} and {@code 4} as the value of the + * {@link Calendar#getMinimalDaysInFirstWeek() MinimalDaysInFirstWeek}. + *

    + * {@code ZoneDateTime} can store points on the time-line further in the + * future and further in the past than {@code GregorianCalendar}. In this + * scenario, this method will throw an {@code IllegalArgumentException} + * exception. + * + * @param zdt the zoned date-time object to convert + * @return the gregorian calendar representing the same point on the + * time-line as the zoned date-time provided + * @exception NullPointerException if {@code zdt} is null + * @exception IllegalArgumentException if the zoned date-time is too + * large to represent as a {@code GregorianCalendar} + * @since 1.8 + */ + /* J2ObjC removed + public static GregorianCalendar from(ZonedDateTime zdt) { + GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone(zdt.getZone())); + cal.setGregorianChange(new Date(Long.MIN_VALUE)); + cal.setFirstDayOfWeek(MONDAY); + cal.setMinimalDaysInFirstWeek(4); + try { + cal.setTimeInMillis(Math.addExact(Math.multiplyExact(zdt.toEpochSecond(), 1000), + zdt.get(ChronoField.MILLI_OF_SECOND))); + } catch (ArithmeticException ex) { + throw new IllegalArgumentException(ex); + } + return cal; + } + */ } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashMap.java index 0cbf4dd249..80f516214f 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, 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 @@ -42,24 +42,24 @@ ]-*/ /** - * Hash table based implementation of the Map interface. This + * Hash table based implementation of the {@code Map} interface. This * implementation provides all of the optional map operations, and permits - * null values and the null key. (The HashMap - * class is roughly equivalent to Hashtable, except that it is + * {@code null} values and the {@code null} key. (The {@code HashMap} + * class is roughly equivalent to {@code Hashtable}, except that it is * unsynchronized and permits nulls.) This class makes no guarantees as to * the order of the map; in particular, it does not guarantee that the order * will remain constant over time. * *

    This implementation provides constant-time performance for the basic - * operations (get and put), assuming the hash function + * operations ({@code get} and {@code put}), assuming the hash function * disperses the elements properly among the buckets. Iteration over * collection views requires time proportional to the "capacity" of the - * HashMap instance (the number of buckets) plus its size (the number + * {@code HashMap} instance (the number of buckets) plus its size (the number * of key-value mappings). Thus, it's very important not to set the initial * capacity too high (or the load factor too low) if iteration performance is * important. * - *

    An instance of HashMap has two parameters that affect its + *

    An instance of {@code HashMap} has two parameters that affect its * performance: initial capacity and load factor. The * capacity is the number of buckets in the hash table, and the initial * capacity is simply the capacity at the time the hash table is created. The @@ -73,15 +73,15 @@ *

    As a general rule, the default load factor (.75) offers a good * tradeoff between time and space costs. Higher values decrease the * space overhead but increase the lookup cost (reflected in most of - * the operations of the HashMap class, including - * get and put). The expected number of entries in + * the operations of the {@code HashMap} class, including + * {@code get} and {@code put}). The expected number of entries in * the map and its load factor should be taken into account when * setting its initial capacity, so as to minimize the number of * rehash operations. If the initial capacity is greater than the * maximum number of entries divided by the load factor, no rehash * operations will ever occur. * - *

    If many mappings are to be stored in a HashMap + *

    If many mappings are to be stored in a {@code HashMap} * instance, creating it with a sufficiently large capacity will allow * the mappings to be stored more efficiently than letting it perform * automatic rehashing as needed to grow the table. Note that using @@ -108,7 +108,7 @@ *

    The iterators returned by all of this class's "collection view methods" * are fail-fast: if the map is structurally modified at any time after * the iterator is created, in any way except through the iterator's own - * remove method, the iterator will throw a + * {@code remove} method, the iterator will throw a * {@link ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than risking * arbitrary, non-deterministic behavior at an undetermined time in the @@ -117,13 +117,13 @@ *

    Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. * *

    This class is a member of the - * + * * Java Collections Framework. * * @param the type of keys maintained by this map @@ -143,6 +143,7 @@ public class HashMap extends AbstractMap implements Map, Cloneable, Serializable { + @java.io.Serial private static final long serialVersionUID = 362498820763181265L; /* @@ -311,6 +312,13 @@ public final V setValue(V newValue) { public final boolean equals(Object o) { if (o == this) return true; + + // BEGIN Android-changed: Patternmatching for instanceof is not available yet. + /* + return o instanceof Map.Entry e + && Objects.equals(key, e.getKey()) + && Objects.equals(value, e.getValue()); + */ if (o instanceof Map.Entry) { Map.Entry e = (Map.Entry)o; if (Objects.equals(key, e.getKey()) && @@ -318,6 +326,7 @@ public final boolean equals(Object o) { return true; } return false; + // END Android-changed: Patternmatching for instanceof is not available yet. } } @@ -350,13 +359,13 @@ static final int hash(Object key) { */ static Class comparableClassFor(Object x) { if (x instanceof Comparable) { - Class c; Type[] ts, as; Type t; ParameterizedType p; + Class c; Type[] ts, as; ParameterizedType p; if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { - for (int i = 0; i < ts.length; ++i) { - if (((t = ts[i]) instanceof ParameterizedType) && - ((p = (ParameterizedType)t).getRawType() == + for (Type t : ts) { + if ((t instanceof ParameterizedType) && + ((p = (ParameterizedType) t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c @@ -381,12 +390,7 @@ static int compareComparables(Class kc, Object k, Object x) { * Returns a power of two size for the given target capacity. */ static final int tableSizeFor(int cap) { - int n = cap - 1; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; + int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1); return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } @@ -441,7 +445,7 @@ static final int tableSizeFor(int cap) { /* ---------------- Public operations -------------- */ /** - * Constructs an empty HashMap with the specified initial + * Constructs an empty {@code HashMap} with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity @@ -463,7 +467,7 @@ public HashMap(int initialCapacity, float loadFactor) { } /** - * Constructs an empty HashMap with the specified initial + * Constructs an empty {@code HashMap} with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity. @@ -474,7 +478,7 @@ public HashMap(int initialCapacity) { } /** - * Constructs an empty HashMap with the default initial capacity + * Constructs an empty {@code HashMap} with the default initial capacity * (16) and the default load factor (0.75). */ public HashMap() { @@ -482,10 +486,10 @@ public HashMap() { } /** - * Constructs a new HashMap with the same mappings as the - * specified Map. The HashMap is created with + * Constructs a new {@code HashMap} with the same mappings as the + * specified {@code Map}. The {@code HashMap} is created with * default load factor (0.75) and an initial capacity sufficient to - * hold the mappings in the specified Map. + * hold the mappings in the specified {@code Map}. * * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null @@ -496,7 +500,7 @@ public HashMap(Map m) { } /** - * Implements Map.putAll and Map constructor + * Implements Map.putAll and Map constructor. * * @param m the map * @param evict false when initially constructing this map, else @@ -511,9 +515,14 @@ final void putMapEntries(Map m, boolean evict) { (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); + } else { + // Because of linked-list bucket constraints, we cannot + // expand all at once, but can reduce total resize + // effort by repeated doubling now vs later + while (s > threshold && table.length < MAXIMUM_CAPACITY) + resize(); } - else if (s > threshold) - resize(); + for (Map.Entry e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); @@ -532,9 +541,9 @@ public int size() { } /** - * Returns true if this map contains no key-value mappings. + * Returns {@code true} if this map contains no key-value mappings. * - * @return true if this map contains no key-value mappings + * @return {@code true} if this map contains no key-value mappings */ public boolean isEmpty() { return size == 0; @@ -559,20 +568,19 @@ public boolean isEmpty() { */ public V get(Object key) { Node e; - return (e = getNode(hash(key), key)) == null ? null : e.value; + return (e = getNode(key)) == null ? null : e.value; } /** - * Implements Map.get and related methods + * Implements Map.get and related methods. * - * @param hash hash for key * @param key the key * @return the node, or null if none */ - final Node getNode(int hash, Object key) { - Node[] tab; Node first, e; int n; K k; + final Node getNode(Object key) { + Node[] tab; Node first, e; int n, hash; K k; if ((tab = table) != null && (n = tab.length) > 0 && - (first = tab[(n - 1) & hash]) != null) { + (first = tab[(n - 1) & (hash = hash(key))]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; @@ -590,15 +598,15 @@ final Node getNode(int hash, Object key) { } /** - * Returns true if this map contains a mapping for the + * Returns {@code true} if this map contains a mapping for the * specified key. * * @param key The key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified + * @return {@code true} if this map contains a mapping for the specified * key. */ public boolean containsKey(Object key) { - return getNode(hash(key), key) != null; + return getNode(key) != null; } /** @@ -608,17 +616,17 @@ public boolean containsKey(Object key) { * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** - * Implements Map.put and related methods + * Implements Map.put and related methods. * * @param hash hash for key * @param key the key @@ -706,7 +714,7 @@ else if (oldThr > 0) // initial capacity was placed in threshold } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) - Node[] newTab = (Node[])new Node[newCap]; + Node[] newTab = (Node[])new Node[newCap]; table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { @@ -794,10 +802,10 @@ public void putAll(Map m) { * Removes the mapping for the specified key from this map if present. * * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) */ public V remove(Object key) { Node e; @@ -806,7 +814,7 @@ public V remove(Object key) { } /** - * Implements Map.remove and related methods + * Implements Map.remove and related methods. * * @param hash hash for key * @param key the key @@ -871,18 +879,18 @@ public void clear() { } /** - * Returns true if this map maps one or more keys to the + * Returns {@code true} if this map maps one or more keys to the * specified value. * * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the + * @return {@code true} if this map maps one or more keys to the * specified value */ public boolean containsValue(Object value) { Node[] tab; V v; if ((tab = table) != null && size > 0) { - for (int i = 0; i < tab.length; ++i) { - for (Node e = tab[i]; e != null; e = e.next) { + for (Node e : tab) { + for (; e != null; e = e.next) { if ((v = e.value) == value || (value != null && value.equals(v))) return true; @@ -897,12 +905,12 @@ public boolean containsValue(Object value) { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation), the results of + * the iterator's own {@code remove} operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the - * Iterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or addAll + * {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} * operations. * * @return a set view of the keys contained in this map @@ -916,6 +924,74 @@ public Set keySet() { return ks; } + /** + * Prepares the array for {@link Collection#toArray(Object[])} implementation. + * If supplied array is smaller than this map size, a new array is allocated. + * If supplied array is bigger than this map size, a null is written at size index. + * + * @param a an original array passed to {@code toArray()} method + * @param type of array elements + * @return an array ready to be filled and returned from {@code toArray()} method. + */ + @SuppressWarnings("unchecked") + final T[] prepareArray(T[] a) { + int size = this.size; + if (a.length < size) { + return (T[]) java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), size); + } + if (a.length > size) { + a[size] = null; + } + return a; + } + + /** + * Fills an array with this map keys and returns it. This method assumes + * that input array is big enough to fit all the keys. Use + * {@link #prepareArray(Object[])} to ensure this. + * + * @param a an array to fill + * @param type of array elements + * @return supplied array + */ + T[] keysToArray(T[] a) { + Object[] r = a; + Node[] tab; + int idx = 0; + if (size > 0 && (tab = table) != null) { + for (Node e : tab) { + for (; e != null; e = e.next) { + r[idx++] = e.key; + } + } + } + return a; + } + + /** + * Fills an array with this map values and returns it. This method assumes + * that input array is big enough to fit all the values. Use + * {@link #prepareArray(Object[])} to ensure this. + * + * @param a an array to fill + * @param type of array elements + * @return supplied array + */ + T[] valuesToArray(T[] a) { + Object[] r = a; + Node[] tab; + int idx = 0; + if (size > 0 && (tab = table) != null) { + for (Node e : tab) { + for (; e != null; e = e.next) { + r[idx++] = e.value; + } + } + } + return a; + } + @WeakOuter final class KeySet extends AbstractSet { public final int size() { return size; } @@ -928,6 +1004,15 @@ public final boolean remove(Object key) { public final Spliterator spliterator() { return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0); } + + public Object[] toArray() { + return keysToArray(new Object[size]); + } + + public T[] toArray(T[] a) { + return keysToArray(prepareArray(a)); + } + public final void forEach(Consumer action) { Node[] tab; if (action == null) @@ -965,13 +1050,13 @@ public final void forEach(Consumer action) { * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress - * (except through the iterator's own remove operation), + * (except through the iterator's own {@code remove} operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear operations. It does not - * support the add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. * * @return a view of the values contained in this map */ @@ -993,6 +1078,15 @@ final class Values extends AbstractCollection { public final Spliterator spliterator() { return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0); } + + public Object[] toArray() { + return valuesToArray(new Object[size]); + } + + public T[] toArray(T[] a) { + return valuesToArray(prepareArray(a)); + } + public final void forEach(Consumer action) { Node[] tab; if (action == null) @@ -1030,14 +1124,14 @@ public final void forEach(Consumer action) { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation, or through the - * setValue operation on a map entry returned by the + * the iterator's own {@code remove} operation, or through the + * {@code setValue} operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll and - * clear operations. It does not support the - * add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and + * {@code clear} operations. It does not support the + * {@code add} or {@code addAll} operations. * * @return a set view of the mappings contained in this map */ @@ -1054,16 +1148,26 @@ public final Iterator> iterator() { return new EntryIterator(); } public final boolean contains(Object o) { + // BEGIN Android-changed: Patternmatching for instanceof is not available yet. + /* + if (!(o instanceof Map.Entry e)) + */ if (!(o instanceof Map.Entry)) + // END Android-changed: Patternmatching for instanceof is not available yet. return false; Map.Entry e = (Map.Entry) o; Object key = e.getKey(); - Node candidate = getNode(hash(key), key); + Node candidate = getNode(key); return candidate != null && candidate.equals(e); } public final boolean remove(Object o) { + // BEGIN Android-changed: Patternmatching for instanceof is not available yet. + /* + if (o instanceof Map.Entry e) { + */ if (o instanceof Map.Entry) { Map.Entry e = (Map.Entry) o; + // END Android-changed: Patternmatching for instanceof is not available yet. Object key = e.getKey(); Object value = e.getValue(); return removeNode(hash(key), key, value, true, true) != null; @@ -1105,7 +1209,7 @@ public final void forEach(Consumer> action) { @Override public V getOrDefault(Object key, V defaultValue) { Node e; - return (e = getNode(hash(key), key)) == null ? defaultValue : e.value; + return (e = getNode(key)) == null ? defaultValue : e.value; } @Override @@ -1121,7 +1225,7 @@ public boolean remove(Object key, Object value) { @Override public boolean replace(K key, V oldValue, V newValue) { Node e; V v; - if ((e = getNode(hash(key), key)) != null && + if ((e = getNode(key)) != null && ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) { e.value = newValue; afterNodeAccess(e); @@ -1133,7 +1237,7 @@ public boolean replace(K key, V oldValue, V newValue) { @Override public V replace(K key, V value) { Node e; - if ((e = getNode(hash(key), key)) != null) { + if ((e = getNode(key)) != null) { V oldValue = e.value; e.value = value; afterNodeAccess(e); @@ -1142,6 +1246,16 @@ public V replace(K key, V value) { return null; } + /** + * {@inheritDoc} + * + *

    This method will, on a best-effort basis, throw a + * {@link ConcurrentModificationException} if it is detected that the + * mapping function modifies this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * mapping function modified this map + */ @Override public V computeIfAbsent(K key, Function mappingFunction) { @@ -1175,7 +1289,9 @@ public V computeIfAbsent(K key, return oldValue; } } + int mc = modCount; V v = mappingFunction.apply(key); + if (mc != modCount) { throw new ConcurrentModificationException(); } if (v == null) { return null; } else if (old != null) { @@ -1190,32 +1306,56 @@ else if (t != null) if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } - ++modCount; + modCount = mc + 1; ++size; afterNodeInsertion(true); return v; } + /** + * {@inheritDoc} + * + *

    This method will, on a best-effort basis, throw a + * {@link ConcurrentModificationException} if it is detected that the + * remapping function modifies this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * remapping function modified this map + */ + @Override public V computeIfPresent(K key, BiFunction remappingFunction) { if (remappingFunction == null) throw new NullPointerException(); Node e; V oldValue; - int hash = hash(key); - if ((e = getNode(hash, key)) != null && + if ((e = getNode(key)) != null && (oldValue = e.value) != null) { + int mc = modCount; V v = remappingFunction.apply(key, oldValue); + if (mc != modCount) { throw new ConcurrentModificationException(); } if (v != null) { e.value = v; afterNodeAccess(e); return v; } - else + else { + int hash = hash(key); removeNode(hash, key, null, false, true); + } } return null; } + /** + * {@inheritDoc} + * + *

    This method will, on a best-effort basis, throw a + * {@link ConcurrentModificationException} if it is detected that the + * remapping function modifies this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * remapping function modified this map + */ @Override public V compute(K key, BiFunction remappingFunction) { @@ -1245,7 +1385,9 @@ public V compute(K key, } } V oldValue = (old == null) ? null : old.value; + int mc = modCount; V v = remappingFunction.apply(key, oldValue); + if (mc != modCount) { throw new ConcurrentModificationException(); } if (old != null) { if (v != null) { old.value = v; @@ -1262,19 +1404,27 @@ else if (v != null) { if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } - ++modCount; + modCount = mc + 1; ++size; afterNodeInsertion(true); } return v; } + /** + * {@inheritDoc} + * + *

    This method will, on a best-effort basis, throw a + * {@link ConcurrentModificationException} if it is detected that the + * remapping function modifies this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * remapping function modified this map + */ @Override public V merge(K key, V value, BiFunction remappingFunction) { - if (value == null) - throw new NullPointerException(); - if (remappingFunction == null) + if (value == null || remappingFunction == null) throw new NullPointerException(); int hash = hash(key); Node[] tab; Node first; int n, i; @@ -1301,10 +1451,15 @@ public V merge(K key, V value, } if (old != null) { V v; - if (old.value != null) + if (old.value != null) { + int mc = modCount; v = remappingFunction.apply(old.value, value); - else + if (mc != modCount) { + throw new ConcurrentModificationException(); + } + } else { v = value; + } if (v != null) { old.value = v; afterNodeAccess(old); @@ -1312,8 +1467,7 @@ public V merge(K key, V value, else removeNode(hash, key, null, false, true); return v; - } - if (value != null) { + } else { if (t != null) t.putTreeVal(this, tab, hash, key, value); else { @@ -1324,8 +1478,8 @@ public V merge(K key, V value, ++modCount; ++size; afterNodeInsertion(true); + return value; } - return value; } @Override @@ -1352,8 +1506,8 @@ public void replaceAll(BiFunction function) { throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; - for (int i = 0; i < tab.length; ++i) { - for (Node e = tab[i]; e != null; e = e.next) { + for (Node e : tab) { + for (; e != null; e = e.next) { e.value = function.apply(e.key, e.value); } } @@ -1366,7 +1520,7 @@ public void replaceAll(BiFunction function) { // Cloning and serialization /** - * Returns a shallow copy of this HashMap instance: the keys and + * Returns a shallow copy of this {@code HashMap} instance: the keys and * values themselves are not cloned. * * @return a shallow copy of this map @@ -1395,9 +1549,10 @@ final int capacity() { } /** - * Save the state of the HashMap instance to a stream (i.e., - * serialize it). + * Saves this map to a stream (that is, serializes it). * + * @param s the stream + * @throws IOException if an I/O error occurs * @serialData The capacity of the HashMap (the length of the * bucket array) is emitted (int), followed by the * size (an int, the number of key-value @@ -1405,6 +1560,7 @@ final int capacity() { * for each key-value mapping. The key-value mappings are * emitted in no particular order. */ + @java.io.Serial private void writeObject(java.io.ObjectOutputStream s) throws IOException { int buckets = capacity(); @@ -1446,7 +1602,7 @@ else if (mappings > 0) { // (if zero, use defaults) threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? (int)ft : Integer.MAX_VALUE); @SuppressWarnings({"rawtypes","unchecked"}) - Node[] tab = (Node[])new Node[cap]; + Node[] tab = (Node[])new Node[cap]; table = tab; // Read the keys and values, and put the mappings in the HashMap @@ -1504,8 +1660,7 @@ public final void remove() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); current = null; - K key = p.key; - removeNode(hash(key), key, null, false, false); + removeNode(p.hash, p.key, null, false, false); expectedModCount = modCount; } } @@ -1833,8 +1988,8 @@ void afterNodeRemoval(Node p) { } void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { Node[] tab; if (size > 0 && (tab = table) != null) { - for (int i = 0; i < tab.length; ++i) { - for (Node e = tab[i]; e != null; e = e.next) { + for (Node e : tab) { + for (; e != null; e = e.next) { s.writeObject(e.key); s.writeObject(e.value); } @@ -1954,7 +2109,6 @@ static int tieBreakOrder(Object a, Object b) { /** * Forms tree of the nodes linked from this node. - * @return root of tree */ final void treeify(Node[] tab) { TreeNode root = null; @@ -2092,8 +2246,11 @@ final void removeTreeNode(HashMap map, Node[] tab, return; if (root.parent != null) root = root.root(); - if (root == null || root.right == null || - (rl = root.left) == null || rl.left == null) { + if (root == null + || (movable + && (root.right == null + || (rl = root.left) == null + || rl.left == null))) { tab[index] = first.untreeify(map); // too small return; } @@ -2145,7 +2302,7 @@ else if (pr != null) if (replacement != p) { TreeNode pp = replacement.parent = p.parent; if (pp == null) - root = replacement; + (root = replacement).red = false; else if (p == pp.left) pp.left = replacement; else @@ -2322,7 +2479,7 @@ else if (!xp.red || (xpp = xp.parent) == null) static TreeNode balanceDeletion(TreeNode root, TreeNode x) { - for (TreeNode xp, xpl, xpr;;) { + for (TreeNode xp, xpl, xpr;;) { if (x == null || x == root) return root; else if ((xp = x.parent) == null) { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashSet.java index 588cd4a969..c276411d40 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/HashSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, 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 @@ -25,19 +25,21 @@ package java.util; +import java.io.InvalidObjectException; + /** - * This class implements the Set interface, backed by a hash table - * (actually a HashMap instance). It makes no guarantees as to the + * This class implements the {@code Set} interface, backed by a hash table + * (actually a {@code HashMap} instance). It makes no guarantees as to the * iteration order of the set; in particular, it does not guarantee that the - * order will remain constant over time. This class permits the null + * order will remain constant over time. This class permits the {@code null} * element. * *

    This class offers constant time performance for the basic operations - * (add, remove, contains and size), + * ({@code add}, {@code remove}, {@code contains} and {@code size}), * assuming the hash function disperses the elements properly among the * buckets. Iterating over this set requires time proportional to the sum of - * the HashSet instance's size (the number of elements) plus the - * "capacity" of the backing HashMap instance (the number of + * the {@code HashSet} instance's size (the number of elements) plus the + * "capacity" of the backing {@code HashMap} instance (the number of * buckets). Thus, it's very important not to set the initial capacity too * high (or the load factor too low) if iteration performance is important. * @@ -53,9 +55,9 @@ * unsynchronized access to the set:

      *   Set s = Collections.synchronizedSet(new HashSet(...));
    * - *

    The iterators returned by this class's iterator method are + *

    The iterators returned by this class's {@code iterator} method are * fail-fast: if the set is modified at any time after the iterator is - * created, in any way except through the iterator's own remove + * created, in any way except through the iterator's own {@code remove} * method, the Iterator throws a {@link ConcurrentModificationException}. * Thus, in the face of concurrent modification, the iterator fails quickly * and cleanly, rather than risking arbitrary, non-deterministic behavior at @@ -64,13 +66,13 @@ *

    Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. * *

    This class is a member of the - * + * * Java Collections Framework. * * @param the type of elements maintained by this set @@ -96,7 +98,7 @@ public class HashSet private static final Object PRESENT = new Object(); /** - * Constructs a new, empty set; the backing HashMap instance has + * Constructs a new, empty set; the backing {@code HashMap} instance has * default initial capacity (16) and load factor (0.75). */ public HashSet() { @@ -105,7 +107,7 @@ public HashSet() { /** * Constructs a new set containing the elements in the specified - * collection. The HashMap is created with default load factor + * collection. The {@code HashMap} is created with default load factor * (0.75) and an initial capacity sufficient to contain the elements in * the specified collection. * @@ -118,7 +120,7 @@ public HashSet(Collection c) { } /** - * Constructs a new, empty set; the backing HashMap instance has + * Constructs a new, empty set; the backing {@code HashMap} instance has * the specified initial capacity and the specified load factor. * * @param initialCapacity the initial capacity of the hash map @@ -131,7 +133,7 @@ public HashSet(int initialCapacity, float loadFactor) { } /** - * Constructs a new, empty set; the backing HashMap instance has + * Constructs a new, empty set; the backing {@code HashMap} instance has * the specified initial capacity and default load factor (0.75). * * @param initialCapacity the initial capacity of the hash table @@ -180,22 +182,22 @@ public int size() { } /** - * Returns true if this set contains no elements. + * Returns {@code true} if this set contains no elements. * - * @return true if this set contains no elements + * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return map.isEmpty(); } /** - * Returns true if this set contains the specified element. - * More formally, returns true if and only if this set - * contains an element e such that - * (o==null ? e==null : o.equals(e)). + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that + * {@code Objects.equals(o, e)}. * * @param o element whose presence in this set is to be tested - * @return true if this set contains the specified element + * @return {@code true} if this set contains the specified element */ public boolean contains(Object o) { return map.containsKey(o); @@ -203,14 +205,14 @@ public boolean contains(Object o) { /** * Adds the specified element to this set if it is not already present. - * More formally, adds the specified element e to this set if - * this set contains no element e2 such that - * (e==null ? e2==null : e.equals(e2)). + * More formally, adds the specified element {@code e} to this set if + * this set contains no element {@code e2} such that + * {@code Objects.equals(e, e2)}. * If this set already contains the element, the call leaves the set - * unchanged and returns false. + * unchanged and returns {@code false}. * * @param e element to be added to this set - * @return true if this set did not already contain the specified + * @return {@code true} if this set did not already contain the specified * element */ public boolean add(E e) { @@ -219,15 +221,15 @@ public boolean add(E e) { /** * Removes the specified element from this set if it is present. - * More formally, removes an element e such that - * (o==null ? e==null : o.equals(e)), - * if this set contains such an element. Returns true if + * More formally, removes an element {@code e} such that + * {@code Objects.equals(o, e)}, + * if this set contains such an element. Returns {@code true} if * this set contained the element (or equivalently, if this set * changed as a result of the call). (This set will not contain the * element once the call returns.) * * @param o object to be removed from this set, if present - * @return true if the set contained the specified element + * @return {@code true} if the set contained the specified element */ public boolean remove(Object o) { return map.remove(o)==PRESENT; @@ -242,26 +244,27 @@ public void clear() { } /** - * Returns a shallow copy of this HashSet instance: the elements + * Returns a shallow copy of this {@code HashSet} instance: the elements * themselves are not cloned. * * @return a shallow copy of this set */ + @SuppressWarnings("unchecked") public Object clone() { try { HashSet newSet = (HashSet) super.clone(); newSet.map = (HashMap) map.clone(); return newSet; } catch (CloneNotSupportedException e) { - throw new InternalError(); + throw new InternalError(e); } } /** - * Save the state of this HashSet instance to a stream (that is, + * Save the state of this {@code HashSet} instance to a stream (that is, * serialize it). * - * @serialData The capacity of the backing HashMap instance + * @serialData The capacity of the backing {@code HashMap} instance * (int), and its load factor (float) are emitted, followed by * the size of the set (the number of elements it contains) * (int), followed by all of its elements (each an Object) in @@ -285,7 +288,7 @@ private void writeObject(java.io.ObjectOutputStream s) } /** - * Reconstitute the HashSet instance from a stream (that is, + * Reconstitute the {@code HashSet} instance from a stream (that is, * deserialize it). */ private void readObject(java.io.ObjectInputStream s) @@ -323,7 +326,7 @@ private void readObject(java.io.ObjectInputStream s) * @since 1.8 */ public Spliterator spliterator() { - return new HashMap.KeySpliterator(map, 0, -1, 0, 0); + return new HashMap.KeySpliterator<>(map, 0, -1, 0, 0); } /*-[ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Hashtable.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Hashtable.java index 7af5bd22ec..4e57cc1ace 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Hashtable.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Hashtable.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2018, 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 @@ -39,13 +39,13 @@ /** * This class implements a hash table, which maps keys to values. Any - * non-null object can be used as a key or as a value.

    + * non-{@code null} object can be used as a key or as a value.

    * * To successfully store and retrieve objects from a hashtable, the - * objects used as keys must implement the hashCode - * method and the equals method.

    + * objects used as keys must implement the {@code hashCode} + * method and the {@code equals} method.

    * - * An instance of Hashtable has two parameters that affect its + * An instance of {@code Hashtable} has two parameters that affect its * performance: initial capacity and load factor. The * capacity is the number of buckets in the hash table, and the * initial capacity is simply the capacity at the time the hash table @@ -60,16 +60,16 @@ * Generally, the default load factor (.75) offers a good tradeoff between * time and space costs. Higher values decrease the space overhead but * increase the time cost to look up an entry (which is reflected in most - * Hashtable operations, including get and put).

    + * {@code Hashtable} operations, including {@code get} and {@code put}).

    * * The initial capacity controls a tradeoff between wasted space and the - * need for rehash operations, which are time-consuming. - * No rehash operations will ever occur if the initial + * need for {@code rehash} operations, which are time-consuming. + * No {@code rehash} operations will ever occur if the initial * capacity is greater than the maximum number of entries the - * Hashtable will contain divided by its load factor. However, + * {@code Hashtable} will contain divided by its load factor. However, * setting the initial capacity too high can waste space.

    * - * If many entries are to be made into a Hashtable, + * If many entries are to be made into a {@code Hashtable}, * creating it with a sufficiently large capacity may allow the * entries to be inserted more efficiently than letting it perform * automatic rehashing as needed to grow the table.

    @@ -90,28 +90,30 @@ * System.out.println("two = " + n); * }} * - *

    The iterators returned by the iterator method of the collections + *

    The iterators returned by the {@code iterator} method of the collections * returned by all of this class's "collection view methods" are * fail-fast: if the Hashtable is structurally modified at any time * after the iterator is created, in any way except through the iterator's own - * remove method, the iterator will throw a {@link + * {@code remove} method, the iterator will throw a {@link * ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than risking * arbitrary, non-deterministic behavior at an undetermined time in the future. - * The Enumerations returned by Hashtable's keys and elements methods are - * not fail-fast. + * The Enumerations returned by Hashtable's {@link #keys keys} and + * {@link #elements elements} methods are not fail-fast; if the + * Hashtable is structurally modified at any time after the enumeration is + * created then the results of enumerating are undefined. * *

    Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. * *

    As of the Java 2 platform v1.2, this class was retrofitted to * implement the {@link Map} interface, making it a member of the - * + * * * Java Collections Framework. Unlike the new collection * implementations, {@code Hashtable} is synchronized. If a @@ -121,6 +123,9 @@ * to use {@link java.util.concurrent.ConcurrentHashMap} in place of * {@code Hashtable}. * + * @param the type of keys maintained by this map + * @param the type of mapped values + * * @author Arthur van Hoff * @author Josh Bloch * @author Neal Gafter @@ -131,7 +136,7 @@ * @see Map * @see HashMap * @see TreeMap - * @since JDK1.0 + * @since 1.0 */ public class Hashtable extends Dictionary @@ -233,6 +238,14 @@ public Hashtable(Map t) { putAll(t); } + /** + * A constructor chained from {@link Properties} keeps Hashtable fields + * uninitialized since they are not used. + * + * @param dummy a dummy parameter + */ + Hashtable(Void dummy) {} + /** * Returns the number of keys in this hashtable. * @@ -245,8 +258,8 @@ public synchronized int size() { /** * Tests if this hashtable maps no keys to values. * - * @return true if this hashtable maps no keys to values; - * false otherwise. + * @return {@code true} if this hashtable maps no keys to values; + * {@code false} otherwise. */ public synchronized boolean isEmpty() { return count == 0; @@ -254,6 +267,9 @@ public synchronized boolean isEmpty() { /** * Returns an enumeration of the keys in this hashtable. + * Use the Enumeration methods on the returned object to fetch the keys + * sequentially. If the hashtable is structurally modified while enumerating + * over the keys then the results of enumerating are undefined. * * @return an enumeration of the keys in this hashtable. * @see Enumeration @@ -268,7 +284,8 @@ public synchronized Enumeration keys() { /** * Returns an enumeration of the values in this hashtable. * Use the Enumeration methods on the returned object to fetch the elements - * sequentially. + * sequentially. If the hashtable is structurally modified while enumerating + * over the values then the results of enumerating are undefined. * * @return an enumeration of the values in this hashtable. * @see java.util.Enumeration @@ -290,11 +307,11 @@ public synchronized Enumeration elements() { * {@link Map} interface in the collections framework). * * @param value a value to search for - * @return true if and only if some key maps to the - * value argument in this hashtable as - * determined by the equals method; - * false otherwise. - * @exception NullPointerException if the value is null + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this hashtable as + * determined by the {@code equals} method; + * {@code false} otherwise. + * @exception NullPointerException if the value is {@code null} */ public synchronized boolean contains(Object value) { if (value == null) { @@ -319,9 +336,9 @@ public synchronized boolean contains(Object value) { * #contains contains} (which predates the {@link Map} interface). * * @param value value whose presence in this hashtable is to be tested - * @return true if this map maps one or more keys to the + * @return {@code true} if this map maps one or more keys to the * specified value - * @throws NullPointerException if the value is null + * @throws NullPointerException if the value is {@code null} * @since 1.2 */ public boolean containsValue(Object value) { @@ -332,10 +349,10 @@ public boolean containsValue(Object value) { * Tests if the specified object is a key in this hashtable. * * @param key possible key - * @return true if and only if the specified object + * @return {@code true} if and only if the specified object * is a key in this hashtable, as determined by the - * equals method; false otherwise. - * @throws NullPointerException if the key is null + * {@code equals} method; {@code false} otherwise. + * @throws NullPointerException if the key is {@code null} * @see #contains(Object) */ public synchronized boolean containsKey(Object key) { @@ -425,8 +442,6 @@ protected void rehash() { } private void addEntry(int hash, K key, V value, int index) { - modCount++; - HashtableEntry tab[] = table; if (count >= threshold) { // Rehash the table if the threshold is exceeded @@ -442,22 +457,23 @@ private void addEntry(int hash, K key, V value, int index) { HashtableEntry e = (HashtableEntry) tab[index]; tab[index] = new HashtableEntry<>(hash, key, value, e); count++; + modCount++; } /** - * Maps the specified key to the specified - * value in this hashtable. Neither the key nor the - * value can be null.

    + * Maps the specified {@code key} to the specified + * {@code value} in this hashtable. Neither the key nor the + * value can be {@code null}.

    * - * The value can be retrieved by calling the get method + * The value can be retrieved by calling the {@code get} method * with a key that is equal to the original key. * * @param key the hashtable key * @param value the value * @return the previous value of the specified key in this hashtable, - * or null if it did not have one + * or {@code null} if it did not have one * @exception NullPointerException if the key or value is - * null + * {@code null} * @see Object#equals(Object) * @see #get(Object) */ @@ -491,8 +507,8 @@ public synchronized V put(K key, V value) { * * @param key the key that needs to be removed * @return the value to which the key had been mapped in this hashtable, - * or null if the key did not have a mapping - * @throws NullPointerException if the key is null + * or {@code null} if the key did not have a mapping + * @throws NullPointerException if the key is {@code null} */ public synchronized V remove(Object key) { HashtableEntry tab[] = table; @@ -502,12 +518,12 @@ public synchronized V remove(Object key) { HashtableEntry e = (HashtableEntry)tab[index]; for(HashtableEntry prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { - modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } + modCount++; count--; V oldValue = e.value; e.value = null; @@ -536,9 +552,9 @@ public synchronized void putAll(Map t) { */ public synchronized void clear() { HashtableEntry tab[] = table; - modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; + modCount++; count = 0; } @@ -550,18 +566,23 @@ public synchronized void clear() { * @return a clone of the hashtable */ public synchronized Object clone() { + Hashtable t = cloneHashtable(); + t.table = new HashtableEntry[table.length]; + for (int i = table.length ; i-- > 0 ; ) { + t.table[i] = (table[i] != null) + ? (HashtableEntry) table[i].clone() : null; + } + t.keySet = null; + t.entrySet = null; + t.values = null; + t.modCount = 0; + return t; + } + + /** Calls super.clone() */ + final Hashtable cloneHashtable() { try { - Hashtable t = (Hashtable)super.clone(); - t.table = new HashtableEntry[table.length]; - for (int i = table.length ; i-- > 0 ; ) { - t.table[i] = (table[i] != null) - ? (HashtableEntry) table[i].clone() : null; - } - t.keySet = null; - t.entrySet = null; - t.values = null; - t.modCount = 0; - return t; + return (Hashtable)super.clone(); } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); @@ -569,11 +590,11 @@ public synchronized Object clone() { } /** - * Returns a string representation of this Hashtable object + * Returns a string representation of this {@code Hashtable} object * in the form of a set of entries, enclosed in braces and separated - * by the ASCII characters "" (comma and space). Each - * entry is rendered as the key, an equals sign =, and the - * associated element, where the toString method is used to + * by the ASCII characters "" (comma and space). Each + * entry is rendered as the key, an equals sign {@code =}, and the + * associated element, where the {@code toString} method is used to * convert the key and element to strings. * * @return a string representation of this hashtable @@ -634,12 +655,12 @@ private Iterator getIterator(int type) { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation), the results of + * the iterator's own {@code remove} operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the - * Iterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or addAll + * {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} * operations. * * @since 1.2 @@ -682,14 +703,14 @@ public void clear() { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation, or through the - * setValue operation on a map entry returned by the + * the iterator's own {@code remove} operation, or through the + * {@code setValue} operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll and - * clear operations. It does not support the - * add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and + * {@code clear} operations. It does not support the + * {@code add} or {@code addAll} operations. * * @since 1.2 */ @@ -779,13 +800,13 @@ public void clear() { * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress - * (except through the iterator's own remove operation), + * (except through the iterator's own {@code remove} operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear operations. It does not - * support the add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. * * @since 1.2 */ @@ -842,13 +863,11 @@ public synchronized boolean equals(Object o) { return false; try { - Iterator> i = entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = i.next(); + for (Map.Entry e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { - if (!(t.get(key)==null && t.containsKey(key))) + if (!(t.get(key) == null && t.containsKey(key))) return false; } else { if (!value.equals(t.get(key))) @@ -982,14 +1001,14 @@ public synchronized boolean remove(Object key, Object value) { HashtableEntry e = (HashtableEntry)tab[index]; for (HashtableEntry prev = null; e != null; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) { - modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } + e.value = null; // clear for gc + modCount++; count--; - e.value = null; return true; } } @@ -1036,6 +1055,16 @@ public synchronized V replace(K key, V value) { return null; } + /** + * {@inheritDoc} + * + *

    This method will, on a best-effort basis, throw a + * {@link java.util.ConcurrentModificationException} if the mapping + * function modified this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * mapping function modified this map + */ @Override public synchronized V computeIfAbsent(K key, Function mappingFunction) { Objects.requireNonNull(mappingFunction); @@ -1052,7 +1081,9 @@ public synchronized V computeIfAbsent(K key, Function ma } } + int mc = modCount; V newValue = mappingFunction.apply(key); + if (mc != modCount) { throw new ConcurrentModificationException(); } if (newValue != null) { addEntry(hash, key, newValue, index); } @@ -1060,6 +1091,16 @@ public synchronized V computeIfAbsent(K key, Function ma return newValue; } + /** + * {@inheritDoc} + * + *

    This method will, on a best-effort basis, throw a + * {@link java.util.ConcurrentModificationException} if the remapping + * function modified this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * remapping function modified this map + */ @Override public synchronized V computeIfPresent(K key, BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); @@ -1071,14 +1112,18 @@ public synchronized V computeIfPresent(K key, BiFunction e = (HashtableEntry)tab[index]; for (HashtableEntry prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { + int mc = modCount; V newValue = remappingFunction.apply(key, e.value); + if (mc != modCount) { + throw new ConcurrentModificationException(); + } if (newValue == null) { - modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } + modCount = mc + 1; count--; } else { e.value = newValue; @@ -1088,7 +1133,16 @@ public synchronized V computeIfPresent(K key, BiFunctionThis method will, on a best-effort basis, throw a + * {@link java.util.ConcurrentModificationException} if the remapping + * function modified this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * remapping function modified this map + */ @Override public synchronized V compute(K key, BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); @@ -1100,14 +1154,18 @@ public synchronized V compute(K key, BiFunction e = (HashtableEntry)tab[index]; for (HashtableEntry prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && Objects.equals(e.key, key)) { + int mc = modCount; V newValue = remappingFunction.apply(key, e.value); + if (mc != modCount) { + throw new ConcurrentModificationException(); + } if (newValue == null) { - modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } + modCount = mc + 1; count--; } else { e.value = newValue; @@ -1116,7 +1174,9 @@ public synchronized V compute(K key, BiFunctionThis method will, on a best-effort basis, throw a + * {@link java.util.ConcurrentModificationException} if the remapping + * function modified this map during computation. + * + * @throws ConcurrentModificationException if it is detected that the + * remapping function modified this map + */ @Override public synchronized V merge(K key, V value, BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); @@ -1135,14 +1205,18 @@ public synchronized V merge(K key, V value, BiFunction e = (HashtableEntry)tab[index]; for (HashtableEntry prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { + int mc = modCount; V newValue = remappingFunction.apply(e.value, value); + if (mc != modCount) { + throw new ConcurrentModificationException(); + } if (newValue == null) { - modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } + modCount = mc + 1; count--; } else { e.value = newValue; @@ -1170,6 +1244,15 @@ public synchronized V merge(K key, V value, BiFunction entryStack = null; synchronized (this) { @@ -1181,8 +1264,7 @@ private void writeObject(java.io.ObjectOutputStream s) s.writeInt(count); // Stack copies of the entries in the table - for (int index = 0; index < table.length; index++) { - HashtableEntry entry = table[index]; + for (HashtableEntry entry : table) { while (entry != null) { entryStack = @@ -1200,12 +1282,32 @@ private void writeObject(java.io.ObjectOutputStream s) } } + /** + * Called by Properties to write out a simulated threshold and loadfactor. + */ + final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length, + float loadFactor) throws IOException { + // Android-changed: Ignore loadFactor when calculating threshold from initialCapacity + // this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); + this.threshold = (int)Math.min(length, MAX_ARRAY_SIZE + 1); + this.loadFactor = loadFactor; + s.defaultWriteObject(); + } + /** * Reconstitute the Hashtable from a stream (i.e., deserialize it). */ private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException - { + throws IOException, ClassNotFoundException { + readHashtable(s); + } + + /** + * Perform deserialization of the Hashtable from an ObjectInputStream. + * The Properties class overrides this method. + */ + void readHashtable(java.io.ObjectInputStream s) + throws IOException, ClassNotFoundException { // Read in the threshold and loadFactor s.defaultReadObject(); @@ -1233,6 +1335,16 @@ private void readObject(java.io.ObjectInputStream s) if (length > elements && (length & 1) == 0) length--; length = Math.min(length, origlength); + + if (length < 0) { // overflow + length = origlength; + } + + // Check Map.Entry[].class since it's the nearest public type to + // what we're actually creating. + /* J2ObjC removed + SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length); + */ table = new HashtableEntry[length]; threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); count = 0; @@ -1374,20 +1486,20 @@ private class Enumerator implements Enumeration, Iterator { int index = table.length; HashtableEntry entry; HashtableEntry lastReturned; - int type; + final int type; /** * Indicates whether this Enumerator is serving as an Iterator * or an Enumeration. (true -> Iterator). */ - boolean iterator; + final boolean iterator; /** * The modCount value that the iterator believes that the backing * Hashtable should have. If this expectation is violated, the iterator * has detected concurrent modification. */ - protected int expectedModCount = modCount; + protected int expectedModCount = Hashtable.this.modCount; Enumerator(int type, boolean iterator) { this.type = type; @@ -1432,7 +1544,7 @@ public boolean hasNext() { } public T next() { - if (modCount != expectedModCount) + if (Hashtable.this.modCount != expectedModCount) throw new ConcurrentModificationException(); return nextElement(); } @@ -1453,14 +1565,14 @@ public void remove() { HashtableEntry e = (HashtableEntry)tab[index]; for(HashtableEntry prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { - modCount++; - expectedModCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; - count--; + expectedModCount++; lastReturned = null; + Hashtable.this.modCount++; + Hashtable.this.count--; return; } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IdentityHashMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IdentityHashMap.java index 07df6b6907..3f222e51a4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IdentityHashMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IdentityHashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -37,18 +37,18 @@ ]-*/ /** - * This class implements the Map interface with a hash table, using + * This class implements the {@code Map} interface with a hash table, using * reference-equality in place of object-equality when comparing keys (and - * values). In other words, in an IdentityHashMap, two keys - * k1 and k2 are considered equal if and only if - * (k1==k2). (In normal Map implementations (like - * HashMap) two keys k1 and k2 are considered equal - * if and only if (k1==null ? k2==null : k1.equals(k2)).) + * values). In other words, in an {@code IdentityHashMap}, two keys + * {@code k1} and {@code k2} are considered equal if and only if + * {@code (k1==k2)}. (In normal {@code Map} implementations (like + * {@code HashMap}) two keys {@code k1} and {@code k2} are considered equal + * if and only if {@code (k1==null ? k2==null : k1.equals(k2))}.) * - *

    This class is not a general-purpose Map - * implementation! While this class implements the Map interface, it - * intentionally violates Map's general contract, which mandates the - * use of the equals method when comparing objects. This class is + *

    This class is not a general-purpose {@code Map} + * implementation! While this class implements the {@code Map} interface, it + * intentionally violates {@code Map's} general contract, which mandates the + * use of the {@code equals} method when comparing objects. This class is * designed for use only in the rare cases wherein reference-equality * semantics are required. * @@ -62,12 +62,12 @@ * each object in the program being debugged. * *

    This class provides all of the optional map operations, and permits - * null values and the null key. This class makes no + * {@code null} values and the {@code null} key. This class makes no * guarantees as to the order of the map; in particular, it does not guarantee * that the order will remain constant over time. * *

    This class provides constant-time performance for the basic - * operations (get and put), assuming the system + * operations ({@code get} and {@code put}), assuming the system * identity hash function ({@link System#identityHashCode(Object)}) * disperses elements properly among the buckets. * @@ -102,11 +102,11 @@ * unsynchronized access to the map:

      *   Map m = Collections.synchronizedMap(new IdentityHashMap(...));
    * - *

    The iterators returned by the iterator method of the + *

    The iterators returned by the {@code iterator} method of the * collections returned by all of this class's "collection view * methods" are fail-fast: if the map is structurally modified * at any time after the iterator is created, in any way except - * through the iterator's own remove method, the iterator + * through the iterator's own {@code remove} method, the iterator * will throw a {@link ConcurrentModificationException}. Thus, in the * face of concurrent modification, the iterator fails quickly and * cleanly, rather than risking arbitrary, non-deterministic behavior @@ -115,7 +115,7 @@ *

    Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: fail-fast iterators should be used only * to detect bugs. @@ -128,7 +128,7 @@ * {@link HashMap} (which uses chaining rather than linear-probing). * *

    This class is a member of the - * + * * Java Collections Framework. * * @see System#identityHashCode(Object) @@ -223,7 +223,7 @@ public IdentityHashMap() { * somewhat time-consuming. * * @param expectedMaxSize the expected maximum size of the map - * @throws IllegalArgumentException if expectedMaxSize is negative + * @throws IllegalArgumentException if {@code expectedMaxSize} is negative */ public IdentityHashMap(int expectedMaxSize) { if (expectedMaxSize < 0) @@ -283,10 +283,10 @@ public int size() { } /** - * Returns true if this identity hash map contains no key-value + * Returns {@code true} if this identity hash map contains no key-value * mappings. * - * @return true if this identity hash map contains no key-value + * @return {@code true} if this identity hash map contains no key-value * mappings */ public boolean isEmpty() { @@ -347,7 +347,7 @@ public V get(Object key) { * hash map. * * @param key possible key - * @return true if the specified object reference is a key + * @return {@code true} if the specified object reference is a key * in this map * @see #containsValue(Object) */ @@ -371,7 +371,7 @@ public boolean containsKey(Object key) { * hash map. * * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the + * @return {@code true} if this map maps one or more keys to the * specified object reference * @see #containsKey(Object) */ @@ -389,7 +389,7 @@ public boolean containsValue(Object value) { * * @param key possible key * @param value possible value - * @return true if and only if the specified key-value + * @return {@code true} if and only if the specified key-value * mapping is in the map */ private boolean containsMapping(Object key, Object value) { @@ -414,10 +414,10 @@ private boolean containsMapping(Object key, Object value) { * * @param key the key with which the specified value is to be associated * @param value the value to be associated with the specified key - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) * @see Object#equals(Object) * @see #get(Object) * @see #containsKey(Object) @@ -516,10 +516,10 @@ public void putAll(Map m) { * Removes the mapping for this key from this map if present. * * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) */ public V remove(Object key) { Object k = maskNull(key); @@ -550,7 +550,7 @@ public V remove(Object key) { * * @param key possible key * @param value possible value - * @return true if and only if the specified key-value + * @return {@code true} if and only if the specified key-value * mapping was in the map */ private boolean removeMapping(Object key, Object value) { @@ -627,19 +627,19 @@ public void clear() { /** * Compares the specified object with this map for equality. Returns - * true if the given object is also a map and the two maps + * {@code true} if the given object is also a map and the two maps * represent identical object-reference mappings. More formally, this - * map is equal to another map m if and only if - * this.entrySet().equals(m.entrySet()). + * map is equal to another map {@code m} if and only if + * {@code this.entrySet().equals(m.entrySet())}. * *

    Owing to the reference-equality-based semantics of this map it is * possible that the symmetry and transitivity requirements of the - * Object.equals contract may be violated if this map is compared - * to a normal map. However, the Object.equals contract is - * guaranteed to hold among IdentityHashMap instances. + * {@code Object.equals} contract may be violated if this map is compared + * to a normal map. However, the {@code Object.equals} contract is + * guaranteed to hold among {@code IdentityHashMap} instances. * * @param o object to be compared for equality with this map - * @return true if the specified object is equal to this map + * @return {@code true} if the specified object is equal to this map * @see Object#equals(Object) */ public boolean equals(Object o) { @@ -668,17 +668,17 @@ public boolean equals(Object o) { /** * Returns the hash code value for this map. The hash code of a map is * defined to be the sum of the hash codes of each entry in the map's - * entrySet() view. This ensures that m1.equals(m2) - * implies that m1.hashCode()==m2.hashCode() for any two - * IdentityHashMap instances m1 and m2, as + * {@code entrySet()} view. This ensures that {@code m1.equals(m2)} + * implies that {@code m1.hashCode()==m2.hashCode()} for any two + * {@code IdentityHashMap} instances {@code m1} and {@code m2}, as * required by the general contract of {@link Object#hashCode}. * *

    Owing to the reference-equality-based semantics of the - * Map.Entry instances in the set returned by this map's - * entrySet method, it is possible that the contractual - * requirement of Object.hashCode mentioned in the previous + * {@code Map.Entry} instances in the set returned by this map's + * {@code entrySet} method, it is possible that the contractual + * requirement of {@code Object.hashCode} mentioned in the previous * paragraph will be violated if one of the two objects being compared is - * an IdentityHashMap instance and the other is a normal map. + * an {@code IdentityHashMap} instance and the other is a normal map. * * @return the hash code value for this map * @see Object#equals(Object) @@ -932,7 +932,7 @@ private void checkIndexForEntryUse() { * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns an identity-based set view of the keys contained in this map. @@ -940,32 +940,32 @@ private void checkIndexForEntryUse() { * the set, and vice-versa. If the map is modified while an iteration * over the set is in progress, the results of the iteration are * undefined. The set supports element removal, which removes the - * corresponding mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll, and - * clear methods. It does not support the add or - * addAll methods. + * corresponding mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll}, and + * {@code clear} methods. It does not support the {@code add} or + * {@code addAll} methods. * *

    While the object returned by this method implements the - * Set interface, it does not obey Set's general + * {@code Set} interface, it does not obey {@code Set's} general * contract. Like its backing map, the set returned by this method * defines element equality as reference-equality rather than - * object-equality. This affects the behavior of its contains, - * remove, containsAll, equals, and - * hashCode methods. + * object-equality. This affects the behavior of its {@code contains}, + * {@code remove}, {@code containsAll}, {@code equals}, and + * {@code hashCode} methods. * - *

    The equals method of the returned set returns true + *

    The {@code equals} method of the returned set returns {@code true} * only if the specified object is a set containing exactly the same * object references as the returned set. The symmetry and transitivity - * requirements of the Object.equals contract may be violated if + * requirements of the {@code Object.equals} contract may be violated if * the set returned by this method is compared to a normal set. However, - * the Object.equals contract is guaranteed to hold among sets + * the {@code Object.equals} contract is guaranteed to hold among sets * returned by this method. * - *

    The hashCode method of the returned set returns the sum of + *

    The {@code hashCode} method of the returned set returns the sum of * the identity hashcodes of the elements in the set, rather than * the sum of their hashcodes. This is mandated by the change in the - * semantics of the equals method, in order to enforce the - * general contract of the Object.hashCode method among sets + * semantics of the {@code equals} method, in order to enforce the + * general contract of the {@code Object.hashCode} method among sets * returned by this method. * * @return an identity-based set view of the keys contained in this map @@ -1068,18 +1068,18 @@ public Spliterator spliterator() { * modified while an iteration over the collection is in progress, * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear methods. It does not - * support the add or addAll methods. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} methods. It does not + * support the {@code add} or {@code addAll} methods. * *

    While the object returned by this method implements the - * Collection interface, it does not obey - * Collection's general contract. Like its backing map, + * {@code Collection} interface, it does not obey + * {@code Collection's} general contract. Like its backing map, * the collection returned by this method defines element equality as * reference-equality rather than object-equality. This affects the - * behavior of its contains, remove and - * containsAll methods. + * behavior of its {@code contains}, {@code remove} and + * {@code containsAll} methods. */ public Collection values() { Collection vs = values; @@ -1154,36 +1154,36 @@ public Spliterator spliterator() { /** * Returns a {@link Set} view of the mappings contained in this map. * Each element in the returned set is a reference-equality-based - * Map.Entry. The set is backed by the map, so changes + * {@code Map.Entry}. The set is backed by the map, so changes * to the map are reflected in the set, and vice-versa. If the * map is modified while an iteration over the set is in progress, * the results of the iteration are undefined. The set supports * element removal, which removes the corresponding mapping from - * the map, via the Iterator.remove, Set.remove, - * removeAll, retainAll and clear - * methods. It does not support the add or - * addAll methods. + * the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll} and {@code clear} + * methods. It does not support the {@code add} or + * {@code addAll} methods. * - *

    Like the backing map, the Map.Entry objects in the set + *

    Like the backing map, the {@code Map.Entry} objects in the set * returned by this method define key and value equality as * reference-equality rather than object-equality. This affects the - * behavior of the equals and hashCode methods of these - * Map.Entry objects. A reference-equality based Map.Entry - * e is equal to an object o if and only if o is a - * Map.Entry and e.getKey()==o.getKey() && - * e.getValue()==o.getValue(). To accommodate these equals - * semantics, the hashCode method returns - * System.identityHashCode(e.getKey()) ^ - * System.identityHashCode(e.getValue()). + * behavior of the {@code equals} and {@code hashCode} methods of these + * {@code Map.Entry} objects. A reference-equality based {@code Map.Entry + * e} is equal to an object {@code o} if and only if {@code o} is a + * {@code Map.Entry} and {@code e.getKey()==o.getKey() && + * e.getValue()==o.getValue()}. To accommodate these equals + * semantics, the {@code hashCode} method returns + * {@code System.identityHashCode(e.getKey()) ^ + * System.identityHashCode(e.getValue())}. * *

    Owing to the reference-equality-based semantics of the - * Map.Entry instances in the set returned by this method, + * {@code Map.Entry} instances in the set returned by this method, * it is possible that the symmetry and transitivity requirements of * the {@link Object#equals(Object)} contract may be violated if any of * the entries in the set is compared to a normal map entry, or if * the set returned by this method is compared to a set of normal map * entries (such as would be returned by a call to this method on a normal - * map). However, the Object.equals contract is guaranteed to + * map). However, the {@code Object.equals} contract is guaranteed to * hold among identity-based map entries, and among sets of such entries. * * @@ -1281,11 +1281,11 @@ public Spliterator> spliterator() { private static final long serialVersionUID = 8188218128353913216L; /** - * Saves the state of the IdentityHashMap instance to a stream + * Saves the state of the {@code IdentityHashMap} instance to a stream * (i.e., serializes it). * * @serialData The size of the HashMap (the number of key-value - * mappings) (int), followed by the key (Object) and + * mappings) ({@code int}), followed by the key (Object) and * value (Object) for each key-value mapping represented by the * IdentityHashMap. The key-value mappings are emitted in no * particular order. @@ -1310,7 +1310,7 @@ private void writeObject(java.io.ObjectOutputStream s) } /** - * Reconstitutes the IdentityHashMap instance from a stream (i.e., + * Reconstitutes the {@code IdentityHashMap} instance from a stream (i.e., * deserializes it). */ private void readObject(java.io.ObjectInputStream s) @@ -1323,7 +1323,11 @@ private void readObject(java.io.ObjectInputStream s) if (size < 0) throw new java.io.StreamCorruptedException ("Illegal mappings count: " + size); - init(capacity(size)); + int cap = capacity(size); + /* J2ObjC removed + SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap); + */ + init(cap); // Read the keys and values, and put the mappings in the table for (int i=0; i public KeySpliterator trySplit() { int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1; return (lo >= mid) ? null : - new KeySpliterator(map, lo, index = mid, est >>>= 1, - expectedModCount); + new KeySpliterator<>(map, lo, index = mid, est >>>= 1, + expectedModCount); } @SuppressWarnings("unchecked") @@ -1499,8 +1503,8 @@ static final class ValueSpliterator public ValueSpliterator trySplit() { int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1; return (lo >= mid) ? null : - new ValueSpliterator(map, lo, index = mid, est >>>= 1, - expectedModCount); + new ValueSpliterator<>(map, lo, index = mid, est >>>= 1, + expectedModCount); } public void forEachRemaining(Consumer action) { @@ -1558,8 +1562,8 @@ static final class EntrySpliterator public EntrySpliterator trySplit() { int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1; return (lo >= mid) ? null : - new EntrySpliterator(map, lo, index = mid, est >>>= 1, - expectedModCount); + new EntrySpliterator<>(map, lo, index = mid, est >>>= 1, + expectedModCount); } public void forEachRemaining(Consumer> action) { @@ -1576,7 +1580,7 @@ public void forEachRemaining(Consumer> action) { (K)unmaskNull(key); @SuppressWarnings("unchecked") V v = (V)a[i+1]; action.accept - (new AbstractMap.SimpleImmutableEntry(k, v)); + (new AbstractMap.SimpleImmutableEntry<>(k, v)); } } @@ -1599,7 +1603,7 @@ public boolean tryAdvance(Consumer> action) { @SuppressWarnings("unchecked") K k = (K)unmaskNull(key); action.accept - (new AbstractMap.SimpleImmutableEntry(k, v)); + (new AbstractMap.SimpleImmutableEntry<>(k, v)); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java index 02add44947..d79d4997d7 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java @@ -30,7 +30,7 @@ * point as defined by {@link Character#isValidCodePoint} is passed to the * {@link Formatter}. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatConversionException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatConversionException.java index a9b006f51c..09ee5c45cd 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatConversionException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatConversionException.java @@ -29,7 +29,7 @@ * Unchecked exception thrown when the argument corresponding to the format * specifier is of an incompatible type. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java index 6b8223a4b3..5374f59aea 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java @@ -28,7 +28,7 @@ /** * Unchecked exception thrown when an illegal combination flags is given. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java index 41cbbb7fec..bc9c6217ae 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java @@ -27,7 +27,7 @@ /** * Unchecked exception thrown when the precision is a negative value other than - * -1, the conversion does not support a precision, or the value is + * {@code -1}, the conversion does not support a precision, or the value is * otherwise unsupported. * * @since 1.5 diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatWidthException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatWidthException.java index 08ae47dcf7..c7b7823c53 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatWidthException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IllegalFormatWidthException.java @@ -27,7 +27,7 @@ /** * Unchecked exception thrown when the format width is a negative value other - * than -1 or is otherwise unsupported. + * than {@code -1} or is otherwise unsupported. * * @since 1.5 */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ImmutableCollections.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ImmutableCollections.java new file mode 100644 index 0000000000..b5547a9e64 --- /dev/null +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ImmutableCollections.java @@ -0,0 +1,1191 @@ +/* + * Copyright (c) 2016, 2018, 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; + +/* J2ObjC removed +import jdk.internal.vm.annotation.Stable; +*/ + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +/** + * 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 { + long nt = System.nanoTime(); + SALT = (int)((nt >>> 32) ^ nt); + } + + /** 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 int EXPAND_FACTOR = 2; + + static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } + + static abstract class AbstractImmutableCollection extends AbstractCollection { + // all mutating methods throw UnsupportedOperationException + @Override public boolean add(E e) { throw uoe(); } + @Override public boolean addAll(Collection 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 filter) { throw uoe(); } + @Override public boolean retainAll(Collection c) { throw uoe(); } + } + + // ---------- List Implementations ---------- + + // make a copy, short-circuiting based on implementation class + @SuppressWarnings("unchecked") + static List listCopy(Collection coll) { + if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) { + return (List)coll; + } else { + return (List)List.of(coll.toArray()); + } + } + + @SuppressWarnings("unchecked") + static List emptyList() { + return (List) ListN.EMPTY_LIST; + } + + static abstract class AbstractImmutableList extends AbstractImmutableCollection + implements List, RandomAccess { + + // all mutating methods throw UnsupportedOperationException + @Override public void add(int index, E element) { throw uoe(); } + @Override public boolean addAll(int index, Collection c) { throw uoe(); } + @Override public E remove(int index) { throw uoe(); } + @Override public void replaceAll(UnaryOperator operator) { throw uoe(); } + @Override public E set(int index, E element) { throw uoe(); } + @Override public void sort(Comparator c) { throw uoe(); } + + @Override + public List subList(int fromIndex, int toIndex) { + int size = size(); + subListRangeCheck(fromIndex, toIndex, size); + return SubList.fromList(this, fromIndex, toIndex); + } + + static void subListRangeCheck(int fromIndex, int toIndex, int size) { + if (fromIndex < 0) + throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); + if (toIndex > size) + throw new IndexOutOfBoundsException("toIndex = " + toIndex); + if (fromIndex > toIndex) + throw new IllegalArgumentException("fromIndex(" + fromIndex + + ") > toIndex(" + toIndex + ")"); + } + + @Override + public Iterator iterator() { + return new ListItr(this, size()); + } + + @Override + public ListIterator listIterator() { + return listIterator(0); + } + + @Override + public ListIterator listIterator(final int index) { + int size = size(); + if (index < 0 || index > size) { + throw outOfBounds(index); + } + return new ListItr(this, size, index); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof List)) { + return false; + } + + Iterator oit = ((List) o).iterator(); + for (int i = 0, s = size(); i < s; i++) { + if (!oit.hasNext() || !get(i).equals(oit.next())) { + return false; + } + } + return !oit.hasNext(); + } + + @Override + public int indexOf(Object o) { + Objects.requireNonNull(o); + for (int i = 0, s = size(); i < s; i++) { + if (o.equals(get(i))) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object o) { + Objects.requireNonNull(o); + for (int i = size() - 1; i >= 0; i--) { + if (o.equals(get(i))) { + return i; + } + } + return -1; + } + + @Override + public int hashCode() { + int hash = 1; + for (int i = 0, s = size(); i < s; i++) { + hash = 31 * hash + get(i).hashCode(); + } + return hash; + } + + @Override + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + + IndexOutOfBoundsException outOfBounds(int index) { + return new IndexOutOfBoundsException("Index: " + index + " Size: " + size()); + } + } + + static final class ListItr implements ListIterator { + + /* J2ObjC removed + @Stable + */ + private final List list; + + /* J2ObjC removed + @Stable + */ + private final int size; + + /* J2ObjC removed + @Stable + */ + private final boolean isListIterator; + + private int cursor; + + ListItr(List list, int size) { + this.list = list; + this.size = size; + this.cursor = 0; + isListIterator = false; + } + + ListItr(List list, int size, int index) { + this.list = list; + this.size = size; + this.cursor = index; + isListIterator = true; + } + + public boolean hasNext() { + return cursor != size; + } + + public E next() { + try { + int i = cursor; + E next = list.get(i); + cursor = i + 1; + return next; + } catch (IndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + + public void remove() { + throw uoe(); + } + + public boolean hasPrevious() { + if (!isListIterator) { + throw uoe(); + } + return cursor != 0; + } + + public E previous() { + if (!isListIterator) { + throw uoe(); + } + try { + int i = cursor - 1; + E previous = list.get(i); + cursor = i; + return previous; + } catch (IndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + + public int nextIndex() { + if (!isListIterator) { + throw uoe(); + } + return cursor; + } + + public int previousIndex() { + if (!isListIterator) { + throw uoe(); + } + return cursor - 1; + } + + public void set(E e) { + throw uoe(); + } + + public void add(E e) { + throw uoe(); + } + } + + static final class SubList extends AbstractImmutableList + implements RandomAccess { + + /* J2ObjC removed + @Stable + */ + private final List root; + + /* J2ObjC removed + @Stable + */ + private final int offset; + + /* J2ObjC removed + @Stable + */ + private final int size; + + private SubList(List root, int offset, int size) { + this.root = root; + this.offset = offset; + this.size = size; + } + + /** + * Constructs a sublist of another SubList. + */ + static SubList fromSubList(SubList parent, int fromIndex, int toIndex) { + return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex); + } + + /** + * Constructs a sublist of an arbitrary AbstractImmutableList, which is + * not a SubList itself. + */ + static SubList fromList(List list, int fromIndex, int toIndex) { + return new SubList<>(list, fromIndex, toIndex - fromIndex); + } + + public E get(int index) { + Objects.checkIndex(index, size); + return root.get(offset + index); + } + + public int size() { + return size; + } + + public Iterator iterator() { + return new ListItr<>(this, size()); + } + + public ListIterator listIterator(int index) { + rangeCheck(index); + return new ListItr<>(this, size(), index); + } + + public List subList(int fromIndex, int toIndex) { + subListRangeCheck(fromIndex, toIndex, size); + return SubList.fromSubList(this, fromIndex, toIndex); + } + + private void rangeCheck(int index) { + if (index < 0 || index > size) { + throw outOfBounds(index); + } + } + } + + static final class List12 extends AbstractImmutableList + implements Serializable { + + /* J2ObjC removed + @Stable + */ + private final E e0; + + /* J2ObjC removed + @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 + public int size() { + return e1 != null ? 2 : 1; + } + + @Override + public E get(int index) { + if (index == 0) { + return e0; + } else if (index == 1 && e1 != null) { + return e1; + } + throw outOfBounds(index); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + if (e1 == null) { + return new CollSer(CollSer.IMM_LIST, e0); + } else { + return new CollSer(CollSer.IMM_LIST, e0, e1); + } + } + + } + + static final class ListN extends AbstractImmutableList + implements Serializable { + + // EMPTY_LIST may be initialized from the CDS archive. + static /* @Stable */ List EMPTY_LIST; + + static { + // Android-removed: CDS is not supported. + // VM.initializeFromArchive(ListN.class); + if (EMPTY_LIST == null) { + EMPTY_LIST = new ListN<>(); + } + } + + /* J2ObjC removed + @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]); + } + elements = tmp; + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public int size() { + return elements.length; + } + + @Override + public E get(int index) { + 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 abstract class AbstractImmutableSet extends AbstractImmutableCollection + implements Set { + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (!(o instanceof Set)) { + return false; + } + + Collection c = (Collection) o; + if (c.size() != size()) { + return false; + } + for (Object e : c) { + if (e == null || !contains(e)) { + return false; + } + } + return true; + } + + @Override + public abstract int hashCode(); + } + + @SuppressWarnings("unchecked") + static Set emptySet() { + return (Set) SetN.EMPTY_SET; + } + + static final class Set12 extends AbstractImmutableSet + implements Serializable { + + /* J2ObjC removed + @Stable + */ + final E e0; + /* J2ObjC removed + @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); + } + + this.e0 = e0; + this.e1 = e1; + } + + @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 iterator() { + return new Iterator<>() { + private int idx = size(); + + @Override + public boolean hasNext() { + return idx > 0; + } + + @Override + public E next() { + if (idx == 1) { + idx = 0; + return SALT >= 0 || e1 == null ? e0 : e1; + } else if (idx == 2) { + idx = 1; + return SALT >= 0 ? e1 : e0; + } else { + throw new NoSuchElementException(); + } + } + }; + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new InvalidObjectException("not serial proxy"); + } + + private Object writeReplace() { + if (e1 == null) { + return new CollSer(CollSer.IMM_SET, e0); + } else { + 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 AbstractImmutableSet + implements Serializable { + + // EMPTY_SET may be initialized from the CDS archive. + static /* @Stable */ Set EMPTY_SET; + + static { + // Android-removed: CDS is not supported. + // VM.initializeFromArchive(SetN.class); + if (EMPTY_SET == null) { + EMPTY_SET = new SetN<>(); + } + } + + /* J2ObjC removed + @Stable + */ + final E[] elements; + /* J2ObjC removed + @Stable + */ + final int size; + + @SafeVarargs + @SuppressWarnings("unchecked") + SetN(E... input) { + size = input.length; // implicit nullcheck of input + + elements = (E[])new Object[EXPAND_FACTOR * input.length]; + for (int i = 0; i < input.length; i++) { + E e = input[i]; + int idx = probe(e); // implicit nullcheck of 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 size > 0 && probe(o) >= 0; + } + + private final class SetNIterator implements Iterator { + + private int remaining; + + private int idx; + + SetNIterator() { + remaining = size(); + if (remaining > 0) { + idx = Math.floorMod(SALT, elements.length); + } + } + + @Override + public boolean hasNext() { + return remaining > 0; + } + + private int nextIndex() { + int idx = this.idx; + if (SALT >= 0) { + if (++idx >= elements.length) { + idx = 0; + } + } else { + if (--idx < 0) { + idx = elements.length - 1; + } + } + return this.idx = idx; + } + + @Override + public E next() { + if (hasNext()) { + E element; + // skip null elements + while ((element = elements[nextIndex()]) == null) {} + remaining--; + return element; + } else { + throw new NoSuchElementException(); + } + } + } + + @Override + public Iterator iterator() { + return new SetNIterator(); + } + + @Override + public int hashCode() { + int h = 0; + for (E e : elements) { + if (e != null) { + h += e.hashCode(); + } + } + return h; + } + + // returns index at which element is present; or if absent, + // (-i - 1) where i is location where element should be inserted. + // Callers are relying on this method to perform an implicit nullcheck + // of pe + private int probe(Object pe) { + int idx = Math.floorMod(pe.hashCode(), 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 ---------- + + @SuppressWarnings("unchecked") + static Map emptyMap() { + return (Map) MapN.EMPTY_MAP; + } + + abstract static class AbstractImmutableMap extends AbstractMap implements Serializable { + @Override public void clear() { throw uoe(); } + @Override public V compute(K key, BiFunction rf) { throw uoe(); } + @Override public V computeIfAbsent(K key, Function mf) { throw uoe(); } + @Override public V computeIfPresent(K key, BiFunction rf) { throw uoe(); } + @Override public V merge(K key, V value, BiFunction rf) { throw uoe(); } + @Override public V put(K key, V value) { throw uoe(); } + @Override public void putAll(Map m) { throw uoe(); } + @Override public V putIfAbsent(K key, V value) { throw uoe(); } + @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 f) { throw uoe(); } + } + + static final class Map1 extends AbstractImmutableMap { + /* J2ObjC removed + @Stable + */ + private final K k0; + /* J2ObjC removed + @Stable + */ + 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 V get(Object o) { + return o.equals(k0) ? v0 : null; // implicit nullcheck of o + } + + @Override + public boolean containsKey(Object o) { + return o.equals(k0); // implicit nullcheck of o + } + + @Override + public boolean containsValue(Object o) { + return o.equals(v0); // implicit nullcheck of 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); + } + + @Override + public int hashCode() { + return k0.hashCode() ^ v0.hashCode(); + } + } + + /** + * 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 AbstractImmutableMap { + + // EMPTY_MAP may be initialized from the CDS archive. + static /* @Stable */ Map EMPTY_MAP; + + static { + // Android-removed: CDS is not supported. + // VM.initializeFromArchive(MapN.class); + if (EMPTY_MAP == null) { + EMPTY_MAP = new MapN<>(); + } + } + + /* J2ObjC removed + @Stable + */ + final Object[] table; // pairs of key, value + + /* J2ObjC removed + @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; + + int len = 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) { + Objects.requireNonNull(o); + return size > 0 && probe(o) >= 0; + } + + @Override + public boolean containsValue(Object o) { + Objects.requireNonNull(o); + for (int i = 1; i < table.length; i += 2) { + Object v = table[i]; + if (v != null && o.equals(v)) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + int hash = 0; + for (int i = 0; i < table.length; i += 2) { + Object k = table[i]; + if (k != null) { + hash += k.hashCode() ^ table[i + 1].hashCode(); + } + } + return hash; + } + + @Override + @SuppressWarnings("unchecked") + public V get(Object o) { + if (size == 0) { + Objects.requireNonNull(o); + return null; + } + int i = probe(o); + if (i >= 0) { + return (V)table[i+1]; + } else { + return null; + } + } + + @Override + public int size() { + return size; + } + + class MapNIterator implements Iterator> { + + private int remaining; + + private int idx; + + MapNIterator() { + remaining = size(); + if (remaining > 0) { + idx = Math.floorMod(SALT, table.length >> 1) << 1; + } + } + + @Override + public boolean hasNext() { + return remaining > 0; + } + + private int nextIndex() { + int idx = this.idx; + if (SALT >= 0) { + if ((idx += 2) >= table.length) { + idx = 0; + } + } else { + if ((idx -= 2) < 0) { + idx = table.length - 2; + } + } + return this.idx = idx; + } + + @Override + public Map.Entry next() { + if (hasNext()) { + while (table[nextIndex()] == null) {} + @SuppressWarnings("unchecked") + Map.Entry e = + new KeyValueHolder<>((K)table[idx], (V)table[idx+1]); + remaining--; + return e; + } else { + throw new NoSuchElementException(); + } + } + } + + @Override + public Set> entrySet() { + return new AbstractSet<>() { + @Override + public int size() { + return MapN.this.size; + } + + @Override + public Iterator> iterator() { + return new MapNIterator(); + } + + // Android-added: AbstractCollection#clear implementation is no-op when + // collection is empty. Overriding this method to make Map.of().clear() + // and Map.of().entrySet().clear() behaviour equal. + @Override + public void clear() { + throw uoe(); + } + }; + } + + // returns index at which the probe key is present; or if absent, + // (-i - 1) where i is location where element should be inserted. + // Callers are relying on this method to perform an implicit nullcheck + // of pk. + private int probe(Object pk) { + int idx = Math.floorMod(pk.hashCode(), 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 ---------- + +/** + * A unified serialization proxy class for the immutable collections. + * + * @serial + * @since 9 + */ +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; + + /** + * Indicates the type of collection that is serialized. + * The low order 8 bits have the value 1 for an immutable + * {@code List}, 2 for an immutable {@code Set}, and 3 for + * an immutable {@code Map}. Any other value causes an + * {@link InvalidObjectException} to be thrown. The high + * order 24 bits are zero when an instance is serialized, + * and they are ignored when an instance is deserialized. + * They can thus be used by future implementations without + * causing compatibility issues. + * + *

    The tag value also determines the interpretation of the + * transient {@code Object[] array} field. + * For {@code List} and {@code Set}, the array's length is the size + * of the collection, and the array contains the elements of the collection. + * Null elements are not allowed. For {@code Set}, duplicate elements + * are not allowed. + * + *

    For {@code Map}, the array's length is twice the number of mappings + * present in the map. The array length is necessarily even. + * The array contains a succession of key and value pairs: + * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed, + * and duplicate keys are not allowed. + * + * @serial + * @since 9 + */ + private final int tag; + + /** + * @serial + * @since 9 + */ + private transient Object[] array; + + CollSer(int t, Object... a) { + tag = t; + array = a; + } + + /** + * Reads objects from the stream and stores them + * in the transient {@code Object[] array} field. + * + * @serialData + * A nonnegative int, indicating the count of objects, + * followed by that many objects. + * + * @param ois the ObjectInputStream from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + * @throws InvalidObjectException if the count is negative + * @since 9 + */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + int len = ois.readInt(); + + if (len < 0) { + throw new InvalidObjectException("negative length " + len); + } + + /* J2ObjC removed + sun.misc.SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len); + */ + Object[] a = new Object[len]; + for (int i = 0; i < len; i++) { + a[i] = ois.readObject(); + } + + array = a; + } + + /** + * Writes objects to the stream from + * the transient {@code Object[] array} field. + * + * @serialData + * A nonnegative int, indicating the count of objects, + * followed by that many objects. + * + * @param oos the ObjectOutputStream to which data is written + * @throws IOException if an I/O error occurs + * @since 9 + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + oos.writeInt(array.length); + for (int i = 0; i < array.length; i++) { + oos.writeObject(array[i]); + } + } + + /** + * Creates and returns an immutable collection from this proxy class. + * The instance returned is created as if by calling one of the + * static factory methods for + * List, + * Map, or + * Set. + * This proxy class is the serial form for all immutable collection instances, + * regardless of implementation type. This is necessary to ensure that the + * existence of any particular implementation type is kept out of the + * serialized form. + * + * @return a collection created from this proxy object + * @throws InvalidObjectException if the tag value is illegal or if an exception + * is thrown during creation of the collection + * @throws ObjectStreamException if another serialization error has occurred + * @since 9 + */ + 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 24 bits + switch (tag & 0xff) { + case IMM_LIST: + 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); + } + default: + throw new InvalidObjectException(String.format("invalid flags 0x%x", tag)); + } + } catch (NullPointerException|IllegalArgumentException ex) { + InvalidObjectException ioe = new InvalidObjectException("invalid object"); + ioe.initCause(ex); + throw ioe; + } + } +} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/InputMismatchException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/InputMismatchException.java index e4d1ce34be..c101c65da1 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/InputMismatchException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/InputMismatchException.java @@ -26,7 +26,7 @@ package java.util; /** - * Thrown by a Scanner to indicate that the token + * Thrown by a {@code Scanner} to indicate that the token * retrieved does not match the pattern for the expected type, or * that the token is out of range for the expected type. * @@ -39,7 +39,7 @@ class InputMismatchException extends NoSuchElementException { private static final long serialVersionUID = 8811230760997066428L; /** - * Constructs an InputMismatchException with null + * Constructs an {@code InputMismatchException} with {@code null} * as its error message string. */ public InputMismatchException() { @@ -47,9 +47,9 @@ public InputMismatchException() { } /** - * Constructs an InputMismatchException, saving a reference - * to the error message string s for later retrieval by the - * getMessage method. + * Constructs an {@code InputMismatchException}, saving a reference + * to the error message string {@code s} for later retrieval by the + * {@code getMessage} method. * * @param s the detail message. */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IntSummaryStatistics.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IntSummaryStatistics.java index d16f2246df..9043c8a15c 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IntSummaryStatistics.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/IntSummaryStatistics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -25,6 +25,7 @@ package java.util; import java.util.function.IntConsumer; +import java.util.stream.Collector; /** * A state object for collecting statistics such as count, min, max, sum, and @@ -53,7 +54,7 @@ * * @implNote This implementation is not thread safe. However, it is safe to use * {@link java.util.stream.Collectors#summarizingInt(java.util.function.ToIntFunction) - * Collectors.toIntStatistics()} on a parallel stream, because the parallel + * Collectors.summarizingInt()} on a parallel stream, because the parallel * implementation of {@link java.util.stream.Stream#collect Stream.collect()} * provides the necessary partitioning, isolation, and merging of results for * safe and efficient parallel execution. @@ -68,12 +69,57 @@ public class IntSummaryStatistics implements IntConsumer { private int max = Integer.MIN_VALUE; /** - * Construct an empty instance with zero count, zero sum, + * Constructs an empty instance with zero count, zero sum, * {@code Integer.MAX_VALUE} min, {@code Integer.MIN_VALUE} max and zero * average. */ public IntSummaryStatistics() { } + /** + * Constructs a non-empty instance with the specified {@code count}, + * {@code min}, {@code max}, and {@code sum}. + * + *

    If {@code count} is zero then the remaining arguments are ignored and + * an empty instance is constructed. + * + *

    If the arguments are inconsistent then an {@code IllegalArgumentException} + * is thrown. The necessary consistent argument conditions are: + *

      + *
    • {@code count >= 0}
    • + *
    • {@code min <= max}
    • + *
    + * @apiNote + * The enforcement of argument correctness means that the retrieved set of + * recorded values obtained from a {@code IntSummaryStatistics} source + * instance may not be a legal set of arguments for this constructor due to + * arithmetic overflow of the source's recorded count of values. + * The consistent argument conditions are not sufficient to prevent the + * creation of an internally inconsistent instance. An example of such a + * state would be an instance with: {@code count} = 2, {@code min} = 1, + * {@code max} = 2, and {@code sum} = 0. + * + * @param count the count of values + * @param min the minimum value + * @param max the maximum value + * @param sum the sum of all values + * @throws IllegalArgumentException if the arguments are inconsistent + * @since 10 + */ + public IntSummaryStatistics(long count, int min, int max, long sum) + throws IllegalArgumentException { + if (count < 0L) { + throw new IllegalArgumentException("Negative count value"); + } else if (count > 0L) { + if (min > max) throw new IllegalArgumentException("Minimum greater than maximum"); + + this.count = count; + this.sum = sum; + this.min = min; + this.max = max; + } + // Use default field values if count == 0 + } + /** * Records a new value into the summary information * @@ -149,14 +195,12 @@ public final double getAverage() { return getCount() > 0 ? (double) getSum() / getCount() : 0.0d; } - @Override /** - * {@inheritDoc} - * * Returns a non-empty string representation of this object suitable for * debugging. The exact presentation format is unspecified and may vary * between implementations and versions. */ + @Override public String toString() { return String.format( "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}", diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Iterator.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Iterator.java index 7d2daf8f96..aaf6a0497f 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Iterator.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Iterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -40,9 +40,13 @@ * * *

    This interface is a member of the - * + * * Java Collections Framework. * + * @apiNote + * An {@link Enumeration} can be converted into an {@code Iterator} by + * using the {@link Enumeration#asIterator} method. + * * @param the type of elements returned by this iterator * * @author Josh Bloch @@ -72,10 +76,15 @@ public interface Iterator { /** * Removes from the underlying collection the last element returned * by this iterator (optional operation). This method can be called - * only once per call to {@link #next}. The behavior of an iterator - * is unspecified if the underlying collection is modified while the - * iteration is in progress in any way other than by calling this - * method. + * only once per call to {@link #next}. + *

    + * The behavior of an iterator is unspecified if the underlying collection + * is modified while the iteration is in progress in any way other than by + * calling this method, unless an overriding class has specified a + * concurrent modification policy. + *

    + * The behavior of an iterator is unspecified if this method is called + * after a call to the {@link #forEachRemaining forEachRemaining} method. * * @implSpec * The default implementation throws an instance of @@ -98,6 +107,14 @@ default void remove() { * have been processed or the action throws an exception. Actions are * performed in the order of iteration, if that order is specified. * Exceptions thrown by the action are relayed to the caller. + *

    + * The behavior of an iterator is unspecified if the action modifies the + * collection in any way (even by calling the {@link #remove remove} method + * or other mutator methods of {@code Iterator} subtypes), + * unless an overriding class has specified a concurrent modification policy. + *

    + * Subsequent behavior of an iterator is unspecified if the action throws an + * exception. * * @implSpec *

    The default implementation behaves as if: diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/JumboEnumSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/JumboEnumSet.java index 6798511826..20e8222ccc 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/JumboEnumSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/JumboEnumSet.java @@ -163,19 +163,19 @@ public int size() { } /** - * Returns true if this set contains no elements. + * Returns {@code true} if this set contains no elements. * - * @return true if this set contains no elements + * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return size == 0; } /** - * Returns true if this set contains the specified element. + * Returns {@code true} if this set contains the specified element. * * @param e element to be checked for containment in this collection - * @return true if this set contains the specified element + * @return {@code true} if this set contains the specified element */ public boolean contains(Object e) { if (e == null) @@ -194,9 +194,9 @@ public boolean contains(Object e) { * Adds the specified element to this set if it is not already present. * * @param e element to be added to this set - * @return true if the set changed as a result of the call + * @return {@code true} if the set changed as a result of the call * - * @throws NullPointerException if e is null + * @throws NullPointerException if {@code e} is null */ public boolean add(E e) { typeCheck(e); @@ -216,7 +216,7 @@ public boolean add(E e) { * Removes the specified element from this set if it is present. * * @param e element to be removed from this set, if present - * @return true if the set contained the specified element + * @return {@code true} if the set contained the specified element */ public boolean remove(Object e) { if (e == null) @@ -238,11 +238,11 @@ public boolean remove(Object e) { // Bulk Operations /** - * Returns true if this set contains all of the elements + * Returns {@code true} if this set contains all of the elements * in the specified collection. * * @param c collection to be checked for containment in this set - * @return true if this set contains all of the elements + * @return {@code true} if this set contains all of the elements * in the specified collection * @throws NullPointerException if the specified collection is null */ @@ -264,7 +264,7 @@ public boolean containsAll(Collection c) { * Adds all of the elements in the specified collection to this set. * * @param c collection whose elements are to be added to this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection or any of * its elements are null */ @@ -291,7 +291,7 @@ public boolean addAll(Collection c) { * the specified collection. * * @param c elements to be removed from this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean removeAll(Collection c) { @@ -312,7 +312,7 @@ public boolean removeAll(Collection c) { * specified collection. * * @param c elements to be retained in this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean retainAll(Collection c) { @@ -341,12 +341,12 @@ public void clear() { /** * Compares the specified object with this set for equality. Returns - * true if the given object is also a set, the two sets have + * {@code true} if the given object is also a set, the two sets have * the same size, and every member of the given set is contained in * this set. * * @param o object to be compared for equality with this set - * @return true if the specified object is equal to this set + * @return {@code true} if the specified object is equal to this set */ public boolean equals(Object o) { if (!(o instanceof JumboEnumSet)) diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/KeyValueHolder.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/KeyValueHolder.java new file mode 100644 index 0000000000..006c546df8 --- /dev/null +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/KeyValueHolder.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, 2017, 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; + +/* J2ObjC removed +import jdk.internal.vm.annotation.Stable; +*/ + +/** + * An immutable container for a key and a value, suitable for use + * in creating and populating {@code Map} instances. + * + *

    This is a value-based + * class; use of identity-sensitive operations (including reference equality + * ({@code ==}), identity hash code, or synchronization) on instances of + * {@code KeyValueHolder} may have unpredictable results and should be avoided. + * + * @apiNote + * This class is not public. Instances can be created using the + * {@link Map#entry Map.entry(k, v)} factory method, which is public. + * + *

    This class differs from AbstractMap.SimpleImmutableEntry in the following ways: + * it is not serializable, it is final, and its key and value must be non-null. + * + * @param the key type + * @param the value type + * + * @see Map#ofEntries Map.ofEntries() + * @since 9 + */ +final class KeyValueHolder implements Map.Entry { + /* J2ObjC removed + @Stable + */ + final K key; + /* J2ObjC removed + @Stable + */ + final V value; + + KeyValueHolder(K k, V v) { + key = Objects.requireNonNull(k); + value = Objects.requireNonNull(v); + } + + /** + * Gets the key from this holder. + * + * @return the key + */ + @Override + public K getKey() { + return key; + } + + /** + * Gets the value from this holder. + * + * @return the value + */ + @Override + public V getValue() { + return value; + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @param value ignored + * @return never returns normally + */ + @Override + public V setValue(V value) { + throw new UnsupportedOperationException("not supported"); + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries' keys and values are equal. Note that key and + * value are non-null, so equals() can be called safely on them. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return key.equals(e.getKey()) && value.equals(e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * is {@code key.hashCode() ^ value.hashCode()}. Note that key and + * value are non-null, so hashCode() can be called safely on them. + */ + @Override + public int hashCode() { + return key.hashCode() ^ value.hashCode(); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("{@code =}") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + @Override + public String toString() { + return key + "=" + value; + } +} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashMap.java index e701900f90..7bc21e14c1 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -39,15 +39,15 @@ // Android-added: Note about spliterator order b/33945212 in Android N /** - *

    Hash table and linked list implementation of the Map interface, + *

    Hash table and linked list implementation of the {@code Map} interface, * with predictable iteration order. This implementation differs from - * HashMap in that it maintains a doubly-linked list running through + * {@code HashMap} in that it maintains a doubly-linked list running through * all of its entries. This linked list defines the iteration ordering, * which is normally the order in which keys were inserted into the map * (insertion-order). Note that insertion order is not affected - * if a key is re-inserted into the map. (A key k is - * reinserted into a map m if m.put(k, v) is invoked when - * m.containsKey(k) would return true immediately prior to + * if a key is re-inserted into the map. (A key {@code k} is + * reinserted into a map {@code m} if {@code m.put(k, v)} is invoked when + * {@code m.containsKey(k)} would return {@code true} immediately prior to * the invocation.) * *

    This implementation spares its clients from the unspecified, generally @@ -86,23 +86,23 @@ * impose a policy for removing stale mappings automatically when new mappings * are added to the map. * - *

    This class provides all of the optional Map operations, and - * permits null elements. Like HashMap, it provides constant-time - * performance for the basic operations (add, contains and - * remove), assuming the hash function disperses elements + *

    This class provides all of the optional {@code Map} operations, and + * permits null elements. Like {@code HashMap}, it provides constant-time + * performance for the basic operations ({@code add}, {@code contains} and + * {@code remove}), assuming the hash function disperses elements * properly among the buckets. Performance is likely to be just slightly - * below that of HashMap, due to the added expense of maintaining the + * below that of {@code HashMap}, due to the added expense of maintaining the * linked list, with one exception: Iteration over the collection-views - * of a LinkedHashMap requires time proportional to the size - * of the map, regardless of its capacity. Iteration over a HashMap + * of a {@code LinkedHashMap} requires time proportional to the size + * of the map, regardless of its capacity. Iteration over a {@code HashMap} * is likely to be more expensive, requiring time proportional to its * capacity. * *

    A linked hash map has two parameters that affect its performance: * initial capacity and load factor. They are defined precisely - * as for HashMap. Note, however, that the penalty for choosing an + * as for {@code HashMap}. Note, however, that the penalty for choosing an * excessively high value for initial capacity is less severe for this class - * than for HashMap, as iteration times for this class are unaffected + * than for {@code HashMap}, as iteration times for this class are unaffected * by capacity. * *

    Note that this implementation is not synchronized. @@ -122,14 +122,14 @@ * iteration order. In insertion-ordered linked hash maps, merely changing * the value associated with a key that is already contained in the map is not * a structural modification. In access-ordered linked hash maps, - * merely querying the map with get is a structural modification. + * merely querying the map with {@code get} is a structural modification. * ) * - *

    The iterators returned by the iterator method of the collections + *

    The iterators returned by the {@code iterator} method of the collections * returned by all of this class's collection view methods are * fail-fast: if the map is structurally modified at any time after * the iterator is created, in any way except through the iterator's own - * remove method, the iterator will throw a {@link + * {@code remove} method, the iterator will throw a {@link * ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than risking * arbitrary, non-deterministic behavior at an undetermined time in the future. @@ -137,7 +137,7 @@ *

    Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. @@ -153,10 +153,10 @@ * to obtain a correctly ordered Spliterator on API level 24 and 25: *

      *
    • For a Collection view {@code c = lhm.keySet()}, - * {@code c = lhm.keySet()} or {@code c = lhm.values()}, use + * {@code c = lhm.entrySet()} or {@code c = lhm.values()}, use * {@code java.util.Spliterators.spliterator(c, c.spliterator().characteristics())} * instead of {@code c.spliterator()}. - *
    • Instead of {@code lhm.stream()} or {@code lhm.parallelStream()}, use + *
    • Instead of {@code c.stream()} or {@code c.parallelStream()}, use * {@code java.util.stream.StreamSupport.stream(spliterator, false)} * to construct a (nonparallel) {@link java.util.stream.Stream} from * such a {@code Spliterator}. @@ -165,7 +165,7 @@ * {@code LinkedHashMap}. * *

      This class is a member of the - * + * * Java Collections Framework. * * @implNote @@ -197,7 +197,7 @@ public class LinkedHashMap * LinkedHashMap.Entry is now treated as intermediary node class * that can also be converted to tree form. * - * BEGIN Android-changed + // BEGIN Android-changed * LinkedHashMapEntry should not be renamed. Specifically, for * source compatibility with earlier versions of Android, this * nested class must not be named "Entry". Otherwise, it would @@ -208,7 +208,7 @@ public class LinkedHashMap * To compile, that code snippet's "LinkedHashMap.Entry" must * mean java.util.Map.Entry which is the compile time type of * entrySet()'s elements. - * END Android-changed + // END Android-changed * * The changes in node classes also require using two fields * (head, tail) rather than a pointer to a header node to maintain @@ -240,8 +240,8 @@ static class LinkedHashMapEntry extends HashMap.Node { transient LinkedHashMapEntry tail; /** - * The iteration ordering method for this linked hash map: true - * for access-order, false for insertion-order. + * The iteration ordering method for this linked hash map: {@code true} + * for access-order, {@code false} for insertion-order. * * @serial */ @@ -285,7 +285,7 @@ void reinitialize() { Node newNode(int hash, K key, V value, Node e) { LinkedHashMapEntry p = - new LinkedHashMapEntry(hash, key, value, e); + new LinkedHashMapEntry<>(hash, key, value, e); linkNodeLast(p); return p; } @@ -293,20 +293,20 @@ Node newNode(int hash, K key, V value, Node e) { Node replacementNode(Node p, Node next) { LinkedHashMapEntry q = (LinkedHashMapEntry)p; LinkedHashMapEntry t = - new LinkedHashMapEntry(q.hash, q.key, q.value, next); + new LinkedHashMapEntry<>(q.hash, q.key, q.value, next); transferLinks(q, t); return t; } TreeNode newTreeNode(int hash, K key, V value, Node next) { - TreeNode p = new TreeNode(hash, key, value, next); + TreeNode p = new TreeNode<>(hash, key, value, next); linkNodeLast(p); return p; } TreeNode replacementTreeNode(Node p, Node next) { LinkedHashMapEntry q = (LinkedHashMapEntry)p; - TreeNode t = new TreeNode(q.hash, q.key, q.value, next); + TreeNode t = new TreeNode<>(q.hash, q.key, q.value, next); transferLinks(q, t); return t; } @@ -366,7 +366,7 @@ void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { } /** - * Constructs an empty insertion-ordered LinkedHashMap instance + * Constructs an empty insertion-ordered {@code LinkedHashMap} instance * with the specified initial capacity and load factor. * * @param initialCapacity the initial capacity @@ -380,7 +380,7 @@ public LinkedHashMap(int initialCapacity, float loadFactor) { } /** - * Constructs an empty insertion-ordered LinkedHashMap instance + * Constructs an empty insertion-ordered {@code LinkedHashMap} instance * with the specified initial capacity and a default load factor (0.75). * * @param initialCapacity the initial capacity @@ -392,7 +392,7 @@ public LinkedHashMap(int initialCapacity) { } /** - * Constructs an empty insertion-ordered LinkedHashMap instance + * Constructs an empty insertion-ordered {@code LinkedHashMap} instance * with the default initial capacity (16) and load factor (0.75). */ public LinkedHashMap() { @@ -401,8 +401,8 @@ public LinkedHashMap() { } /** - * Constructs an insertion-ordered LinkedHashMap instance with - * the same mappings as the specified map. The LinkedHashMap + * Constructs an insertion-ordered {@code LinkedHashMap} instance with + * the same mappings as the specified map. The {@code LinkedHashMap} * instance is created with a default load factor (0.75) and an initial * capacity sufficient to hold the mappings in the specified map. * @@ -416,13 +416,13 @@ public LinkedHashMap(Map m) { } /** - * Constructs an empty LinkedHashMap instance with the + * Constructs an empty {@code LinkedHashMap} instance with the * specified initial capacity, load factor and ordering mode. * * @param initialCapacity the initial capacity * @param loadFactor the load factor - * @param accessOrder the ordering mode - true for - * access-order, false for insertion-order + * @param accessOrder the ordering mode - {@code true} for + * access-order, {@code false} for insertion-order * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ @@ -435,11 +435,11 @@ public LinkedHashMap(int initialCapacity, /** - * Returns true if this map maps one or more keys to the + * Returns {@code true} if this map maps one or more keys to the * specified value. * * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the + * @return {@code true} if this map maps one or more keys to the * specified value */ public boolean containsValue(Object value) { @@ -468,7 +468,7 @@ public boolean containsValue(Object value) { */ public V get(Object key) { Node e; - if ((e = getNode(hash(key), key)) == null) + if ((e = getNode(key)) == null) return null; if (accessOrder) afterNodeAccess(e); @@ -480,7 +480,7 @@ public V get(Object key) { */ public V getOrDefault(Object key, V defaultValue) { Node e; - if ((e = getNode(hash(key), key)) == null) + if ((e = getNode(key)) == null) return defaultValue; if (accessOrder) afterNodeAccess(e); @@ -495,9 +495,21 @@ public void clear() { head = tail = null; } + // Android-added: eldest(), for internal use in LRU caches /** - * Returns true if this map should remove its eldest entry. - * This method is invoked by put and putAll after + * Returns the eldest entry in the map, or {@code null} if the map is empty. + * + * @return eldest entry in the map, or {@code null} if the map is empty + * + * @hide + */ + public Map.Entry eldest() { + return head; + } + + /** + * Returns {@code true} if this map should remove its eldest entry. + * This method is invoked by {@code put} and {@code putAll} after * inserting a new entry into the map. It provides the implementor * with the opportunity to remove the eldest entry each time a new one * is added. This is useful if the map represents a cache: it allows @@ -518,23 +530,23 @@ public void clear() { * instead allowing the map to modify itself as directed by its * return value. It is permitted for this method to modify * the map directly, but if it does so, it must return - * false (indicating that the map should not attempt any - * further modification). The effects of returning true + * {@code false} (indicating that the map should not attempt any + * further modification). The effects of returning {@code true} * after modifying the map from within this method are unspecified. * - *

      This implementation merely returns false (so that this + *

      This implementation merely returns {@code false} (so that this * map acts like a normal map - the eldest element is never removed). * * @param eldest The least recently inserted entry in the map, or if * this is an access-ordered map, the least recently accessed * entry. This is the entry that will be removed it this - * method returns true. If the map was empty prior - * to the put or putAll invocation resulting + * method returns {@code true}. If the map was empty prior + * to the {@code put} or {@code putAll} invocation resulting * in this invocation, this will be the entry that was just * inserted; in other words, if the map contains a single * entry, the eldest entry is also the newest. - * @return true if the eldest entry should be removed - * from the map; false if it should be retained. + * @return {@code true} if the eldest entry should be removed + * from the map; {@code false} if it should be retained. */ protected boolean removeEldestEntry(Map.Entry eldest) { return false; @@ -545,12 +557,12 @@ protected boolean removeEldestEntry(Map.Entry eldest) { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation), the results of + * the iterator's own {@code remove} operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the - * Iterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or addAll + * {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} * operations. * Its {@link Spliterator} typically provides faster sequential * performance but much poorer parallel performance than that of @@ -603,13 +615,13 @@ public final void forEach(Consumer action) { * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress - * (except through the iterator's own remove operation), + * (except through the iterator's own {@code remove} operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear operations. It does not - * support the add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. * Its {@link Spliterator} typically provides faster sequential * performance but much poorer parallel performance than that of * {@code HashMap}. @@ -656,14 +668,14 @@ public final void forEach(Consumer action) { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation, or through the - * setValue operation on a map entry returned by the + * the iterator's own {@code remove} operation, or through the + * {@code setValue} operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll and - * clear operations. It does not support the - * add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and + * {@code clear} operations. It does not support the + * {@code add} or {@code addAll} operations. * Its {@link Spliterator} typically provides faster sequential * performance but much poorer parallel performance than that of * {@code HashMap}. @@ -687,7 +699,7 @@ public final boolean contains(Object o) { return false; Map.Entry e = (Map.Entry) o; Object key = e.getKey(); - Node candidate = getNode(hash(key), key); + Node candidate = getNode(key); return candidate != null && candidate.equals(e); } public final boolean remove(Object o) { @@ -778,8 +790,7 @@ public final void remove() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); current = null; - K key = p.key; - removeNode(hash(key), key, null, false, false); + removeNode(p.hash, p.key, null, false, false); expectedModCount = modCount; } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashSet.java index ae32f72151..71fe3581d1 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedHashSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -26,15 +26,15 @@ package java.util; /** - *

      Hash table and linked list implementation of the Set interface, + *

      Hash table and linked list implementation of the {@code Set} interface, * with predictable iteration order. This implementation differs from - * HashSet in that it maintains a doubly-linked list running through + * {@code HashSet} in that it maintains a doubly-linked list running through * all of its entries. This linked list defines the iteration ordering, * which is the order in which elements were inserted into the set * (insertion-order). Note that insertion order is not affected - * if an element is re-inserted into the set. (An element e - * is reinserted into a set s if s.add(e) is invoked when - * s.contains(e) would return true immediately prior to + * if an element is re-inserted into the set. (An element {@code e} + * is reinserted into a set {@code s} if {@code s.add(e)} is invoked when + * {@code s.contains(e)} would return {@code true} immediately prior to * the invocation.) * *

      This implementation spares its clients from the unspecified, generally @@ -53,22 +53,22 @@ * the copy. (Clients generally appreciate having things returned in the same * order they were presented.) * - *

      This class provides all of the optional Set operations, and - * permits null elements. Like HashSet, it provides constant-time - * performance for the basic operations (add, contains and - * remove), assuming the hash function disperses elements + *

      This class provides all of the optional {@code Set} operations, and + * permits null elements. Like {@code HashSet}, it provides constant-time + * performance for the basic operations ({@code add}, {@code contains} and + * {@code remove}), assuming the hash function disperses elements * properly among the buckets. Performance is likely to be just slightly - * below that of HashSet, due to the added expense of maintaining the - * linked list, with one exception: Iteration over a LinkedHashSet + * below that of {@code HashSet}, due to the added expense of maintaining the + * linked list, with one exception: Iteration over a {@code LinkedHashSet} * requires time proportional to the size of the set, regardless of - * its capacity. Iteration over a HashSet is likely to be more + * its capacity. Iteration over a {@code HashSet} is likely to be more * expensive, requiring time proportional to its capacity. * *

      A linked hash set has two parameters that affect its performance: * initial capacity and load factor. They are defined precisely - * as for HashSet. Note, however, that the penalty for choosing an + * as for {@code HashSet}. Note, however, that the penalty for choosing an * excessively high value for initial capacity is less severe for this class - * than for HashSet, as iteration times for this class are unaffected + * than for {@code HashSet}, as iteration times for this class are unaffected * by capacity. * *

      Note that this implementation is not synchronized. @@ -83,9 +83,9 @@ * unsynchronized access to the set:

        *   Set s = Collections.synchronizedSet(new LinkedHashSet(...));
      * - *

      The iterators returned by this class's iterator method are + *

      The iterators returned by this class's {@code iterator} method are * fail-fast: if the set is modified at any time after the iterator - * is created, in any way except through the iterator's own remove + * is created, in any way except through the iterator's own {@code remove} * method, the iterator will throw a {@link ConcurrentModificationException}. * Thus, in the face of concurrent modification, the iterator fails quickly * and cleanly, rather than risking arbitrary, non-deterministic behavior at @@ -94,13 +94,13 @@ *

      Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. * *

      This class is a member of the - * + * * Java Collections Framework. * * @param the type of elements maintained by this set diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedList.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedList.java index d5d3437e13..3b1f8b705a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedList.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LinkedList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -72,7 +72,7 @@ * should be used only to detect bugs. * *

      This class is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch @@ -90,18 +90,22 @@ public class LinkedList /** * Pointer to first node. - * Invariant: (first == null && last == null) || - * (first.prev == null && first.item != null) */ transient Node first; /** * Pointer to last node. - * Invariant: (first == null && last == null) || - * (last.next == null && last.item != null) */ transient Node last; + /* + void dataStructureInvariants() { + assert (size == 0) + ? (first == null && last == null) + : (first.prev == null && last.next == null); + } + */ + /** * Constructs an empty list. */ @@ -310,13 +314,13 @@ public void addLast(E e) { * Returns {@code true} if this list contains the specified element. * More formally, returns {@code true} if and only if this list contains * at least one element {@code e} such that - * (o==null ? e==null : o.equals(e)). + * {@code Objects.equals(o, e)}. * * @param o element whose presence in this list is to be tested * @return {@code true} if this list contains the specified element */ public boolean contains(Object o) { - return indexOf(o) != -1; + return indexOf(o) >= 0; } /** @@ -346,7 +350,7 @@ public boolean add(E e) { * if it is present. If this list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index * {@code i} such that - * (o==null ? get(i)==null : o.equals(get(i))) + * {@code Objects.equals(o, get(i))} * (if such an element exists). Returns {@code true} if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). @@ -587,7 +591,7 @@ Node node(int index) { * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index {@code i} such that - * (o==null ? get(i)==null : o.equals(get(i))), + * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. * * @param o element to search for @@ -616,7 +620,7 @@ public int indexOf(Object o) { * Returns the index of the last occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the highest index {@code i} such that - * (o==null ? get(i)==null : o.equals(get(i))), + * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. * * @param o element to search for @@ -871,7 +875,7 @@ public ListIterator listIterator(int index) { } private class ListItr implements ListIterator { - private Node lastReturned = null; + private Node lastReturned; private Node next; private int nextIndex; private int expectedModCount = modCount; @@ -952,7 +956,6 @@ public void add(E e) { expectedModCount++; } - @Override public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); while (modCount == expectedModCount && nextIndex < size) { @@ -1170,7 +1173,7 @@ private void readObject(java.io.ObjectInputStream s) */ @Override public Spliterator spliterator() { - return new LLSpliterator(this, -1, 0); + return new LLSpliterator<>(this, -1, 0); } /** A customized variant of Spliterators.IteratorSpliterator */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/List.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/List.java index 3f05797cc2..fca40ac999 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/List.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/List.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -88,15 +88,16 @@ * Such exceptions are marked as "optional" in the specification for this * interface. * - *

      Immutable List Static Factory Methods

      - *

      The {@link List#of(Object...) List.of()} static factory methods - * provide a convenient way to create immutable lists. The {@code List} + *

      Unmodifiable Lists

      + *

      The {@link List#of(Object...) List.of} and + * {@link List#copyOf List.copyOf} static factory methods + * provide a convenient way to create unmodifiable lists. The {@code List} * instances created by these methods have the following characteristics: * *

        - *
      • They are structurally immutable. Elements cannot be added, removed, - * or replaced. Calling any mutator method will always cause - * {@code UnsupportedOperationException} to be thrown. + *
      • They are unmodifiable. Elements cannot + * be added, removed, or replaced. Calling any mutator method on the List + * will always cause {@code UnsupportedOperationException} to be thrown. * However, if the contained elements are themselves mutable, * this may cause the List's contents to appear to change. *
      • They disallow {@code null} elements. Attempts to create them with @@ -795,4 +796,287 @@ default Spliterator spliterator() { } } + /** + * Returns an unmodifiable list containing zero elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @return an empty {@code List} + * + * @since 9 + */ + static List of() { + return ImmutableCollections.emptyList(); + } + + /** + * Returns an unmodifiable list containing one element. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the single element + * @return a {@code List} containing the specified element + * @throws NullPointerException if the element is {@code null} + * + * @since 9 + */ + static List of(E e1) { + return new ImmutableCollections.List12<>(e1); + } + + /** + * Returns an unmodifiable list containing two elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2) { + return new ImmutableCollections.List12<>(e1, e2); + } + + /** + * Returns an unmodifiable list containing three elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3) { + return new ImmutableCollections.ListN<>(e1, e2, e3); + } + + /** + * Returns an unmodifiable list containing four elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4) { + return new ImmutableCollections.ListN<>(e1, e2, e3, e4); + } + + /** + * Returns an unmodifiable list containing five elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5) { + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5); + } + + /** + * Returns an unmodifiable list containing six elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6) { + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6); + } + + /** + * Returns an unmodifiable list containing seven elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7); + } + + /** + * Returns an unmodifiable list containing eight elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @param e8 the eighth element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7, e8); + } + + /** + * Returns an unmodifiable list containing nine elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @param e8 the eighth element + * @param e9 the ninth element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9); + } + + /** + * Returns an unmodifiable list containing ten elements. + * + * See Unmodifiable Lists for details. + * + * @param the {@code List}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @param e8 the eighth element + * @param e9 the ninth element + * @param e10 the tenth element + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} + * + * @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 new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10); + } + + /** + * Returns an unmodifiable list containing an arbitrary number of elements. + * See Unmodifiable Lists for details. + * + * @apiNote + * This method also accepts a single array as an argument. The element type of + * the resulting list will be the component type of the array, and the size of + * the list will be equal to the length of the array. To create a list with + * a single element that is an array, do the following: + * + *
        {@code
        +     *     String[] array = ... ;
        +     *     List list = List.of(array);
        +     * }
        + * + * This will cause the {@link List#of(Object) List.of(E)} method + * to be invoked instead. + * + * @param the {@code List}'s element type + * @param elements the elements to be contained in the list + * @return a {@code List} containing the specified elements + * @throws NullPointerException if an element is {@code null} or if the array is {@code null} + * + * @since 9 + */ + @SafeVarargs + @SuppressWarnings("varargs") + static List of(E... elements) { + switch (elements.length) { // implicit null check of elements + case 0: + return ImmutableCollections.emptyList(); + case 1: + return new ImmutableCollections.List12<>(elements[0]); + case 2: + return new ImmutableCollections.List12<>(elements[0], elements[1]); + default: + return new ImmutableCollections.ListN<>(elements); + } + } + + /** + * Returns an unmodifiable List containing the elements of + * the given Collection, in its iteration order. The given Collection must not be null, + * and it must not contain any null elements. If the given Collection is subsequently + * modified, the returned List will not reflect such modifications. + * + * @implNote + * If the given Collection is an unmodifiable List, + * calling copyOf will generally not create a copy. + * + * @param the {@code List}'s element type + * @param coll a {@code Collection} from which elements are drawn, must be non-null + * @return a {@code List} containing the elements of the given {@code Collection} + * @throws NullPointerException if coll is null, or if it contains any nulls + * @since 10 + */ + static List copyOf(Collection coll) { + return ImmutableCollections.listCopy(coll); + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListIterator.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListIterator.java index 6ad98fe3fa..365daf0cb3 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListIterator.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -46,7 +46,7 @@ * {@link #previous()}. * *

        This interface is a member of the - * + * * Java Collections Framework. * * @author Josh Bloch diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListResourceBundle.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListResourceBundle.java index 99090ca80b..053d70b1cf 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListResourceBundle.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ListResourceBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, 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 @@ -43,24 +43,24 @@ import sun.util.ResourceBundleEnumeration; /** - * ListResourceBundle is an abstract subclass of - * ResourceBundle that manages resources for a locale - * in a convenient and easy to use list. See ResourceBundle for + * {@code ListResourceBundle} is an abstract subclass of + * {@code ResourceBundle} that manages resources for a locale + * in a convenient and easy to use list. See {@code ResourceBundle} for * more information about resource bundles in general. * *

        - * Subclasses must override getContents and provide an array, + * Subclasses must override {@code getContents} and provide an array, * where each item in the array is a pair of objects. * The first element of each pair is the key, which must be a - * String, and the second element is the value associated with + * {@code String}, and the second element is the value associated with * that key. * *

        - * The following example shows two members of a resource + * The following example shows two members of a resource * bundle family with the base name "MyResources". * "MyResources" is the default member of the bundle family, and * "MyResources_fr" is the French member. - * These members are based on ListResourceBundle + * These members are based on {@code ListResourceBundle} * (a related example shows * how you can add a bundle to this family that's based on a properties file). * The keys in this example are of the form "s1" etc. The actual @@ -113,7 +113,7 @@ * * @see ResourceBundle * @see PropertyResourceBundle - * @since JDK1.1 + * @since 1.1 */ public abstract class ListResourceBundle extends ResourceBundle { /** @@ -136,11 +136,11 @@ public final Object handleGetObject(String key) { } /** - * Returns an Enumeration of the keys contained in - * this ResourceBundle and its parent bundles. + * Returns an {@code Enumeration} of the keys contained in + * this {@code ResourceBundle} and its parent bundles. * - * @return an Enumeration of the keys contained in - * this ResourceBundle and its parent bundles. + * @return an {@code Enumeration} of the keys contained in + * this {@code ResourceBundle} and its parent bundles. * @see #keySet() */ public Enumeration getKeys() { @@ -155,11 +155,11 @@ public Enumeration getKeys() { } /** - * Returns a Set of the keys contained - * only in this ResourceBundle. + * Returns a {@code Set} of the keys contained + * only in this {@code ResourceBundle}. * - * @return a Set of the keys contained only in this - * ResourceBundle + * @return a {@code Set} of the keys contained only in this + * {@code ResourceBundle} * @since 1.6 * @see #keySet() */ @@ -172,15 +172,15 @@ protected Set handleKeySet() { /** * Returns an array in which each item is a pair of objects in an - * Object array. The first element of each pair is - * the key, which must be a String, and the second + * {@code Object} array. The first element of each pair is + * the key, which must be a {@code String}, and the second * element is the value associated with that key. See the class * description for details. * - * @return an array of an Object array representing a + * @return an array of an {@code Object} array representing a * key-value pair. */ - abstract protected Object[][] getContents(); + protected abstract Object[][] getContents(); // ==================privates==================== @@ -194,10 +194,10 @@ private synchronized void loadLookup() { Object[][] contents = getContents(); HashMap temp = new HashMap<>(contents.length); - for (int i = 0; i < contents.length; ++i) { + for (Object[] content : contents) { // key must be non-null String, value must be non-null - String key = (String) contents[i][0]; - Object value = contents[i][1]; + String key = (String) content[0]; + Object value = content[1]; if (key == null || value == null) { throw new NullPointerException(); } @@ -206,8 +206,5 @@ private synchronized void loadLookup() { lookup = temp; } - // Android-changed: Fix unsafe publication http://b/31467561 - // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae - // was: private Map lookup = null; - private volatile Map lookup = null; + private volatile Map lookup; } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Locale.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Locale.java index aa1406056e..cfc86d6700 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Locale.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Locale.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, 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 @@ -50,6 +50,9 @@ import java.io.ObjectStreamField; import java.io.Serializable; import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + import libcore.icu.ICU; import sun.util.locale.BaseLocale; @@ -83,7 +86,7 @@ * described below. * *

        - *
        language
        + *
        language
        * *
        ISO 639 alpha-2 or alpha-3 language code, or registered * language subtags up to 8 alpha letters (for future enhancements). @@ -94,14 +97,14 @@ * Locale always canonicalizes to lower case.
        * *
        Well-formed language values have the form - * [a-zA-Z]{2,8}. Note that this is not the the full + * [a-zA-Z]{2,8}. Note that this is not the full * BCP47 language production, since it excludes extlang. They are * not needed since modern three-letter language codes replace * them.
        * *
        Example: "en" (English), "ja" (Japanese), "kok" (Konkani)
        * - *
        script
        + *
        script
        * *
        ISO 15924 alpha-4 script code. You can find a full list of * valid script codes in the IANA Language Subtag Registry (search @@ -115,7 +118,7 @@ * *
        Example: "Latn" (Latin), "Cyrl" (Cyrillic)
        * - *
        country (region)
        + *
        country (region)
        * *
        ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code. * You can find a full list of valid country and region codes in the @@ -129,7 +132,7 @@ *
        Example: "US" (United States), "FR" (France), "029" * (Caribbean)
        * - *
        variant
        + *
        variant
        * *
        Any arbitrary value used to indicate a variation of a * Locale. Where there are two or more variant values @@ -160,7 +163,7 @@ * *
        Example: "polyton" (Polytonic Greek), "POSIX"
        * - *
        extensions
        + *
        extensions
        * *
        A map from single character keys to string values, indicating * extensions apart from language identification. The extensions in @@ -188,7 +191,7 @@ * requirement (is well-formed), but does not validate the value * itself. See {@link Builder} for details. * - *

        Unicode locale/language extension

        + *

        Unicode locale/language extension

        * *

        UTS#35, "Unicode Locale Data Markup Language" defines optional * attributes and keywords to override or refine the default behavior @@ -199,7 +202,7 @@ * *

        The keywords are mapped to a BCP 47 extension value using the * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above - * example, "nu-thai", becomes the extension "u-nu-thai".code + * example, "nu-thai", becomes the extension "u-nu-thai". * *

        Thus, when a Locale object contains Unicode locale * attributes and keywords, @@ -269,7 +272,7 @@ * * * - *

        Locale Matching

        + *

        Locale Matching

        * *

        If an application or a system is internationalized and provides localized * resources for multiple locales, it sometimes needs to find one or more @@ -408,28 +411,28 @@ * Clients desiring a string representation of the complete locale can * then always rely on toLanguageTag for this purpose. * - *

        Special cases
        + *
        Special cases
        * *

        For compatibility reasons, two * non-conforming locales are treated as special cases. These are - * ja_JP_JP and th_TH_TH. These are ill-formed + * {@code ja_JP_JP} and {@code th_TH_TH}. These are ill-formed * in BCP 47 since the variants are too short. To ease migration to BCP 47, * these are treated specially during construction. These two cases (and only * these) cause a constructor to generate an extension, all other values behave * exactly as they did prior to Java 7. * - *

        Java has used ja_JP_JP to represent Japanese as used in + *

        Java has used {@code ja_JP_JP} to represent Japanese as used in * Japan together with the Japanese Imperial calendar. This is now * representable using a Unicode locale extension, by specifying the - * Unicode locale key ca (for "calendar") and type - * japanese. When the Locale constructor is called with the + * Unicode locale key {@code ca} (for "calendar") and type + * {@code japanese}. When the Locale constructor is called with the * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is * automatically added. * - *

        Java has used th_TH_TH to represent Thai as used in + *

        Java has used {@code th_TH_TH} to represent Thai as used in * Thailand together with Thai digits. This is also now representable using * a Unicode locale extension, by specifying the Unicode locale key - * nu (for "number") and value thai. When the Locale + * {@code nu} (for "number") and value {@code thai}. When the Locale * constructor is called with the arguments "th", "TH", "TH", the * extension "u-nu-thai" is automatically added. * @@ -445,9 +448,9 @@ *

        Legacy language codes
        * *

        Locale's constructor has always converted three language codes to - * their earlier, obsoleted forms: he maps to iw, - * yi maps to ji, and id maps to - * in. This continues to be the case, in order to not break + * their earlier, obsoleted forms: {@code he} maps to {@code iw}, + * {@code yi} maps to {@code ji}, and {@code id} maps to + * {@code in}. This continues to be the case, in order to not break * backwards compatibility. * *

        The APIs added in 1.7 map between the old and new language codes, @@ -533,7 +536,7 @@ *

    *
    GregorianCalendar default field values
    Field
    + *
    + * Field * Default Value
    + *
    + Default Value *
    - * ERA
    - *
    - * AD
    + *
    + * ERA + * + * AD *
    - * YEAR
    - *
    - * 1970
    + *
    + * YEAR + * + * 1970 *
    - * MONTH
    - *
    - * JANUARY
    + *
    + * MONTH + * + * JANUARY *
    - * DAY_OF_MONTH
    - *
    - * 1
    + *
    + * DAY_OF_MONTH + * + * 1 *
    - * DAY_OF_WEEK
    - *
    - * the first day of week
    + *
    + * DAY_OF_WEEK + * + * the first day of week *
    - * WEEK_OF_MONTH
    - *
    - * 0
    + *
    + * WEEK_OF_MONTH + * + * 0 *
    - * DAY_OF_WEEK_IN_MONTH
    - *
    - * 1
    + *
    + * DAY_OF_WEEK_IN_MONTH + * + * 1 *
    - * AM_PM
    - *
    - * AM
    + *
    + * AM_PM + * + * AM *
    - * HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND
    - *
    - * 0
    + *
    + * HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND + * + * 0 *
    Unicode 11.0
    * - *

    Be wary of the default locale

    + *

    Be wary of the default locale

    *

    Note that there are many convenience methods that automatically use the default locale, but * using them may lead to subtle bugs. * @@ -572,91 +575,91 @@ */ public final class Locale implements Cloneable, Serializable { - static private final Cache LOCALECACHE = new Cache(); + private static final Cache LOCALECACHE = new Cache(); /** Useful constant for language. */ - static public final Locale ENGLISH = createConstant("en", ""); + public static final Locale ENGLISH = createConstant("en", ""); /** Useful constant for language. */ - static public final Locale FRENCH = createConstant("fr", ""); + public static final Locale FRENCH = createConstant("fr", ""); /** Useful constant for language. */ - static public final Locale GERMAN = createConstant("de", ""); + public static final Locale GERMAN = createConstant("de", ""); /** Useful constant for language. */ - static public final Locale ITALIAN = createConstant("it", ""); + public static final Locale ITALIAN = createConstant("it", ""); /** Useful constant for language. */ - static public final Locale JAPANESE = createConstant("ja", ""); + public static final Locale JAPANESE = createConstant("ja", ""); /** Useful constant for language. */ - static public final Locale KOREAN = createConstant("ko", ""); + public static final Locale KOREAN = createConstant("ko", ""); /** Useful constant for language. */ - static public final Locale CHINESE = createConstant("zh", ""); + public static final Locale CHINESE = createConstant("zh", ""); /** Useful constant for language. */ - static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); + public static final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); /** Useful constant for language. */ - static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); + public static final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); /** Useful constant for country. */ - static public final Locale FRANCE = createConstant("fr", "FR"); + public static final Locale FRANCE = createConstant("fr", "FR"); /** Useful constant for country. */ - static public final Locale GERMANY = createConstant("de", "DE"); + public static final Locale GERMANY = createConstant("de", "DE"); /** Useful constant for country. */ - static public final Locale ITALY = createConstant("it", "IT"); + public static final Locale ITALY = createConstant("it", "IT"); /** Useful constant for country. */ - static public final Locale JAPAN = createConstant("ja", "JP"); + public static final Locale JAPAN = createConstant("ja", "JP"); /** Useful constant for country. */ - static public final Locale KOREA = createConstant("ko", "KR"); + public static final Locale KOREA = createConstant("ko", "KR"); /** Useful constant for country. */ - static public final Locale CHINA = SIMPLIFIED_CHINESE; + public static final Locale CHINA = SIMPLIFIED_CHINESE; /** Useful constant for country. */ - static public final Locale PRC = SIMPLIFIED_CHINESE; + public static final Locale PRC = SIMPLIFIED_CHINESE; /** Useful constant for country. */ - static public final Locale TAIWAN = TRADITIONAL_CHINESE; + public static final Locale TAIWAN = TRADITIONAL_CHINESE; /** Useful constant for country. */ - static public final Locale UK = createConstant("en", "GB"); + public static final Locale UK = createConstant("en", "GB"); /** Useful constant for country. */ - static public final Locale US = createConstant("en", "US"); + public static final Locale US = createConstant("en", "US"); /** Useful constant for country. */ - static public final Locale CANADA = createConstant("en", "CA"); + public static final Locale CANADA = createConstant("en", "CA"); /** Useful constant for country. */ - static public final Locale CANADA_FRENCH = createConstant("fr", "CA"); + public static final Locale CANADA_FRENCH = createConstant("fr", "CA"); // Android-added: (internal only): ISO 639-3 generic code for undetermined languages. private static final String UNDETERMINED_LANGUAGE = "und"; @@ -669,7 +672,7 @@ public final class Locale implements Cloneable, Serializable { * * @since 1.6 */ - static public final Locale ROOT = createConstant("", ""); + public static final Locale ROOT = createConstant("", ""); /** * The key for the private use extension ('x'). @@ -678,7 +681,7 @@ public final class Locale implements Cloneable, Serializable { * @see Builder#setExtension(char, String) * @since 1.7 */ - static public final char PRIVATE_USE_EXTENSION = 'x'; + public static final char PRIVATE_USE_EXTENSION = 'x'; /** * The key for Unicode locale extension ('u'). @@ -687,19 +690,84 @@ public final class Locale implements Cloneable, Serializable { * @see Builder#setExtension(char, String) * @since 1.7 */ - static public final char UNICODE_LOCALE_EXTENSION = 'u'; + public static final char UNICODE_LOCALE_EXTENSION = 'u'; /** serialization ID */ static final long serialVersionUID = 9149081749638150636L; + /** + * Enum for specifying the type defined in ISO 3166. This enum is used to + * retrieve the two-letter ISO3166-1 alpha-2, three-letter ISO3166-1 + * alpha-3, four-letter ISO3166-3 country codes. + * + * @see #getISOCountries(Locale.IsoCountryCode) + * @since 9 + */ + public static enum IsoCountryCode { + /** + * PART1_ALPHA2 is used to represent the ISO3166-1 alpha-2 two letter + * country codes. + */ + PART1_ALPHA2 { + @Override + Set createCountryCodeSet() { + return Set.of(Locale.getISOCountries()); + } + }, + + /** + * + * PART1_ALPHA3 is used to represent the ISO3166-1 alpha-3 three letter + * country codes. + */ + /* J2ObjC removed. + PART1_ALPHA3 { + @Override + Set createCountryCodeSet() { + return LocaleISOData.computeISO3166_1Alpha3Countries(); + } + }, + + /** + * PART3 is used to represent the ISO3166-3 four letter country codes. + * / + PART3 { + @Override + Set createCountryCodeSet() { + return Set.of(LocaleISOData.ISO3166_3); + } + }*/; + + /** + * Concrete implementation of this method attempts to compute value + * for iso3166CodesMap for each IsoCountryCode type key. + */ + abstract Set createCountryCodeSet(); + + /** + * Map to hold country codes for each ISO3166 part. + */ + private static Map> iso3166CodesMap = new ConcurrentHashMap<>(); + + /** + * This method is called from Locale class to retrieve country code set + * for getISOCountries(type) + */ + static Set retrieveISOCountryCodes(IsoCountryCode type) { + return iso3166CodesMap.computeIfAbsent(type, IsoCountryCode::createCountryCodeSet); + } + } + /** * Display types for retrieving localized names from the name providers. */ - private static final int DISPLAY_LANGUAGE = 0; - private static final int DISPLAY_COUNTRY = 1; - private static final int DISPLAY_VARIANT = 2; - private static final int DISPLAY_SCRIPT = 3; + private static final int DISPLAY_LANGUAGE = 0; + private static final int DISPLAY_COUNTRY = 1; + private static final int DISPLAY_VARIANT = 2; + private static final int DISPLAY_SCRIPT = 3; + private static final int DISPLAY_UEXT_KEY = 4; + private static final int DISPLAY_UEXT_TYPE = 5; /** * Private constructor used by getInstance method @@ -811,7 +879,7 @@ private static Locale createConstant(String lang, String country) { * created and cached. * * @param language lowercase 2 to 8 language code. - * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code. + * @param country uppercase two-letter ISO-3166 code and numeric-3 UN M.49 area code. * @param variant vendor and browser specific code. See class description. * @return the Locale instance requested * @exception NullPointerException if any argument is null. @@ -835,17 +903,41 @@ static Locale getInstance(String language, String script, String country, } static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) { - LocaleKey key = new LocaleKey(baseloc, extensions); - return LOCALECACHE.get(key); + if (extensions == null) { + return LOCALECACHE.get(baseloc); + } else { + LocaleKey key = new LocaleKey(baseloc, extensions); + return LOCALECACHE.get(key); + } } - private static class Cache extends LocaleObjectCache { + // BEGIN Android-added: Add a static method to clear the stale entries in Zygote + /** + * This method cleans the stale entries in LOCALECACHE. This would + * be called in Zygote after GC but before fork, and so to avoid the + * cleaning of the cache to happen in child processes. + * + * @hide + */ + /* J2ObjC removed. + public static void cleanCache() { + LOCALECACHE.cleanStaleEntries(); + } + END Android-added: Add a static method to clear the stale entries in Zygote + */ + + private static class Cache extends LocaleObjectCache { private Cache() { } @Override - protected Locale createObject(LocaleKey key) { - return new Locale(key.base, key.exts); + protected Locale createObject(Object key) { + if (key instanceof BaseLocale) { + return new Locale((BaseLocale)key, null); + } else { + LocaleKey lk = (LocaleKey)key; + return new Locale(lk.base, lk.exts); + } } } @@ -919,7 +1011,7 @@ public static Locale getDefault() { * setDefault(Locale.Category, Locale) method. * * @param category - the specified category to get the default locale - * @throws NullPointerException - if category is null + * @throws NullPointerException if category is null * @return the default locale for the specified Category for this instance * of the Java Virtual Machine * @see #setDefault(Locale.Category, Locale) @@ -969,6 +1061,10 @@ public static Locale initDefault() { // BEGIN Android-changed: Short-circuit legacy security code. // Use System.getProperty(name, default) instead of // AccessController.doPrivileged(new GetPropertyAction(name, default)). + // Properties props = GetPropertyAction.privilegedGetProperties(); + // language = props.getProperty("user.language", "en"); + // for compatibility, check for old user.region property + // region = props.getProperty("user.region"); String language, region, script, country, variant; language = System.getProperty("user.language", "en"); // for compatibility, check for old user.region property @@ -985,13 +1081,20 @@ public static Locale initDefault() { } script = ""; } else { + // script = props.getProperty("user.script", ""); + // country = props.getProperty("user.country", ""); + // variant = props.getProperty("user.variant", ""); script = System.getProperty("user.script", ""); country = System.getProperty("user.country", ""); variant = System.getProperty("user.variant", ""); } + // return getInstance(language, script, country, variant, + // getDefaultExtensions(props.getProperty("user.extensions", "")) + // .orElse(null)); + LocaleExtensions extension = getDefaultExtensions(System.getProperty("user.extensions", "")) + .orElse(null); + return getInstance(language, script, country, variant, extension); // END Android-changed: Short-circuit legacy security code. - - return getInstance(language, script, country, variant, null); } private static Locale initDefault(Locale.Category category) { @@ -999,16 +1102,19 @@ private static Locale initDefault(Locale.Category category) { final Locale defaultLocale = NoImagePreloadHolder.defaultLocale; // BEGIN Android-changed: Short-circuit legacy security code. /* + Properties props = GetPropertyAction.privilegedGetProperties(); + return getInstance( - AccessController.doPrivileged( - new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())), - AccessController.doPrivileged( - new GetPropertyAction(category.scriptKey, defaultLocale.getScript())), - AccessController.doPrivileged( - new GetPropertyAction(category.countryKey, defaultLocale.getCountry())), - AccessController.doPrivileged( - new GetPropertyAction(category.variantKey, defaultLocale.getVariant())), - null); + props.getProperty(category.languageKey, + defaultLocale.getLanguage()), + props.getProperty(category.scriptKey, + defaultLocale.getScript()), + props.getProperty(category.countryKey, + defaultLocale.getCountry()), + props.getProperty(category.variantKey, + defaultLocale.getVariant()), + getDefaultExtensions(props.getProperty(category.extensionsKey, "")) + .orElse(defaultLocale.getLocaleExtensions())); */ return getInstance( System.getProperty(category.languageKey, defaultLocale.getLanguage()), @@ -1019,6 +1125,20 @@ private static Locale initDefault(Locale.Category category) { // END Android-changed: Short-circuit legacy security code. } + private static Optional getDefaultExtensions(String extensionsProp) { + LocaleExtensions exts = null; + + try { + exts = new InternalLocaleBuilder() + .setExtensions(extensionsProp) + .getLocaleExtensions(); + } catch (LocaleSyntaxException e) { + // just ignore this incorrect property + } + + return Optional.ofNullable(exts); + } + /** * Sets the default locale for this instance of the Java Virtual Machine. * This does not affect the host locale. @@ -1073,13 +1193,12 @@ public static synchronized void setDefault(Locale newLocale) { * functionality, this method should only be used if the caller is * prepared to reinitialize locale-sensitive code running within the * same Java Virtual Machine. - *

    * * @param category - the specified category to set the default locale * @param newLocale - the new default locale - * @throws SecurityException - if a security manager exists and its + * @throws SecurityException if a security manager exists and its * checkPermission method doesn't allow the operation. - * @throws NullPointerException - if category and/or newLocale is null + * @throws NullPointerException if category and/or newLocale is null * @see SecurityManager#checkPermission(java.security.Permission) * @see PropertyPermission * @see #getDefault(Locale.Category) @@ -1124,12 +1243,18 @@ public static Locale[] getAvailableLocales() { /** * Returns a list of all 2-letter country codes defined in ISO 3166. * Can be used to create Locales. + * This method is equivalent to {@link #getISOCountries(Locale.IsoCountryCode type)} + * with {@code type} {@link IsoCountryCode#PART1_ALPHA2}. *

    * Note: The Locale class also supports other codes for * country (region), such as 3-letter numeric UN M.49 area codes. * Therefore, the list returned by this method does not contain ALL valid * codes that can be used to create Locales. - * + *

    + * Note that this method does not return obsolete 2-letter country codes. + * ISO3166-3 codes which designate country codes for those obsolete codes, + * can be retrieved from {@link #getISOCountries(Locale.IsoCountryCode type)} with + * {@code type} {@link IsoCountryCode#PART3}. * @return An array of ISO 3166 two-letter country codes. */ public static String[] getISOCountries() { @@ -1145,6 +1270,20 @@ public static String[] getISOCountries() { return ICU.getISOCountries(); } + /** + * Returns a {@code Set} of ISO3166 country codes for the specified type. + * + * @param type {@link Locale.IsoCountryCode} specified ISO code type. + * @see java.util.Locale.IsoCountryCode + * @throws NullPointerException if type is null + * @return a {@code Set} of ISO country codes for the specified type. + * @since 9 + */ + public static Set getISOCountries(IsoCountryCode type) { + Objects.requireNonNull(type); + return IsoCountryCode.retrieveISOCountryCodes(type); + } + /** * Returns a list of all 2-letter language codes defined in ISO 639. * Can be used to create Locales. @@ -1159,7 +1298,7 @@ public static String[] getISOCountries() { * not contain ALL valid codes that can be used to create Locales. * * - * @return Am array of ISO 639 two-letter language codes. + * @return An array of ISO 639 two-letter language codes. */ public static String[] getISOLanguages() { // Android-changed: Use ICU. @@ -1371,7 +1510,7 @@ BaseLocale getBaseLocale() { /** * Package private method returning the Locale's LocaleExtensions, * used by ResourceBundle. - * @return locale exnteions of this Locale, + * @return locale extensions of this Locale, * or {@code null} if no extensions are defined */ LocaleExtensions getLocaleExtensions() { @@ -1383,7 +1522,7 @@ LocaleExtensions getLocaleExtensions() { * object, consisting of language, country, variant, script, * and extensions as below: *

    - * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions + * language + "_" + country + "_" + (variant + "_#" | "#") + script + "_" + extensions *
    * * Language is always lower case, country is always upper case, script is always title @@ -1407,14 +1546,14 @@ LocaleExtensions getLocaleExtensions() { * {@link #toLanguageTag}. * *

    Examples:

      - *
    • en
    • - *
    • de_DE
    • - *
    • _GB
    • - *
    • en_US_WIN
    • - *
    • de__POSIX
    • - *
    • zh_CN_#Hans
    • - *
    • zh_TW_#Hant-x-java
    • - *
    • th_TH_TH_#u-nu-thai
    + *
  • {@code en}
  • + *
  • {@code de_DE}
  • + *
  • {@code _GB}
  • + *
  • {@code en_US_WIN}
  • + *
  • {@code de__POSIX}
  • + *
  • {@code zh_CN_#Hans}
  • + *
  • {@code zh_TW_#Hant_x-java}
  • + *
  • {@code th_TH_TH_#u-nu-thai}
  • * * @return A string representation of the Locale, for debugging. * @see #getDisplayName @@ -1422,11 +1561,11 @@ LocaleExtensions getLocaleExtensions() { */ @Override public final String toString() { - boolean l = (baseLocale.getLanguage().length() != 0); - boolean s = (baseLocale.getScript().length() != 0); - boolean r = (baseLocale.getRegion().length() != 0); - boolean v = (baseLocale.getVariant().length() != 0); - boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0); + boolean l = !baseLocale.getLanguage().isEmpty(); + boolean s = !baseLocale.getScript().isEmpty(); + boolean r = !baseLocale.getRegion().isEmpty(); + boolean v = !baseLocale.getVariant().isEmpty(); + boolean e = localeExtensions != null && !localeExtensions.getID().isEmpty(); StringBuilder result = new StringBuilder(baseLocale.getLanguage()); if (r || (l && (v || s || e))) { @@ -1530,18 +1669,18 @@ public String toLanguageTag() { StringBuilder buf = new StringBuilder(); String subtag = tag.getLanguage(); - if (subtag.length() > 0) { + if (!subtag.isEmpty()) { buf.append(LanguageTag.canonicalizeLanguage(subtag)); } subtag = tag.getScript(); - if (subtag.length() > 0) { + if (!subtag.isEmpty()) { buf.append(LanguageTag.SEP); buf.append(LanguageTag.canonicalizeScript(subtag)); } subtag = tag.getRegion(); - if (subtag.length() > 0) { + if (!subtag.isEmpty()) { buf.append(LanguageTag.SEP); buf.append(LanguageTag.canonicalizeRegion(subtag)); } @@ -1560,7 +1699,7 @@ public String toLanguageTag() { } subtag = tag.getPrivateuse(); - if (subtag.length() > 0) { + if (!subtag.isEmpty()) { if (buf.length() > 0) { buf.append(LanguageTag.SEP); } @@ -1644,44 +1783,50 @@ public String toLanguageTag() { * *

    Grandfathered tags with canonical replacements are as follows: * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * + *
    grandfathered tag modern replacement
    art-lojban jbo
    i-ami ami
    i-bnn bnn
    i-hak hak
    i-klingon tlh
    i-lux lb
    i-navajo nv
    i-pwn pwn
    i-tao tao
    i-tay tay
    i-tsu tsu
    no-bok nb
    no-nyn nn
    sgn-BE-FR sfb
    sgn-BE-NL vgt
    sgn-CH-DE sgg
    zh-guoyu cmn
    zh-hakka hak
    zh-min-nan nan
    zh-xiang hsn
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * * *
    Grandfathered tags with canonical replacements
    grandfathered tagmodern replacement
    art-lojbanjbo
    i-amiami
    i-bnnbnn
    i-hakhak
    i-klingontlh
    i-luxlb
    i-navajonv
    i-pwnpwn
    i-taotao
    i-taytay
    i-tsutsu
    no-boknb
    no-nynnn
    sgn-BE-FRsfb
    sgn-BE-NLvgt
    sgn-CH-DEsgg
    zh-guoyucmn
    zh-hakkahak
    zh-min-nannan
    zh-xianghsn
    * *

    Grandfathered tags with no modern replacement will be * converted as follows: * - * - * - * - * - * - * - * - * - * + *
    grandfathered tag converts to
    cel-gaulish xtg-x-cel-gaulish
    en-GB-oed en-GB-x-oed
    i-default en-x-i-default
    i-enochian und-x-i-enochian
    i-mingo see-x-i-mingo
    zh-min nan-x-zh-min
    + * + * + * + * + * + * + * + * + * + * + * * *
    Grandfathered tags with no modern replacement
    grandfathered tagconverts to
    cel-gaulishxtg-x-cel-gaulish
    en-GB-oeden-GB-x-oed
    i-defaulten-x-i-default
    i-enochianund-x-i-enochian
    i-mingosee-x-i-mingo
    zh-minnan-x-zh-min
    * @@ -1704,7 +1849,7 @@ public static Locale forLanguageTag(String languageTag) { bldr.setLanguageTag(tag); BaseLocale base = bldr.getBaseLocale(); LocaleExtensions exts = bldr.getLocaleExtensions(); - if (exts == null && base.getVariant().length() > 0) { + if (exts == null && !base.getVariant().isEmpty()) { exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(), base.getRegion(), base.getVariant()); } @@ -1851,7 +1996,7 @@ public final String getDisplayLanguage() { * @exception NullPointerException if inLocale is null * public String getDisplayLanguage(Locale inLocale) { - return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE); + return getDisplayString(baseLocale.getLanguage(), null, inLocale, DISPLAY_LANGUAGE); } */ /** @@ -1921,7 +2066,7 @@ private static boolean isAsciiAlphaNum(String string) { // END Android-changed: Documentation and behavior of getDisplay*(). /** - * Returns a name for the the locale's script that is appropriate for display to + * Returns a name for the locale's script that is appropriate for display to * the user. If possible, the name will be localized for the default * {@link Locale.Category#DISPLAY DISPLAY} locale. Returns * the empty string if this locale doesn't specify a script code. @@ -1948,7 +2093,7 @@ public String getDisplayScript() { */ public String getDisplayScript(Locale inLocale) { // BEGIN Android-changed: Use ICU. - // return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT); + // return getDisplayString(baseLocale.getScript(), null, inLocale, DISPLAY_SCRIPT); String scriptCode = baseLocale.getScript(); if (scriptCode.isEmpty()) { return ""; @@ -2006,29 +2151,24 @@ public final String getDisplayCountry() { * @exception NullPointerException if inLocale is null * public String getDisplayCountry(Locale inLocale) { - return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY); + return getDisplayString(baseLocale.getRegion(), null, inLocale, DISPLAY_COUNTRY); } - private String getDisplayString(String code, Locale inLocale, int type) { - if (code.length() == 0) { - return ""; - } + private String getDisplayString(String code, String cat, Locale inLocale, int type) { + Objects.requireNonNull(inLocale); + Objects.requireNonNull(code); - if (inLocale == null) { - throw new NullPointerException(); + if (code.isEmpty()) { + return ""; } LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(LocaleNameProvider.class); - String key = (type == DISPLAY_VARIANT ? "%%"+code : code); + String rbKey = (type == DISPLAY_VARIANT ? "%%"+code : code); String result = pool.getLocalizedObject( LocaleNameGetter.INSTANCE, - inLocale, key, type, code); - if (result != null) { - return result; - } - - return code; + inLocale, rbKey, type, code, cat); + return result != null ? result : code; } */ /** @@ -2134,17 +2274,18 @@ public String getDisplayVariant(Locale inLocale) { // BEGIN Android-changed: Documentation and behavior of getDisplay*(). // Use ICU; added private helper methods. /* - if (baseLocale.getVariant().length() == 0) + if (baseLocale.getVariant().isEmpty()) return ""; - LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); + LocaleResources lr = LocaleProviderAdapter + .getResourceBundleBased() + .getLocaleResources(inLocale); String names[] = getDisplayVariantArray(inLocale); // Get the localized patterns for formatting a list, and use // them to format the list. return formatList(names, - lr.getLocaleName("ListPattern"), lr.getLocaleName("ListCompositionPattern")); } */ @@ -2215,19 +2356,21 @@ private static boolean isValidVariantSubtag(String subTag) { /** * Returns a name for the locale that is appropriate for display to the * user. This will be the values returned by getDisplayLanguage(), - * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled - * into a single string. The the non-empty values are used in order, - * with the second and subsequent names in parentheses. For example: + * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and + * optional Unicode extensions + * assembled into a single string. The non-empty values are used in order, with + * the second and subsequent names in parentheses. For example: *

    - * language (script, country, variant)
    - * language (country)
    - * language (variant)
    - * script (country)
    - * country
    + * language (script, country, variant(, extension)*)
    + * language (country(, extension)*)
    + * language (variant(, extension)*)
    + * script (country(, extension)*)
    + * country (extension)*
    *
    - * depending on which fields are specified in the locale. If the - * language, script, country, and variant fields are all empty, - * this function returns the empty string. + * depending on which fields are specified in the locale. The field + * separator in the above parentheses, denoted as a comma character, may + * be localized depending on the locale. If the language, script, country, + * and variant fields are all empty, this function returns the empty string. * * @return The name of the locale appropriate to display. */ @@ -2240,27 +2383,31 @@ public final String getDisplayName() { /** * Returns a name for the locale that is appropriate for display * to the user. This will be the values returned by - * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(), - * and getDisplayVariant() assembled into a single string. - * The non-empty values are used in order, - * with the second and subsequent names in parentheses. For example: + * getDisplayLanguage(), getDisplayScript(),getDisplayCountry() + * getDisplayVariant(), and optional + * Unicode extensions assembled into a single string. The non-empty + * values are used in order, with the second and subsequent names in + * parentheses. For example: *
    - * language (script, country, variant)
    - * language (country)
    - * language (variant)
    - * script (country)
    - * country
    + * language (script, country, variant(, extension)*)
    + * language (country(, extension)*)
    + * language (variant(, extension)*)
    + * script (country(, extension)*)
    + * country (extension)*
    *
    - * depending on which fields are specified in the locale. If the - * language, script, country, and variant fields are all empty, - * this function returns the empty string. + * depending on which fields are specified in the locale. The field + * separator in the above parentheses, denoted as a comma character, may + * be localized depending on the locale. If the language, script, country, + * and variant fields are all empty, this function returns the empty string. * * @param inLocale The locale for which to retrieve the display name. * @return The name of the locale appropriate to display. * @throws NullPointerException if inLocale is null * public String getDisplayName(Locale inLocale) { - LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); + LocaleResources lr = LocaleProviderAdapter + .getResourceBundleBased() + .getLocaleResources(inLocale); String languageName = getDisplayLanguage(inLocale); String scriptName = getDisplayScript(inLocale); @@ -2269,40 +2416,49 @@ public String getDisplayName(Locale inLocale) { // Get the localized patterns for formatting a display name. String displayNamePattern = lr.getLocaleName("DisplayNamePattern"); - String listPattern = lr.getLocaleName("ListPattern"); String listCompositionPattern = lr.getLocaleName("ListCompositionPattern"); // The display name consists of a main name, followed by qualifiers. // Typically, the format is "MainName (Qualifier, Qualifier)" but this // depends on what pattern is stored in the display locale. - String mainName = null; - String[] qualifierNames = null; + String mainName; + String[] qualifierNames; // The main name is the language, or if there is no language, the script, // then if no script, the country. If there is no language/script/country // (an anomalous situation) then the display name is simply the variant's // display name. - if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) { + if (languageName.isEmpty() && scriptName.isEmpty() && countryName.isEmpty()) { if (variantNames.length == 0) { return ""; } else { - return formatList(variantNames, listPattern, listCompositionPattern); + return formatList(variantNames, listCompositionPattern); } } ArrayList names = new ArrayList<>(4); - if (languageName.length() != 0) { + if (!languageName.isEmpty()) { names.add(languageName); } - if (scriptName.length() != 0) { + if (!scriptName.isEmpty()) { names.add(scriptName); } - if (countryName.length() != 0) { + if (!countryName.isEmpty()) { names.add(countryName); } if (variantNames.length != 0) { names.addAll(Arrays.asList(variantNames)); } + // add Unicode extensions + if (localeExtensions != null) { + localeExtensions.getUnicodeLocaleAttributes().stream() + .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY)) + .forEach(names::add); + localeExtensions.getUnicodeLocaleKeys().stream() + .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale)) + .forEach(names::add); + } + // The first one in the main name mainName = names.get(0); @@ -2317,13 +2473,13 @@ public String getDisplayName(Locale inLocale) { // the qualifier; if there are no qualifiers, the third element is // unused by the format pattern. Object[] displayNames = { - new Integer(qualifierNames.length != 0 ? 2 : 1), + qualifierNames.length != 0 ? 2 : 1, mainName, // We could also just call formatList() and have it handle the empty // list case, but this is more efficient, and we want it to be // efficient since all the language-only locales will not have any // qualifiers. - qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null + qualifierNames.length != 0 ? formatList(qualifierNames, listCompositionPattern) : null }; if (displayNamePattern != null) { @@ -2472,15 +2628,15 @@ public boolean equals(Object obj) { /** * Calculated hashcode */ - private transient volatile int hashCodeValue = 0; + private transient volatile int hashCodeValue; // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization. // private volatile static Locale defaultLocale = initDefault(); private static class NoImagePreloadHolder { public volatile static Locale defaultLocale = initDefault(); } - private volatile static Locale defaultDisplayLocale = null; - private volatile static Locale defaultFormatLocale = null; + private static volatile Locale defaultDisplayLocale; + private static volatile Locale defaultFormatLocale; private transient volatile String languageTag; @@ -2499,7 +2655,7 @@ private String[] getDisplayVariantArray(Locale inLocale) { // For each variant token, lookup the display name. If // not found, use the variant name itself. for (int i=0; i TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.LONG, inLocale)) + .orElse(type); + break; + } + ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"), + getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY), + Optional.ofNullable(displayType).orElse(type)); + } + + return ret; + } + */ + // END Android-removed: Private helper getDisplayKeyTypeExtensionString() unused on Android. + /** * Format a list using given pattern strings. * If either of the patterns is null, then a the list is * formatted by concatenation with the delimiter ','. * @param stringList the list of strings to be formatted. - * @param listPattern should create a MessageFormat taking 0-3 arguments * and formatting them into a list. - * @param listCompositionPattern should take 2 arguments - * and is used by composeList. + * @param pattern should take 2 arguments for reduction * @return a string representing the list. */ - private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) { + private static String formatList(String[] stringList, String pattern) { // If we have no list patterns, compose the list in a simple, // non-localized way. - if (listPattern == null || listCompositionPattern == null) { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < stringList.length; ++i) { - if (i > 0) { - result.append(','); - } - result.append(stringList[i]); - } - return result.toString(); + if (pattern == null) { + return Arrays.stream(stringList).collect(Collectors.joining(",")); } - // Compose the list down to three elements if necessary - if (stringList.length > 3) { - MessageFormat format = new MessageFormat(listCompositionPattern); - stringList = composeList(format, stringList); + switch (stringList.length) { + case 0: + return ""; + case 1: + return stringList[0]; + default: + return Arrays.stream(stringList).reduce("", + (s1, s2) -> { + if (s1.equals("")) { + return s2; + } + if (s2.equals("")) { + return s1; + } + return MessageFormat.format(pattern, s1, s2); + }); } - - // Rebuild the argument list with the list length as the first element - Object[] args = new Object[stringList.length + 1]; - System.arraycopy(stringList, 0, args, 1, stringList.length); - args[0] = new Integer(stringList.length); - - // Format it using the pattern in the resource - MessageFormat format = new MessageFormat(listPattern); - return format.format(args); - } - - /** - * Given a list of strings, return a list shortened to three elements. - * Shorten it by applying the given format to the first two elements - * recursively. - * @param format a format which takes two arguments - * @param list a list of strings - * @return if the list is three elements or shorter, the same list; - * otherwise, a new list of three elements. - */ - private static String[] composeList(MessageFormat format, String[] list) { - if (list.length <= 3) return list; - - // Use the given format to compose the first two elements into one - String[] listItems = { list[0], list[1] }; - String newItem = format.format(listItems); - - // Form a new list one element shorter - String[] newList = new String[list.length-1]; - System.arraycopy(list, 2, newList, 1, newList.length-1); - newList[0] = newItem; - - // Recurse - return composeList(format, newList); } // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to @@ -2643,8 +2804,8 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE String extStr = (String)fields.get("extensions", ""); baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); // Android-changed: Handle null for backwards compatible deserialization. http://b/26387905 - // if (extStr.length() > 0) { - if (extStr != null && extStr.length() > 0) { + // if (!extStr.isEmpty()) { + if (extStr != null && !extStr.isEmpty()) { try { InternalLocaleBuilder bldr = new InternalLocaleBuilder(); bldr.setExtensions(extStr); @@ -2676,9 +2837,9 @@ private Object readResolve() throws java.io.ObjectStreamException { baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions); } - private static volatile String[] isoLanguages = null; + private static volatile String[] isoLanguages; - private static volatile String[] isoCountries = null; + private static volatile String[] isoCountries; private static String convertOldISOCodes(String language) { // we accept both the old and the new ISO codes for the languages whose ISO @@ -2702,13 +2863,13 @@ private static LocaleExtensions getCompatibilityExtensions(String language, LocaleExtensions extensions = null; // Special cases for backward compatibility support if (LocaleUtils.caseIgnoreMatch(language, "ja") - && script.length() == 0 + && script.isEmpty() && LocaleUtils.caseIgnoreMatch(country, "jp") && "JP".equals(variant)) { // ja_JP_JP -> u-ca-japanese (calendar = japanese) extensions = LocaleExtensions.CALENDAR_JAPANESE; } else if (LocaleUtils.caseIgnoreMatch(language, "th") - && script.length() == 0 + && script.isEmpty() && LocaleUtils.caseIgnoreMatch(country, "th") && "TH".equals(variant)) { // th_TH_TH -> u-nu-thai (numbersystem = thai) @@ -2732,9 +2893,10 @@ public String getObject(LocaleNameProvider localeNameProvider, Locale locale, String key, Object... params) { - assert params.length == 2; + assert params.length == 3; int type = (Integer)params[0]; String code = (String)params[1]; + String cat = (String)params[2]; switch(type) { case DISPLAY_LANGUAGE: @@ -2745,6 +2907,10 @@ public String getObject(LocaleNameProvider localeNameProvider, return localeNameProvider.getDisplayVariant(code, locale); case DISPLAY_SCRIPT: return localeNameProvider.getDisplayScript(code, locale); + case DISPLAY_UEXT_KEY: + return localeNameProvider.getDisplayUnicodeExtensionKey(code, locale); + case DISPLAY_UEXT_TYPE: + return localeNameProvider.getDisplayUnicodeExtensionType(code, cat, locale); default: assert false; // shouldn't happen } @@ -2754,24 +2920,6 @@ public String getObject(LocaleNameProvider localeNameProvider, } */ - // BEGIN Android-added: adjustLanguageCode(), for internal use only. - /** @hide for internal use only. */ - public static String adjustLanguageCode(String languageCode) { - String adjusted = languageCode.toLowerCase(Locale.US); - // Map new language codes to the obsolete language - // codes so the correct resource bundles will be used. - if (languageCode.equals("he")) { - adjusted = "iw"; - } else if (languageCode.equals("id")) { - adjusted = "in"; - } else if (languageCode.equals("yi")) { - adjusted = "ji"; - } - - return adjusted; - } - // END Android-added: adjustLanguageCode(), for internal use only. - /** * Enum for locale categories. These locale categories are used to get/set * the default locale for the specific functionality represented by the @@ -2790,7 +2938,8 @@ public enum Category { DISPLAY("user.language.display", "user.script.display", "user.country.display", - "user.variant.display"), + "user.variant.display", + "user.extensions.display"), /** * Category used to represent the default locale for @@ -2799,19 +2948,23 @@ public enum Category { FORMAT("user.language.format", "user.script.format", "user.country.format", - "user.variant.format"); + "user.variant.format", + "user.extensions.format"); - Category(String languageKey, String scriptKey, String countryKey, String variantKey) { + Category(String languageKey, String scriptKey, String countryKey, + String variantKey, String extensionsKey) { this.languageKey = languageKey; this.scriptKey = scriptKey; this.countryKey = countryKey; this.variantKey = variantKey; + this.extensionsKey = extensionsKey; } final String languageKey; final String scriptKey; final String countryKey; final String variantKey; + final String extensionsKey; } /** @@ -3099,7 +3252,7 @@ public Builder addUnicodeLocaleAttribute(String attribute) { * href="./Locale.html#def_locale_extension">well-formed or an exception * is thrown. * - *

    Attribute comparision for removal is case-insensitive. + *

    Attribute comparison for removal is case-insensitive. * * @param attribute the attribute * @return This builder. @@ -3108,13 +3261,7 @@ public Builder addUnicodeLocaleAttribute(String attribute) { * @see #setExtension(char, String) */ public Builder removeUnicodeLocaleAttribute(String attribute) { - // BEGIN Android-added: removeUnicodeLocaleAttribute(null) is documented to throw NPE. - // This could probably be contributed back to upstream. http://b/110752069 - if (attribute == null) { - throw new NullPointerException("attribute == null"); - } - // END Android-added: removeUnicodeLocaleAttribute(null) is documented to throw NPE. - + Objects.requireNonNull(attribute); try { localeBuilder.removeUnicodeLocaleAttribute(attribute); } catch (LocaleSyntaxException e) { @@ -3158,7 +3305,7 @@ public Builder clearExtensions() { public Locale build() { BaseLocale baseloc = localeBuilder.getBaseLocale(); LocaleExtensions extensions = localeBuilder.getLocaleExtensions(); - if (extensions == null && baseloc.getVariant().length() > 0) { + if (extensions == null && !baseloc.getVariant().isEmpty()) { extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(), baseloc.getRegion(), baseloc.getVariant()); } @@ -3186,71 +3333,76 @@ public Locale build() { * * The filtering method will behave as follows: * - * + *
    + * + * * - * - * - * + * + * + * * + * + * * - * - * * * - * - * + * * * - * - * * * - * - * + * * * - * - * + * * + * *
    Filtering method behavior
    Filtering ModeLanguage Priority List: {@code "de-DE"}Language Priority List: {@code "de-*-DE"}Filtering ModeLanguage Priority List: {@code "de-DE"}Language Priority List: {@code "de-*-DE"}
    + * * {@link FilteringMode#AUTOSELECT_FILTERING AUTOSELECT_FILTERING} - * - * + * + * * Performs basic filtering and returns {@code "de-DE"} and * {@code "de-DE-1996"}. * + * * Performs extended filtering and returns {@code "de-DE"}, * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and * {@code "de-Latn-DE-1996"}. *
    + * * {@link FilteringMode#EXTENDED_FILTERING EXTENDED_FILTERING} - * - * + * + * * Performs extended filtering and returns {@code "de-DE"}, * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and * {@code "de-Latn-DE-1996"}. * Same as above.Same as above.
    + * * {@link FilteringMode#IGNORE_EXTENDED_RANGES IGNORE_EXTENDED_RANGES} - * - * + * + * * Performs basic filtering and returns {@code "de-DE"} and * {@code "de-DE-1996"}. * + * * Performs basic filtering and returns {@code null} because * nothing matches. *
    + * * {@link FilteringMode#MAP_EXTENDED_RANGES MAP_EXTENDED_RANGES} - * - * Same as above. + * + * Same as above. * Performs basic filtering and returns {@code "de-DE"} and * {@code "de-DE-1996"} because {@code "de-*-DE"} is mapped to * {@code "de-DE"}. *
    + * * {@link FilteringMode#REJECT_EXTENDED_RANGES REJECT_EXTENDED_RANGES} - * - * Same as above. + * + * Same as above. * Throws {@link IllegalArgumentException} because {@code "de-*-DE"} is * not a valid basic language range. *
    * * @see #filter(List, Collection, FilteringMode) @@ -3348,7 +3500,7 @@ public static final class LanguageRange { private final String range; private final double weight; - private volatile int hash = 0; + private volatile int hash; /** * Constructs a {@code LanguageRange} using the given {@code range}. @@ -3360,6 +3512,8 @@ public static final class LanguageRange { * @param range a language range * @throws NullPointerException if the given {@code range} is * {@code null} + * @throws IllegalArgumentException if the given {@code range} does not + * comply with the syntax of the language range mentioned in RFC 4647 */ public LanguageRange(String range) { this(range, MAX_WEIGHT); @@ -3375,8 +3529,10 @@ public LanguageRange(String range) { * {@code MAX_WEIGHT} * @throws NullPointerException if the given {@code range} is * {@code null} - * @throws IllegalArgumentException if the given {@code weight} is less - * than {@code MIN_WEIGHT} or greater than {@code MAX_WEIGHT} + * @throws IllegalArgumentException if the given {@code range} does not + * comply with the syntax of the language range mentioned in RFC 4647 + * or if the given {@code weight} is less than {@code MIN_WEIGHT} + * or greater than {@code MAX_WEIGHT} */ public LanguageRange(String range, double weight) { if (range == null) { @@ -3386,7 +3542,7 @@ public LanguageRange(String range, double weight) { throw new IllegalArgumentException("weight=" + weight); } - range = range.toLowerCase(); + range = range.toLowerCase(Locale.ROOT); // Do syntax check. boolean isIllFormed = false; @@ -3605,14 +3761,17 @@ public static List mapEquivalents( */ @Override public int hashCode() { - if (hash == 0) { - int result = 17; - result = 37*result + range.hashCode(); + int h = hash; + if (h == 0) { + h = 17; + h = 37*h + range.hashCode(); long bitsWeight = Double.doubleToLongBits(weight); - result = 37*result + (int)(bitsWeight ^ (bitsWeight >>> 32)); - hash = result; + h = 37*h + (int)(bitsWeight ^ (bitsWeight >>> 32)); + if (h != 0) { + hash = h; + } } - return hash; + return h; } /** @@ -3639,12 +3798,27 @@ public boolean equals(Object obj) { && range.equals(other.range) && weight == other.weight; } + + /** + * Returns an informative string representation of this {@code LanguageRange} + * object, consisting of language range and weight if the range is + * weighted and the weight is less than the max weight. + * + * @return a string representation of this {@code LanguageRange} object. + */ + @Override + public String toString() { + return (weight == MAX_WEIGHT) ? range : range + ";q=" + weight; + } } /** * Returns a list of matching {@code Locale} instances using the filtering * mechanism defined in RFC 4647. * + * This filter operation on the given {@code locales} ensures that only + * unique matching locale(s) are returned. + * * @param priorityList user's Language Priority List in which each language * tag is sorted in descending order based on priority or weight * @param locales {@code Locale} instances used for matching @@ -3672,6 +3846,9 @@ public static List filter(List priorityList, * {@link #filter(List, Collection, FilteringMode)} when {@code mode} is * {@link FilteringMode#AUTOSELECT_FILTERING}. * + * This filter operation on the given {@code locales} ensures that only + * unique matching locale(s) are returned. + * * @param priorityList user's Language Priority List in which each language * tag is sorted in descending order based on priority or weight * @param locales {@code Locale} instances used for matching @@ -3692,6 +3869,17 @@ public static List filter(List priorityList, * Returns a list of matching languages tags using the basic filtering * mechanism defined in RFC 4647. * + * This filter operation on the given {@code tags} ensures that only + * unique matching tag(s) are returned with preserved case. In case of + * duplicate matching tags with the case difference, the first matching + * tag with preserved case is returned. + * For example, "de-ch" is returned out of the duplicate matching tags + * "de-ch" and "de-CH", if "de-ch" is checked first for matching in the + * given {@code tags}. Note that if the given {@code tags} is an unordered + * {@code Collection}, the returned matching tag out of duplicate tags is + * subject to change, depending on the implementation of the + * {@code Collection}. + * * @param priorityList user's Language Priority List in which each language * tag is sorted in descending order based on priority or weight * @param tags language tags @@ -3719,6 +3907,17 @@ public static List filterTags(List priorityList, * {@link #filterTags(List, Collection, FilteringMode)} when {@code mode} * is {@link FilteringMode#AUTOSELECT_FILTERING}. * + * This filter operation on the given {@code tags} ensures that only + * unique matching tag(s) are returned with preserved case. In case of + * duplicate matching tags with the case difference, the first matching + * tag with preserved case is returned. + * For example, "de-ch" is returned out of the duplicate matching tags + * "de-ch" and "de-CH", if "de-ch" is checked first for matching in the + * given {@code tags}. Note that if the given {@code tags} is an unordered + * {@code Collection}, the returned matching tag out of duplicate tags is + * subject to change, depending on the implementation of the + * {@code Collection}. + * * @param priorityList user's Language Priority List in which each language * tag is sorted in descending order based on priority or weight * @param tags language tags @@ -3758,6 +3957,9 @@ public static Locale lookup(List priorityList, * Returns the best-matching language tag using the lookup mechanism * defined in RFC 4647. * + * This lookup operation on the given {@code tags} ensures that the + * first matching tag with preserved case is returned. + * * @param priorityList user's Language Priority List in which each language * tag is sorted in descending order based on priority or weight * @param tags language tangs used for matching diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LongSummaryStatistics.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LongSummaryStatistics.java index 2ba3959896..06ad64795d 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LongSummaryStatistics.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/LongSummaryStatistics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -26,6 +26,7 @@ import java.util.function.IntConsumer; import java.util.function.LongConsumer; +import java.util.stream.Collector; /** * A state object for collecting statistics such as count, min, max, sum, and @@ -41,7 +42,7 @@ * } * *

    {@code LongSummaryStatistics} can be used as a - * {@linkplain java.util.stream.Stream#collect(Collector)} reduction} + * {@linkplain java.util.stream.Stream#collect(Collector) reduction} * target for a {@linkplain java.util.stream.Stream stream}. For example: * *

     {@code
    @@ -54,7 +55,7 @@
      *
      * @implNote This implementation is not thread safe. However, it is safe to use
      * {@link java.util.stream.Collectors#summarizingLong(java.util.function.ToLongFunction)
    - * Collectors.toLongStatistics()} on a parallel stream, because the parallel
    + * Collectors.summarizingLong()} on a parallel stream, because the parallel
      * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
      * provides the necessary partitioning, isolation, and merging of results for
      * safe and efficient parallel execution.
    @@ -69,12 +70,57 @@ public class LongSummaryStatistics implements LongConsumer, IntConsumer {
         private long max = Long.MIN_VALUE;
     
         /**
    -     * Construct an empty instance with zero count, zero sum,
    +     * Constructs an empty instance with zero count, zero sum,
          * {@code Long.MAX_VALUE} min, {@code Long.MIN_VALUE} max and zero
          * average.
          */
         public LongSummaryStatistics() { }
     
    +    /**
    +     * Constructs a non-empty instance with the specified {@code count},
    +     * {@code min}, {@code max}, and {@code sum}.
    +     *
    +     * 

    If {@code count} is zero then the remaining arguments are ignored and + * an empty instance is constructed. + * + *

    If the arguments are inconsistent then an {@code IllegalArgumentException} + * is thrown. The necessary consistent argument conditions are: + *

      + *
    • {@code count >= 0}
    • + *
    • {@code min <= max}
    • + *
    + * @apiNote + * The enforcement of argument correctness means that the retrieved set of + * recorded values obtained from a {@code LongSummaryStatistics} source + * instance may not be a legal set of arguments for this constructor due to + * arithmetic overflow of the source's recorded count of values. + * The consistent argument conditions are not sufficient to prevent the + * creation of an internally inconsistent instance. An example of such a + * state would be an instance with: {@code count} = 2, {@code min} = 1, + * {@code max} = 2, and {@code sum} = 0. + * + * @param count the count of values + * @param min the minimum value + * @param max the maximum value + * @param sum the sum of all values + * @throws IllegalArgumentException if the arguments are inconsistent + * @since 10 + */ + public LongSummaryStatistics(long count, long min, long max, long sum) + throws IllegalArgumentException { + if (count < 0L) { + throw new IllegalArgumentException("Negative count value"); + } else if (count > 0L) { + if (min > max) throw new IllegalArgumentException("Minimum greater than maximum"); + + this.count = count; + this.sum = sum; + this.min = min; + this.max = max; + } + // Use default field values if count == 0 + } + /** * Records a new {@code int} value into the summary information. * @@ -161,14 +207,12 @@ public final double getAverage() { return getCount() > 0 ? (double) getSum() / getCount() : 0.0d; } - @Override /** - * {@inheritDoc} - * * Returns a non-empty string representation of this object suitable for * debugging. The exact presentation format is unspecified and may vary * between implementations and versions. */ + @Override public String toString() { return String.format( "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}", diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Map.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Map.java index 0557e97455..1148e63892 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Map.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Map.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -30,7 +30,6 @@ import java.util.function.Function; import java.io.Serializable; -// Android-changed: removed link to collections framework docs /** * An object that maps keys to values. A map cannot contain duplicate keys; * each key can map to at most one value. @@ -111,17 +110,18 @@ * Implementations may optionally handle the self-referential scenario, however * most current implementations do not do so. * - *

    Immutable Map Static Factory Methods

    - *

    The {@link Map#of() Map.of()} and - * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()} - * static factory methods provide a convenient way to create immutable maps. + *

    Unmodifiable Maps

    + *

    The {@link Map#of() Map.of}, + * {@link Map#ofEntries(Map.Entry...) Map.ofEntries}, and + * {@link Map#copyOf Map.copyOf} + * static factory methods provide a convenient way to create unmodifiable maps. * The {@code Map} * instances created by these methods have the following characteristics: * *

      - *
    • They are structurally immutable. Keys and values cannot be added, - * removed, or updated. Calling any mutator method will always cause - * {@code UnsupportedOperationException} to be thrown. + *
    • They are unmodifiable. Keys and values + * cannot be added, removed, or updated. Calling any mutator method on the Map + * will always cause {@code UnsupportedOperationException} to be thrown. * However, if the contained keys or values are themselves mutable, this may cause the * Map to behave inconsistently or its contents to appear to change. *
    • They disallow {@code null} keys and values. Attempts to create them with @@ -140,6 +140,10 @@ * page. *
    * + *

    This interface is a member of the + * + * Java Collections Framework. + * * @param the type of keys maintained by this map * @param the type of mapped values * @@ -152,7 +156,6 @@ * @see Set * @since 1.2 */ -// Android-changed: fix doc links to Collection#optional-restrictions public interface Map { // Query Operations @@ -184,10 +187,10 @@ public interface Map { * key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ boolean containsKey(Object key); @@ -204,10 +207,10 @@ public interface Map { * specified value * @throws ClassCastException if the value is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified value is null and this * map does not permit null values - * (optional) + * (optional) */ boolean containsValue(Object value); @@ -232,10 +235,10 @@ public interface Map { * {@code null} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ V get(Object key); @@ -292,10 +295,10 @@ public interface Map { * is not supported by this map * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this * map does not permit null keys - * (optional) + * (optional) */ V remove(Object key); @@ -605,10 +608,10 @@ public static Comparator> comparingByValue(Comparatoroptional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) * @since 1.8 */ default V getOrDefault(Object key, V defaultValue) { @@ -687,13 +690,13 @@ default void forEach(BiConsumer action) { * values * @throws ClassCastException if a replacement value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if function or a replacement value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a replacement value * prevents it from being stored in this map - * (optional) + * (optional) * @throws ConcurrentModificationException if an entry is found to be * removed during iteration * @since 1.8 @@ -754,16 +757,16 @@ default void replaceAll(BiFunction function) * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V putIfAbsent(K key, V value) { @@ -800,13 +803,13 @@ default V putIfAbsent(K key, V value) { * @return {@code true} if the value was removed * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @since 1.8 */ default boolean remove(Object key, Object value) { @@ -849,14 +852,14 @@ default boolean remove(Object key, Object value) { * @return {@code true} if the value was replaced * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of a specified key or value * prevents it from being stored in this map * @throws NullPointerException if a specified key or newValue is null, * and this map does not permit null keys or values * @throws NullPointerException if oldValue is null and this map does not * permit null values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a specified key * or value prevents it from being stored in this map * @since 1.8 @@ -899,10 +902,10 @@ default boolean replace(K key, V oldValue, V newValue) { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key @@ -982,13 +985,13 @@ default V replace(K key, V value) { * is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfAbsent(K key, @@ -1059,13 +1062,13 @@ default V computeIfAbsent(K key, * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfPresent(K key, @@ -1151,13 +1154,13 @@ default V computeIfPresent(K key, * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V compute(K key, @@ -1246,13 +1249,13 @@ default V compute(K key, * value is associated with the key * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not support null keys or the value or remappingFunction is * null @@ -1273,4 +1276,412 @@ default V merge(K key, V value, return newValue; } + /** + * Returns an unmodifiable map containing zero mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @return an empty {@code Map} + * + * @since 9 + */ + static Map of() { + return ImmutableCollections.emptyMap(); + } + + /** + * Returns an unmodifiable map containing a single mapping. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the mapping's key + * @param v1 the mapping's value + * @return a {@code Map} containing the specified mapping + * @throws NullPointerException if the key or the value is {@code null} + * + * @since 9 + */ + static Map of(K k1, V v1) { + return new ImmutableCollections.Map1<>(k1, v1); + } + + /** + * Returns an unmodifiable map containing two mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if the keys are duplicates + * @throws NullPointerException if any key or value is {@code null} + * + * @since 9 + */ + static Map of(K k1, V v1, K k2, V v2) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2); + } + + /** + * Returns an unmodifiable map containing three mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @since 9 + */ + static Map of(K k1, V v1, K k2, V v2, K k3, V v3) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3); + } + + /** + * Returns an unmodifiable map containing four mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @since 9 + */ + static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4); + } + + /** + * Returns an unmodifiable map containing five mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @param k5 the fifth mapping's key + * @param v5 the fifth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @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) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); + } + + /** + * Returns an unmodifiable map containing six mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @param k5 the fifth mapping's key + * @param v5 the fifth mapping's value + * @param k6 the sixth mapping's key + * @param v6 the sixth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @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, + K k6, V v6) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6); + } + + /** + * Returns an unmodifiable map containing seven mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @param k5 the fifth mapping's key + * @param v5 the fifth mapping's value + * @param k6 the sixth mapping's key + * @param v6 the sixth mapping's value + * @param k7 the seventh mapping's key + * @param v7 the seventh mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @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, + K k6, V v6, K k7, V v7) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7); + } + + /** + * Returns an unmodifiable map containing eight mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @param k5 the fifth mapping's key + * @param v5 the fifth mapping's value + * @param k6 the sixth mapping's key + * @param v6 the sixth mapping's value + * @param k7 the seventh mapping's key + * @param v7 the seventh mapping's value + * @param k8 the eighth mapping's key + * @param v8 the eighth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @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, + K k6, V v6, K k7, V v7, K k8, V v8) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7, k8, v8); + } + + /** + * Returns an unmodifiable map containing nine mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @param k5 the fifth mapping's key + * @param v5 the fifth mapping's value + * @param k6 the sixth mapping's key + * @param v6 the sixth mapping's value + * @param k7 the seventh mapping's key + * @param v7 the seventh mapping's value + * @param k8 the eighth mapping's key + * @param v8 the eighth mapping's value + * @param k9 the ninth mapping's key + * @param v9 the ninth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @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, + K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7, k8, v8, k9, v9); + } + + /** + * Returns an unmodifiable map containing ten mappings. + * See Unmodifiable Maps for details. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param k1 the first mapping's key + * @param v1 the first mapping's value + * @param k2 the second mapping's key + * @param v2 the second mapping's value + * @param k3 the third mapping's key + * @param v3 the third mapping's value + * @param k4 the fourth mapping's key + * @param v4 the fourth mapping's value + * @param k5 the fifth mapping's key + * @param v5 the fifth mapping's value + * @param k6 the sixth mapping's key + * @param v6 the sixth mapping's value + * @param k7 the seventh mapping's key + * @param v7 the seventh mapping's value + * @param k8 the eighth mapping's key + * @param v8 the eighth mapping's value + * @param k9 the ninth mapping's key + * @param v9 the ninth mapping's value + * @param k10 the tenth mapping's key + * @param v10 the tenth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any key or value is {@code null} + * + * @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, + K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) { + return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, + k6, v6, k7, v7, k8, v8, k9, v9, k10, v10); + } + + /** + * Returns an unmodifiable map containing keys and values extracted from the given entries. + * The entries themselves are not stored in the map. + * See Unmodifiable Maps for details. + * + * @apiNote + * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method. + * For example, + * + *

    {@code
    +     *     import static java.util.Map.entry;
    +     *
    +     *     Map map = Map.ofEntries(
    +     *         entry(1, "a"),
    +     *         entry(2, "b"),
    +     *         entry(3, "c"),
    +     *         ...
    +     *         entry(26, "z"));
    +     * }
    + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any entry, key, or value is {@code null}, or if + * the {@code entries} array is {@code null} + * + * @see Map#entry Map.entry() + * @since 9 + */ + @SafeVarargs + @SuppressWarnings("varargs") + static Map ofEntries(Entry... entries) { + if (entries.length == 0) { // implicit null check of entries array + return ImmutableCollections.emptyMap(); + } else if (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 entry : entries) { + // implicit null checks of each array slot + kva[a++] = entry.getKey(); + kva[a++] = entry.getValue(); + } + return new ImmutableCollections.MapN<>(kva); + } + } + + /** + * Returns an unmodifiable {@link Entry} containing the given key and value. + * These entries are suitable for populating {@code Map} instances using the + * {@link Map#ofEntries Map.ofEntries()} method. + * The {@code Entry} instances created by this method have the following characteristics: + * + *
      + *
    • They disallow {@code null} keys and values. Attempts to create them using a {@code null} + * key or value result in {@code NullPointerException}. + *
    • They are unmodifiable. Calls to {@link Entry#setValue Entry.setValue()} + * on a returned {@code Entry} result in {@code UnsupportedOperationException}. + *
    • They are not serializable. + *
    • They are value-based. + * Callers should make no assumptions about the identity of the returned instances. + * This method is free to create new instances or reuse existing ones. Therefore, + * identity-sensitive operations on these instances (reference equality ({@code ==}), + * identity hash code, and synchronization) are unreliable and should be avoided. + *
    + * + * @apiNote + * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or + * {@link AbstractMap.SimpleImmutableEntry}. + * + * @param the key's type + * @param the value's type + * @param k the key + * @param v the value + * @return an {@code Entry} containing the specified key and value + * @throws NullPointerException if the key or value is {@code null} + * + * @see Map#ofEntries Map.ofEntries() + * @since 9 + */ + static Entry entry(K k, V v) { + // KeyValueHolder checks for nulls + return new KeyValueHolder<>(k, v); + } + + /** + * Returns an unmodifiable Map containing the entries + * of the given Map. The given Map must not be null, and it must not contain any + * null keys or values. If the given Map is subsequently modified, the returned + * Map will not reflect such modifications. + * + * @implNote + * If the given Map is an unmodifiable Map, + * calling copyOf will generally not create a copy. + * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param map a {@code Map} from which entries are drawn, must be non-null + * @return a {@code Map} containing the entries of the given {@code Map} + * @throws NullPointerException if map is null, or if it contains any null keys or values + * @since 10 + */ + @SuppressWarnings({"rawtypes","unchecked"}) + static Map copyOf(Map map) { + if (map instanceof ImmutableCollections.AbstractImmutableMap) { + return (Map)map; + } else { + return (Map)Map.ofEntries(map.entrySet().toArray(new Entry[0])); + } + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatArgumentException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatArgumentException.java index 79b04a304a..926a6975f7 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatArgumentException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatArgumentException.java @@ -30,7 +30,7 @@ * have a corresponding argument or if an argument index refers to an argument * that does not exist. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatWidthException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatWidthException.java index 9650fe2b3e..e748695299 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatWidthException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingFormatWidthException.java @@ -28,7 +28,7 @@ /** * Unchecked exception thrown when the format width is required. * - *

    Unless otherwise specified, passing a null argument to any + *

    Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingResourceException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingResourceException.java index 4586480e0a..3e09dfa8b9 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingResourceException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/MissingResourceException.java @@ -45,7 +45,7 @@ * @see java.lang.Exception * @see ResourceBundle * @author Mark Davis - * @since JDK1.1 + * @since 1.1 */ public class MissingResourceException extends RuntimeException { @@ -64,10 +64,10 @@ public MissingResourceException(String s, String className, String key) { } /** - * Constructs a MissingResourceException with - * message, className, key, - * and cause. This constructor is package private for - * use by ResourceBundle.getBundle. + * Constructs a {@code MissingResourceException} with + * {@code message}, {@code className}, {@code key}, + * and {@code cause}. This constructor is package private for + * use by {@code ResourceBundle.getBundle}. * * @param message * the detail message diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/NoSuchElementException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/NoSuchElementException.java index 15e1aad98c..28c2036795 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/NoSuchElementException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/NoSuchElementException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, 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 @@ -29,17 +29,16 @@ * Thrown by various accessor methods to indicate that the element being requested * does not exist. * - * @author unascribed * @see java.util.Enumeration#nextElement() * @see java.util.Iterator#next() - * @since JDK1.0 + * @since 1.0 */ -public -class NoSuchElementException extends RuntimeException { +public class NoSuchElementException extends RuntimeException { + @java.io.Serial private static final long serialVersionUID = 6769829250639411880L; /** - * Constructs a NoSuchElementException with null + * Constructs a {@code NoSuchElementException} with {@code null} * as its error message string. */ public NoSuchElementException() { @@ -47,9 +46,36 @@ public NoSuchElementException() { } /** - * Constructs a NoSuchElementException, saving a reference - * to the error message string s for later retrieval by the - * getMessage method. + * Constructs a {@code NoSuchElementException} with the specified detail + * message and cause. + * + * @param s the detail message, or null + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method), or null + * @since 15 + */ + public NoSuchElementException(String s, Throwable cause) { + super(s, cause); + } + + /** + * Constructs a {@code NoSuchElementException} with the specified cause. + * The detail message is set to {@code (cause == null ? null : + * cause.toString())} (which typically contains the class and + * detail message of {@code cause}). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + * @since 15 + */ + public NoSuchElementException(Throwable cause) { + super(cause); + } + + /** + * Constructs a {@code NoSuchElementException}, saving a reference + * to the error message string {@code s} for later retrieval by the + * {@code getMessage} method. * * @param s the detail message. */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Objects.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Objects.java index 833536527e..236011f740 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Objects.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Objects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, 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 @@ -25,6 +25,8 @@ package java.util; +import jdk.internal.util.Preconditions; + import java.util.function.Supplier; /** @@ -32,21 +34,7 @@ * on objects, or checking certain conditions before operation. These utilities * include {@code null}-safe or {@code null}-tolerant methods for computing the * hash code of an object, returning a string for an object, comparing two - * objects, and checking if indexes or sub-range values are out-of-bounds. - * - * @apiNote - * Static methods such as {@link Objects#checkIndex}, - * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are - * provided for the convenience of checking if values corresponding to indexes - * and sub-ranges are out-of-bounds. - * Variations of these static methods support customization of the runtime - * exception, and corresponding exception detail message, that is thrown when - * values are out-of-bounds. Such methods accept a functional interface - * argument, instances of {@code BiFunction}, that maps out-of-bound values to a - * runtime exception. Care should be taken when using such methods in - * combination with an argument that is a lambda expression, method reference or - * class that capture values. In such cases the cost of capture, related to - * functional interface allocation, may exceed the cost of checking bounds. + * objects, and checking if indexes or sub-range values are out of bounds. * * @since 1.7 */ @@ -59,10 +47,11 @@ private Objects() { * Returns {@code true} if the arguments are equal to each other * and {@code false} otherwise. * Consequently, if both arguments are {@code null}, {@code true} - * is returned and if exactly one argument is {@code null}, {@code - * false} is returned. Otherwise, equality is determined by using - * the {@link Object#equals equals} method of the first - * argument. + * is returned. Otherwise, if the first argument is not {@code + * null}, equality is determined by calling the {@link + * Object#equals equals} method of the first argument with the + * second argument of this method. Otherwise, {@code false} is + * returned. * * @param a an object * @param b an object to be compared with {@code a} for equality @@ -344,4 +333,158 @@ public static T requireNonNull(T obj, Supplier messageSupplier) { null : messageSupplier.get()); return obj; } + + /** + * Checks if the {@code index} is within the bounds of the range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

    The {@code index} is defined to be out of bounds if any of the + * following inequalities is true: + *

      + *
    • {@code index < 0}
    • + *
    • {@code index >= length}
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + * @param index the index + * @param length the upper-bound (exclusive) of the range + * @return {@code index} if it is within bounds of the range + * @throws IndexOutOfBoundsException if the {@code index} is out of bounds + * @since 9 + */ + // Android-removed: @ForceInline is an unsupported attribute. + //@ForceInline + public static + int checkIndex(int index, int length) { + return Preconditions.checkIndex(index, length, null); + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} + * (inclusive) to {@code length} (exclusive). + * + *

    The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

      + *
    • {@code fromIndex < 0}
    • + *
    • {@code fromIndex > toIndex}
    • + *
    • {@code toIndex > length}
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + * @param fromIndex the lower-bound (inclusive) of the sub-range + * @param toIndex the upper-bound (exclusive) of the sub-range + * @param length the upper-bound (exclusive) the range + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws IndexOutOfBoundsException if the sub-range is out of bounds + * @since 9 + */ + public static + int checkFromToIndex(int fromIndex, int toIndex, int length) { + return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null); + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code fromIndex + size} (exclusive) is within the bounds of range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

    The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

      + *
    • {@code fromIndex < 0}
    • + *
    • {@code size < 0}
    • + *
    • {@code fromIndex + size > length}, taking into account integer overflow
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + * @param fromIndex the lower-bound (inclusive) of the sub-interval + * @param size the size of the sub-range + * @param length the upper-bound (exclusive) of the range + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws IndexOutOfBoundsException if the sub-range is out of bounds + * @since 9 + */ + public static + int checkFromIndexSize(int fromIndex, int size, int length) { + return Preconditions.checkFromIndexSize(fromIndex, size, length, null); + } + + /** + * Checks if the {@code index} is within the bounds of the range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

    The {@code index} is defined to be out of bounds if any of the + * following inequalities is true: + *

      + *
    • {@code index < 0}
    • + *
    • {@code index >= length}
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + * @param index the index + * @param length the upper-bound (exclusive) of the range + * @return {@code index} if it is within bounds of the range + * @throws IndexOutOfBoundsException if the {@code index} is out of bounds + * @since 16 + */ + // Android-removed: @ForceInline is an unsupported attribute. + //@ForceInline + public static + long checkIndex(long index, long length) { + return Preconditions.checkIndex(index, length, null); + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} + * (inclusive) to {@code length} (exclusive). + * + *

    The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

      + *
    • {@code fromIndex < 0}
    • + *
    • {@code fromIndex > toIndex}
    • + *
    • {@code toIndex > length}
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + * @param fromIndex the lower-bound (inclusive) of the sub-range + * @param toIndex the upper-bound (exclusive) of the sub-range + * @param length the upper-bound (exclusive) the range + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws IndexOutOfBoundsException if the sub-range is out of bounds + * @since 16 + */ + public static + long checkFromToIndex(long fromIndex, long toIndex, long length) { + return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null); + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code fromIndex + size} (exclusive) is within the bounds of range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

    The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

      + *
    • {@code fromIndex < 0}
    • + *
    • {@code size < 0}
    • + *
    • {@code fromIndex + size > length}, taking into account integer overflow
    • + *
    • {@code length < 0}, which is implied from the former inequalities
    • + *
    + * + * @param fromIndex the lower-bound (inclusive) of the sub-interval + * @param size the size of the sub-range + * @param length the upper-bound (exclusive) of the range + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws IndexOutOfBoundsException if the sub-range is out of bounds + * @since 16 + */ + public static + long checkFromIndexSize(long fromIndex, long size, long length) { + return Preconditions.checkFromIndexSize(fromIndex, size, length, null); + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observable.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observable.java index be01640169..65e399561d 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observable.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -31,11 +31,11 @@ * object that the application wants to have observed. *

    * An observable object can have one or more observers. An observer - * may be any object that implements interface Observer. After an + * may be any object that implements interface {@code Observer}. After an * observable instance changes, an application calling the - * Observable's notifyObservers method + * {@code Observable}'s {@code notifyObservers} method * causes all of its observers to be notified of the change by a call - * to their update method. + * to their {@code update} method. *

    * The order in which notifications will be delivered is unspecified. * The default implementation provided in the Observable class will @@ -45,20 +45,34 @@ * subclass follows this order, as they choose. *

    * Note that this notification mechanism has nothing to do with threads - * and is completely separate from the wait and notify - * mechanism of class Object. + * and is completely separate from the {@code wait} and {@code notify} + * mechanism of class {@code Object}. *

    * When an observable object is newly created, its set of observers is * empty. Two observers are considered the same if and only if the - * equals method returns true for them. + * {@code equals} method returns true for them. * * @author Chris Warth * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) * @see java.util.Observer * @see java.util.Observer#update(java.util.Observable, java.lang.Object) - * @since JDK1.0 + * @since 1.0 + * + * @deprecated + * This class and the {@link Observer} interface have been deprecated. + * The event model supported by {@code Observer} and {@code Observable} + * is quite limited, the order of notifications delivered by + * {@code Observable} is unspecified, and state changes are not in + * one-for-one correspondence with notifications. + * For a richer event model, consider using the + * {@link java.beans} package. For reliable and ordered + * messaging among threads, consider using one of the concurrent data + * structures in the {@link java.util.concurrent} package. + * For reactive streams style programming, see the + * {@link java.util.concurrent.Flow} API. */ +@Deprecated(since="9") public class Observable { private boolean changed = false; private Vector obs; @@ -88,7 +102,7 @@ public synchronized void addObserver(Observer o) { /** * Deletes an observer from the set of observers of this object. - * Passing null to this method will have no effect. + * Passing {@code null} to this method will have no effect. * @param o the observer to be deleted. */ public synchronized void deleteObserver(Observer o) { @@ -97,15 +111,15 @@ public synchronized void deleteObserver(Observer o) { /** * If this object has changed, as indicated by the - * hasChanged method, then notify all of its observers - * and then call the clearChanged method to + * {@code hasChanged} method, then notify all of its observers + * and then call the {@code clearChanged} method to * indicate that this object has no longer changed. *

    - * Each observer has its update method called with two - * arguments: this observable object and null. In other + * Each observer has its {@code update} method called with two + * arguments: this observable object and {@code null}. In other * words, this method is equivalent to: - *

    - * notifyObservers(null)
    + *
    {@code + * notifyObservers(null)}
    * * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() @@ -117,12 +131,12 @@ public void notifyObservers() { /** * If this object has changed, as indicated by the - * hasChanged method, then notify all of its observers - * and then call the clearChanged method to indicate + * {@code hasChanged} method, then notify all of its observers + * and then call the {@code clearChanged} method to indicate * that this object has no longer changed. *

    - * Each observer has its update method called with two - * arguments: this observable object and the arg argument. + * Each observer has its {@code update} method called with two + * arguments: this observable object and the {@code arg} argument. * * @param arg any object. * @see java.util.Observable#clearChanged() @@ -171,8 +185,8 @@ public synchronized void deleteObservers() { } /** - * Marks this Observable object as having been changed; the - * hasChanged method will now return true. + * Marks this {@code Observable} object as having been changed; the + * {@code hasChanged} method will now return {@code true}. */ protected synchronized void setChanged() { changed = true; @@ -181,9 +195,9 @@ protected synchronized void setChanged() { /** * Indicates that this object has no longer changed, or that it has * already notified all of its observers of its most recent change, - * so that the hasChanged method will now return false. + * so that the {@code hasChanged} method will now return {@code false}. * This method is called automatically by the - * notifyObservers methods. + * {@code notifyObservers} methods. * * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) @@ -195,10 +209,10 @@ protected synchronized void clearChanged() { /** * Tests if this object has changed. * - * @return true if and only if the setChanged + * @return {@code true} if and only if the {@code setChanged} * method has been called more recently than the - * clearChanged method on this object; - * false otherwise. + * {@code clearChanged} method on this object; + * {@code false} otherwise. * @see java.util.Observable#clearChanged() * @see java.util.Observable#setChanged() */ @@ -207,7 +221,7 @@ public synchronized boolean hasChanged() { } /** - * Returns the number of observers of this Observable object. + * Returns the number of observers of this {@code Observable} object. * * @return the number of observers of this object. */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observer.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observer.java index ef64e148cb..8536bce8a1 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observer.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Observer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -25,22 +25,27 @@ package java.util; /** - * A class can implement the Observer interface when it + * A class can implement the {@code Observer} interface when it * wants to be informed of changes in observable objects. * * @author Chris Warth * @see java.util.Observable - * @since JDK1.0 + * @since 1.0 + * + * @deprecated + * This interface has been deprecated. See the {@link Observable} + * class for further information. */ +@Deprecated() public interface Observer { /** * This method is called whenever the observed object is changed. An - * application calls an Observable object's - * notifyObservers method to have all the object's + * application calls an {@code Observable} object's + * {@code notifyObservers} method to have all the object's * observers notified of the change. * * @param o the observable object. - * @param arg an argument passed to the notifyObservers + * @param arg an argument passed to the {@code notifyObservers} * method. */ void update(Observable o, Object arg); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Optional.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Optional.java index bce8ff9abe..d27837fa04 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Optional.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Optional.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, 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 @@ -28,52 +28,60 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.stream.Stream; -// Android-changed: removed ValueBased paragraph. +// Android-changed: removed ValueBased paragraph and annotation. /** - * A container object which may or may not contain a non-null value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code get()} will return the value. + * A container object which may or may not contain a non-{@code null} value. + * If a value is present, {@code isPresent()} returns {@code true}. If no + * value is present, the object is considered empty and + * {@code isPresent()} returns {@code false}. * *

    Additional methods that depend on the presence or absence of a contained - * value are provided, such as {@link #orElse(java.lang.Object) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block - * of code if the value is present). + * value are provided, such as {@link #orElse(Object) orElse()} + * (returns a default value if no value is present) and + * {@link #ifPresent(Consumer) ifPresent()} (performs an + * action if a value is present). * + * + * + * @apiNote + * {@code Optional} is primarily intended for use as a method return type where + * there is a clear need to represent "no result," and where using {@code null} + * is likely to cause errors. A variable whose type is {@code Optional} should + * never itself be {@code null}; it should always point to an {@code Optional} + * instance. + * + * @param the type of value * @since 1.8 */ +// @jdk.internal.ValueBased public final class Optional { /** * Common instance for {@code empty()}. */ - private static final Optional EMPTY = new Optional<>(); + private static final Optional EMPTY = new Optional<>(null); /** * If non-null, the value; if null, indicates no value is present */ private final T value; - /** - * Constructs an empty instance. - * - * @implNote Generally only one empty instance, {@link Optional#EMPTY}, - * should exist per VM. - */ - private Optional() { - this.value = null; - } - /** * Returns an empty {@code Optional} instance. No value is present for this - * Optional. + * {@code Optional}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. - * Instead, use {@link #isPresent()}. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} or {@code !=} against instances returned by + * {@code Optional.empty()}. There is no guarantee that it is a singleton. + * Instead, use {@link #isEmpty()} or {@link #isPresent()}. * - * @param Type of the non-existent value + * @param The type of the non-existent value * @return an empty {@code Optional} */ public static Optional empty() { @@ -83,48 +91,53 @@ public static Optional empty() { } /** - * Constructs an instance with the value present. + * Constructs an instance with the described value. * - * @param value the non-null value to be present - * @throws NullPointerException if value is null + * @param value the value to describe; it's the caller's responsibility to + * ensure the value is non-{@code null} unless creating the singleton + * instance returned by {@code empty()}. */ private Optional(T value) { - this.value = Objects.requireNonNull(value); + this.value = value; } /** - * Returns an {@code Optional} with the specified present non-null value. + * Returns an {@code Optional} describing the given non-{@code null} + * value. * - * @param the class of the value - * @param value the value to be present, which must be non-null + * @param value the value to describe, which must be non-{@code null} + * @param the type of the value * @return an {@code Optional} with the value present - * @throws NullPointerException if value is null + * @throws NullPointerException if value is {@code null} */ public static Optional of(T value) { - return new Optional<>(value); + return new Optional<>(Objects.requireNonNull(value)); } /** - * Returns an {@code Optional} describing the specified value, if non-null, - * otherwise returns an empty {@code Optional}. + * Returns an {@code Optional} describing the given value, if + * non-{@code null}, otherwise returns an empty {@code Optional}. * - * @param the class of the value - * @param value the possibly-null value to describe + * @param value the possibly-{@code null} value to describe + * @param the type of the value * @return an {@code Optional} with a present value if the specified value - * is non-null, otherwise an empty {@code Optional} + * is non-{@code null}, otherwise an empty {@code Optional} */ + @SuppressWarnings("unchecked") public static Optional ofNullable(T value) { - return value == null ? empty() : of(value); + return value == null ? (Optional) EMPTY + : new Optional<>(value); } /** - * If a value is present in this {@code Optional}, returns the value, - * otherwise throws {@code NoSuchElementException}. + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @return the non-null value held by this {@code Optional} - * @throws NoSuchElementException if there is no value present + * @apiNote + * The preferred alternative to this method is {@link #orElseThrow()}. * - * @see Optional#isPresent() + * @return the non-{@code null} value described by this {@code Optional} + * @throws NoSuchElementException if no value is present */ public T get() { if (value == null) { @@ -134,115 +147,204 @@ public T get() { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return value != null; } /** - * If a value is present, invoke the specified consumer with the value, - * otherwise do nothing. + * If a value is not present, returns {@code true}, otherwise + * {@code false}. + * + * @return {@code true} if a value is not present, otherwise {@code false} + * @since 11 + */ + public boolean isEmpty() { + return value == null; + } + + /** + * If a value is present, performs the given action with the value, + * otherwise does nothing. + * + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} + */ + public void ifPresent(Consumer action) { + if (value != null) { + action.accept(value); + } + } + + /** + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. * - * @param consumer block to be executed if a value is present - * @throws NullPointerException if value is present and {@code consumer} is - * null + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 */ - public void ifPresent(Consumer consumer) { - if (value != null) - consumer.accept(value); + public void ifPresentOrElse(Consumer action, Runnable emptyAction) { + if (value != null) { + action.accept(value); + } else { + emptyAction.run(); + } } /** * If a value is present, and the value matches the given predicate, - * return an {@code Optional} describing the value, otherwise return an + * returns an {@code Optional} describing the value, otherwise returns an * empty {@code Optional}. * - * @param predicate a predicate to apply to the value, if present - * @return an {@code Optional} describing the value of this {@code Optional} - * if a value is present and the value matches the given predicate, - * otherwise an empty {@code Optional} - * @throws NullPointerException if the predicate is null + * @param predicate the predicate to apply to a value, if present + * @return an {@code Optional} describing the value of this + * {@code Optional}, if a value is present and the value matches the + * given predicate, otherwise an empty {@code Optional} + * @throws NullPointerException if the predicate is {@code null} */ public Optional filter(Predicate predicate) { Objects.requireNonNull(predicate); - if (!isPresent()) + if (!isPresent()) { return this; - else + } else { return predicate.test(value) ? this : empty(); + } } /** - * If a value is present, apply the provided mapping function to it, - * and if the result is non-null, return an {@code Optional} describing the - * result. Otherwise return an empty {@code Optional}. + * If a value is present, returns an {@code Optional} describing (as if by + * {@link #ofNullable}) the result of applying the given mapping function to + * the value, otherwise returns an empty {@code Optional}. * - * @apiNote This method supports post-processing on optional values, without + *

    If the mapping function returns a {@code null} result then this method + * returns an empty {@code Optional}. + * + * @apiNote + * This method supports post-processing on {@code Optional} values, without * the need to explicitly check for a return status. For example, the - * following code traverses a stream of file names, selects one that has - * not yet been processed, and then opens that file, returning an - * {@code Optional}: + * following code traverses a stream of URIs, selects one that has not + * yet been processed, and creates a path from that URI, returning + * an {@code Optional}: * *

    {@code
    -     *     Optional fis =
    -     *         names.stream().filter(name -> !isProcessedYet(name))
    +     *     Optional p =
    +     *         uris.stream().filter(uri -> !isProcessedYet(uri))
          *                       .findFirst()
    -     *                       .map(name -> new FileInputStream(name));
    +     *                       .map(Paths::get);
          * }
    * - * Here, {@code findFirst} returns an {@code Optional}, and then - * {@code map} returns an {@code Optional} for the desired - * file if one exists. + * Here, {@code findFirst} returns an {@code Optional}, and then + * {@code map} returns an {@code Optional} for the desired + * URI if one exists. * - * @param The type of the result of the mapping function - * @param mapper a mapping function to apply to the value, if present + * @param mapper the mapping function to apply to a value, if present + * @param The type of the value returned from the mapping function * @return an {@code Optional} describing the result of applying a mapping - * function to the value of this {@code Optional}, if a value is present, - * otherwise an empty {@code Optional} - * @throws NullPointerException if the mapping function is null + * function to the value of this {@code Optional}, if a value is + * present, otherwise an empty {@code Optional} + * @throws NullPointerException if the mapping function is {@code null} */ - public Optional map(Function mapper) { + public Optional map(Function mapper) { Objects.requireNonNull(mapper); - if (!isPresent()) + if (!isPresent()) { return empty(); - else { + } else { return Optional.ofNullable(mapper.apply(value)); } } /** - * If a value is present, apply the provided {@code Optional}-bearing - * mapping function to it, return that result, otherwise return an empty - * {@code Optional}. This method is similar to {@link #map(Function)}, - * but the provided mapper is one whose result is already an {@code Optional}, - * and if invoked, {@code flatMap} does not wrap it with an additional + * If a value is present, returns the result of applying the given + * {@code Optional}-bearing mapping function to the value, otherwise returns + * an empty {@code Optional}. + * + *

    This method is similar to {@link #map(Function)}, but the mapping + * function is one whose result is already an {@code Optional}, and if + * invoked, {@code flatMap} does not wrap it within an additional * {@code Optional}. * - * @param The type parameter to the {@code Optional} returned by - * @param mapper a mapping function to apply to the value, if present - * the mapping function + * @param The type of value of the {@code Optional} returned by the + * mapping function + * @param mapper the mapping function to apply to a value, if present * @return the result of applying an {@code Optional}-bearing mapping - * function to the value of this {@code Optional}, if a value is present, - * otherwise an empty {@code Optional} - * @throws NullPointerException if the mapping function is null or returns - * a null result + * function to the value of this {@code Optional}, if a value is + * present, otherwise an empty {@code Optional} + * @throws NullPointerException if the mapping function is {@code null} or + * returns a {@code null} result */ - public Optional flatMap(Function> mapper) { + public Optional flatMap(Function> mapper) { Objects.requireNonNull(mapper); - if (!isPresent()) + if (!isPresent()) { return empty(); - else { - return Objects.requireNonNull(mapper.apply(value)); + } else { + @SuppressWarnings("unchecked") + Optional r = (Optional) mapper.apply(value); + return Objects.requireNonNull(r); + } + } + + /** + * If a value is present, returns an {@code Optional} describing the value, + * otherwise returns an {@code Optional} produced by the supplying function. + * + * @param supplier the supplying function that produces an {@code Optional} + * to be returned + * @return returns an {@code Optional} describing the value of this + * {@code Optional}, if a value is present, otherwise an + * {@code Optional} produced by the supplying function. + * @throws NullPointerException if the supplying function is {@code null} or + * produces a {@code null} result + * @since 9 + */ + public Optional or(Supplier> supplier) { + Objects.requireNonNull(supplier); + if (isPresent()) { + return this; + } else { + @SuppressWarnings("unchecked") + Optional r = (Optional) supplier.get(); + return Objects.requireNonNull(r); + } + } + + /** + * If a value is present, returns a sequential {@link Stream} containing + * only that value, otherwise returns an empty {@code Stream}. + * + * @apiNote + * This method can be used to transform a {@code Stream} of optional + * elements to a {@code Stream} of present value elements: + *

    {@code
    +     *     Stream> os = ..
    +     *     Stream s = os.flatMap(Optional::stream)
    +     * }
    + * + * @return the optional value as a {@code Stream} + * @since 9 + */ + public Stream stream() { + if (!isPresent()) { + return Stream.empty(); + } else { + return Stream.of(value); } } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, returns the value, otherwise returns + * {@code other}. * - * @param other the value to be returned if there is no value present, may - * be null + * @param other the value to be returned, if no value is present. + * May be {@code null}. * @return the value, if present, otherwise {@code other} */ public T orElse(T other) { @@ -250,34 +352,50 @@ public T orElse(T other) { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. + * + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} + */ + public T orElseGet(Supplier supplier) { + return value != null ? value : supplier.get(); + } + + /** + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @param other a {@code Supplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.get()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @return the non-{@code null} value described by this {@code Optional} + * @throws NoSuchElementException if no value is present + * @since 10 */ - public T orElseGet(Supplier other) { - return value != null ? value : other.get(); + public T orElseThrow() { + if (value == null) { + throw new NoSuchElementException("No value present"); + } + return value; } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} */ public T orElseThrow(Supplier exceptionSupplier) throws X { if (value != null) { @@ -288,8 +406,8 @@ public T orElseThrow(Supplier exceptionSuppli } /** - * Indicates whether some other object is "equal to" this Optional. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this {@code Optional}. + * The other object is considered equal if: *
      *
    • it is also an {@code Optional} and; *
    • both instances have no value present or; @@ -297,8 +415,8 @@ public T orElseThrow(Supplier exceptionSuppli *
    * * @param obj an object to be tested for equality - * @return {code true} if the other object is "equal to" this object - * otherwise {@code false} + * @return {@code true} if the other object is "equal to" this object + * otherwise {@code false} */ @Override public boolean equals(Object obj) { @@ -315,10 +433,11 @@ public boolean equals(Object obj) { } /** - * Returns the hash code value of the present value, if any, or 0 (zero) if - * no value is present. + * Returns the hash code of the value, if present, otherwise {@code 0} + * (zero) if no value is present. * - * @return hash code value of the present value or 0 if no value is present + * @return hash code value of the present value or {@code 0} if no value is + * present */ @Override public int hashCode() { @@ -326,13 +445,14 @@ public int hashCode() { } /** - * Returns a non-empty string representation of this Optional suitable for - * debugging. The exact presentation format is unspecified and may vary - * between implementations and versions. + * Returns a non-empty string representation of this {@code Optional} + * suitable for debugging. The exact presentation format is unspecified and + * may vary between implementations and versions. * - * @implSpec If a value is present the result must include its string - * representation in the result. Empty and present Optionals must be - * unambiguously differentiable. + * @implSpec + * If a value is present the result must include its string representation + * in the result. Empty and present {@code Optional}s must be unambiguously + * differentiable. * * @return the string representation of this instance */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalDouble.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalDouble.java index 7112df1655..4539fa9558 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalDouble.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -27,18 +27,26 @@ import java.util.function.DoubleConsumer; import java.util.function.DoubleSupplier; import java.util.function.Supplier; +import java.util.stream.DoubleStream; // Android-changed: removed ValueBased paragraph. /** * A container object which may or may not contain a {@code double} value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code getAsDouble()} will return the value. + * If a value is present, {@code isPresent()} returns {@code true}. If no + * value is present, the object is considered empty and + * {@code isPresent()} returns {@code false}. * *

    Additional methods that depend on the presence or absence of a contained * value are provided, such as {@link #orElse(double) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.DoubleConsumer) ifPresent()} (execute a block - * of code if the value is present). + * (returns a default value if no value is present) and + * {@link #ifPresent(DoubleConsumer) ifPresent()} (performs + * an action if a value is present). + * + * @apiNote + * {@code OptionalDouble} is primarily intended for use as a method return type where + * there is a clear need to represent "no result." A variable whose type is + * {@code OptionalDouble} should never itself be {@code null}; it should always point + * to an {@code OptionalDouble} instance. * * @since 1.8 */ @@ -66,12 +74,13 @@ private OptionalDouble() { } /** - * Returns an empty {@code OptionalDouble} instance. No value is present for this - * OptionalDouble. + * Returns an empty {@code OptionalDouble} instance. No value is present + * for this {@code OptionalDouble}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} against instances returned by + * {@code OptionalDouble.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * * @return an empty {@code OptionalDouble}. @@ -81,9 +90,9 @@ public static OptionalDouble empty() { } /** - * Construct an instance with the value present. + * Construct an instance with the described value. * - * @param value the double value to be present. + * @param value the double value to describe. */ private OptionalDouble(double value) { this.isPresent = true; @@ -91,9 +100,9 @@ private OptionalDouble(double value) { } /** - * Return an {@code OptionalDouble} with the specified value present. + * Returns an {@code OptionalDouble} describing the given value. * - * @param value the value to be present + * @param value the value to describe * @return an {@code OptionalDouble} with the value present */ public static OptionalDouble of(double value) { @@ -101,13 +110,14 @@ public static OptionalDouble of(double value) { } /** - * If a value is present in this {@code OptionalDouble}, returns the value, - * otherwise throws {@code NoSuchElementException}. + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @return the value held by this {@code OptionalDouble} - * @throws NoSuchElementException if there is no value present + * @apiNote + * The preferred alternative to this method is {@link #orElseThrow()}. * - * @see OptionalDouble#isPresent() + * @return the value described by this {@code OptionalDouble} + * @throws NoSuchElementException if no value is present */ public double getAsDouble() { if (!isPresent) { @@ -117,31 +127,88 @@ public double getAsDouble() { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return isPresent; } /** - * Have the specified consumer accept the value if a value is present, - * otherwise do nothing. + * If a value is not present, returns {@code true}, otherwise + * {@code false}. + * + * @return {@code true} if a value is not present, otherwise {@code false} + * @since 11 + */ + public boolean isEmpty() { + return !isPresent; + } + + /** + * If a value is present, performs the given action with the value, + * otherwise does nothing. + * + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} + */ + public void ifPresent(DoubleConsumer action) { + if (isPresent) { + action.accept(value); + } + } + + /** + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. + * + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 + */ + public void ifPresentOrElse(DoubleConsumer action, Runnable emptyAction) { + if (isPresent) { + action.accept(value); + } else { + emptyAction.run(); + } + } + + /** + * If a value is present, returns a sequential {@link DoubleStream} + * containing only that value, otherwise returns an empty + * {@code DoubleStream}. * - * @param consumer block to be executed if a value is present - * @throws NullPointerException if value is present and {@code consumer} is - * null + * @apiNote + * This method can be used to transform a {@code Stream} of optional doubles + * to a {@code DoubleStream} of present doubles: + *

    {@code
    +     *     Stream os = ..
    +     *     DoubleStream s = os.flatMapToDouble(OptionalDouble::stream)
    +     * }
    + * + * @return the optional value as a {@code DoubleStream} + * @since 9 */ - public void ifPresent(DoubleConsumer consumer) { - if (isPresent) - consumer.accept(value); + public DoubleStream stream() { + if (isPresent) { + return DoubleStream.of(value); + } else { + return DoubleStream.empty(); + } } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, returns the value, otherwise returns + * {@code other}. * - * @param other the value to be returned if there is no value present + * @param other the value to be returned, if no value is present * @return the value, if present, otherwise {@code other} */ public double orElse(double other) { @@ -149,36 +216,52 @@ public double orElse(double other) { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. + * + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} + */ + public double orElseGet(DoubleSupplier supplier) { + return isPresent ? value : supplier.getAsDouble(); + } + + /** + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @param other a {@code DoubleSupplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.getAsDouble()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @return the value described by this {@code OptionalDouble} + * @throws NoSuchElementException if no value is present + * @since 10 */ - public double orElseGet(DoubleSupplier other) { - return isPresent ? value : other.getAsDouble(); + public double orElseThrow() { + if (!isPresent) { + throw new NoSuchElementException("No value present"); + } + return value; } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null - */ - public double orElseThrow(Supplier exceptionSupplier) throws X { + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} + */ + public double orElseThrow(Supplier exceptionSupplier) throws X { if (isPresent) { return value; } else { @@ -187,17 +270,18 @@ public double orElseThrow(Supplier exceptionSupplier) th } /** - * Indicates whether some other object is "equal to" this OptionalDouble. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this + * {@code OptionalDouble}. The other object is considered equal if: *
      *
    • it is also an {@code OptionalDouble} and; *
    • both instances have no value present or; - *
    • the present values are "equal to" each other via {@code Double.compare() == 0}. + *
    • the present values are "equal to" each other via + * {@code Double.compare() == 0}. *
    * * @param obj an object to be tested for equality - * @return {code true} if the other object is "equal to" this object - * otherwise {@code false} + * @return {@code true} if the other object is "equal to" this object + * otherwise {@code false} */ @Override public boolean equals(Object obj) { @@ -216,10 +300,11 @@ public boolean equals(Object obj) { } /** - * Returns the hash code value of the present value, if any, or 0 (zero) if - * no value is present. + * Returns the hash code of the value, if present, otherwise {@code 0} + * (zero) if no value is present. * - * @return hash code value of the present value or 0 if no value is present + * @return hash code value of the present value or {@code 0} if no value is + * present */ @Override public int hashCode() { @@ -227,14 +312,13 @@ public int hashCode() { } /** - * {@inheritDoc} - * - * Returns a non-empty string representation of this object suitable for - * debugging. The exact presentation format is unspecified and may vary - * between implementations and versions. + * Returns a non-empty string representation of this {@code OptionalDouble} + * suitable for debugging. The exact presentation format is unspecified and + * may vary between implementations and versions. * - * @implSpec If a value is present the result must include its string - * representation in the result. Empty and present instances must be + * @implSpec + * If a value is present the result must include its string representation + * in the result. Empty and present {@code OptionalDouble}s must be * unambiguously differentiable. * * @return the string representation of this instance diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalInt.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalInt.java index 61cac03f22..d28bd02e75 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalInt.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -27,18 +27,27 @@ import java.util.function.IntConsumer; import java.util.function.IntSupplier; import java.util.function.Supplier; +import java.util.stream.IntStream; // Android-changed: removed ValueBased paragraph. /** - * A container object which may or may not contain a {@code int} value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code getAsInt()} will return the value. + * A container object which may or may not contain an {@code int} value. + * If a value is present, {@code isPresent()} returns {@code true}. If no + * value is present, the object is considered empty and + * {@code isPresent()} returns {@code false}. * *

    Additional methods that depend on the presence or absence of a contained * value are provided, such as {@link #orElse(int) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.IntConsumer) ifPresent()} (execute a block - * of code if the value is present). + * (returns a default value if no value is present) and + * {@link #ifPresent(IntConsumer) ifPresent()} (performs an + * action if a value is present). + * + * + * @apiNote + * {@code OptionalInt} is primarily intended for use as a method return type where + * there is a clear need to represent "no result." A variable whose type is + * {@code OptionalInt} should never itself be {@code null}; it should always point + * to an {@code OptionalInt} instance. * * @since 1.8 */ @@ -66,24 +75,25 @@ private OptionalInt() { } /** - * Returns an empty {@code OptionalInt} instance. No value is present for this - * OptionalInt. + * Returns an empty {@code OptionalInt} instance. No value is present for + * this {@code OptionalInt}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} against instances returned by + * {@code OptionalInt.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * - * @return an empty {@code OptionalInt} + * @return an empty {@code OptionalInt} */ public static OptionalInt empty() { return EMPTY; } /** - * Construct an instance with the value present. + * Construct an instance with the described value. * - * @param value the int value to be present + * @param value the int value to describe */ private OptionalInt(int value) { this.isPresent = true; @@ -91,9 +101,9 @@ private OptionalInt(int value) { } /** - * Return an {@code OptionalInt} with the specified value present. + * Returns an {@code OptionalInt} describing the given value. * - * @param value the value to be present + * @param value the value to describe * @return an {@code OptionalInt} with the value present */ public static OptionalInt of(int value) { @@ -101,13 +111,14 @@ public static OptionalInt of(int value) { } /** - * If a value is present in this {@code OptionalInt}, returns the value, - * otherwise throws {@code NoSuchElementException}. + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @return the value held by this {@code OptionalInt} - * @throws NoSuchElementException if there is no value present + * @apiNote + * The preferred alternative to this method is {@link #orElseThrow()}. * - * @see OptionalInt#isPresent() + * @return the value described by this {@code OptionalInt} + * @throws NoSuchElementException if no value is present */ public int getAsInt() { if (!isPresent) { @@ -117,31 +128,87 @@ public int getAsInt() { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return isPresent; } /** - * Have the specified consumer accept the value if a value is present, - * otherwise do nothing. + * If a value is not present, returns {@code true}, otherwise + * {@code false}. + * + * @return {@code true} if a value is not present, otherwise {@code false} + * @since 11 + */ + public boolean isEmpty() { + return !isPresent; + } + + /** + * If a value is present, performs the given action with the value, + * otherwise does nothing. * - * @param consumer block to be executed if a value is present - * @throws NullPointerException if value is present and {@code consumer} is - * null + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} */ - public void ifPresent(IntConsumer consumer) { - if (isPresent) - consumer.accept(value); + public void ifPresent(IntConsumer action) { + if (isPresent) { + action.accept(value); + } } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. * - * @param other the value to be returned if there is no value present + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 + */ + public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) { + if (isPresent) { + action.accept(value); + } else { + emptyAction.run(); + } + } + + /** + * If a value is present, returns a sequential {@link IntStream} containing + * only that value, otherwise returns an empty {@code IntStream}. + * + * @apiNote + * This method can be used to transform a {@code Stream} of optional + * integers to an {@code IntStream} of present integers: + *

    {@code
    +     *     Stream os = ..
    +     *     IntStream s = os.flatMapToInt(OptionalInt::stream)
    +     * }
    + * + * @return the optional value as an {@code IntStream} + * @since 9 + */ + public IntStream stream() { + if (isPresent) { + return IntStream.of(value); + } else { + return IntStream.empty(); + } + } + + /** + * If a value is present, returns the value, otherwise returns + * {@code other}. + * + * @param other the value to be returned, if no value is present * @return the value, if present, otherwise {@code other} */ public int orElse(int other) { @@ -149,36 +216,52 @@ public int orElse(int other) { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. + * + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} + */ + public int orElseGet(IntSupplier supplier) { + return isPresent ? value : supplier.getAsInt(); + } + + /** + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @param other a {@code IntSupplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.getAsInt()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @return the value described by this {@code OptionalInt} + * @throws NoSuchElementException if no value is present + * @since 10 */ - public int orElseGet(IntSupplier other) { - return isPresent ? value : other.getAsInt(); + public int orElseThrow() { + if (!isPresent) { + throw new NoSuchElementException("No value present"); + } + return value; } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null - */ - public int orElseThrow(Supplier exceptionSupplier) throws X { + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} + */ + public int orElseThrow(Supplier exceptionSupplier) throws X { if (isPresent) { return value; } else { @@ -187,8 +270,8 @@ public int orElseThrow(Supplier exceptionSupplier) throw } /** - * Indicates whether some other object is "equal to" this OptionalInt. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this + * {@code OptionalInt}. The other object is considered equal if: *
      *
    • it is also an {@code OptionalInt} and; *
    • both instances have no value present or; @@ -196,8 +279,8 @@ public int orElseThrow(Supplier exceptionSupplier) throw *
    * * @param obj an object to be tested for equality - * @return {code true} if the other object is "equal to" this object - * otherwise {@code false} + * @return {@code true} if the other object is "equal to" this object + * otherwise {@code false} */ @Override public boolean equals(Object obj) { @@ -216,10 +299,11 @@ public boolean equals(Object obj) { } /** - * Returns the hash code value of the present value, if any, or 0 (zero) if - * no value is present. + * Returns the hash code of the value, if present, otherwise {@code 0} + * (zero) if no value is present. * - * @return hash code value of the present value or 0 if no value is present + * @return hash code value of the present value or {@code 0} if no value is + * present */ @Override public int hashCode() { @@ -227,14 +311,13 @@ public int hashCode() { } /** - * {@inheritDoc} - * - * Returns a non-empty string representation of this object suitable for - * debugging. The exact presentation format is unspecified and may vary - * between implementations and versions. + * Returns a non-empty string representation of this {@code OptionalInt} + * suitable for debugging. The exact presentation format is unspecified and + * may vary between implementations and versions. * - * @implSpec If a value is present the result must include its string - * representation in the result. Empty and present instances must be + * @implSpec + * If a value is present the result must include its string representation + * in the result. Empty and present {@code OptionalInt}s must be * unambiguously differentiable. * * @return the string representation of this instance diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalLong.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalLong.java index b337d832d2..5558afa183 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalLong.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/OptionalLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -27,18 +27,27 @@ import java.util.function.LongConsumer; import java.util.function.LongSupplier; import java.util.function.Supplier; +import java.util.stream.LongStream; // Android-changed: removed ValueBased paragraph. /** * A container object which may or may not contain a {@code long} value. - * If a value is present, {@code isPresent()} will return {@code true} and - * {@code getAsLong()} will return the value. + * If a value is present, {@code isPresent()} returns {@code true}. If no + * value is present, the object is considered empty and + * {@code isPresent()} returns {@code false}. * *

    Additional methods that depend on the presence or absence of a contained * value are provided, such as {@link #orElse(long) orElse()} - * (return a default value if value not present) and - * {@link #ifPresent(java.util.function.LongConsumer) ifPresent()} (execute a block - * of code if the value is present). + * (returns a default value if no value is present) and + * {@link #ifPresent(LongConsumer) ifPresent()} (performs an + * action if a value is present). + * + * + * @apiNote + * {@code OptionalLong} is primarily intended for use as a method return type where + * there is a clear need to represent "no result." A variable whose type is + * {@code OptionalLong} should never itself be {@code null}; it should always point + * to an {@code OptionalLong} instance. * * @since 1.8 */ @@ -66,24 +75,25 @@ private OptionalLong() { } /** - * Returns an empty {@code OptionalLong} instance. No value is present for this - * OptionalLong. + * Returns an empty {@code OptionalLong} instance. No value is present for + * this {@code OptionalLong}. * - * @apiNote Though it may be tempting to do so, avoid testing if an object - * is empty by comparing with {@code ==} against instances returned by - * {@code Option.empty()}. There is no guarantee that it is a singleton. + * @apiNote + * Though it may be tempting to do so, avoid testing if an object is empty + * by comparing with {@code ==} against instances returned by + * {@code OptionalLong.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * - * @return an empty {@code OptionalLong}. + * @return an empty {@code OptionalLong}. */ public static OptionalLong empty() { return EMPTY; } /** - * Construct an instance with the value present. + * Construct an instance with the described value. * - * @param value the long value to be present + * @param value the long value to describe */ private OptionalLong(long value) { this.isPresent = true; @@ -91,9 +101,9 @@ private OptionalLong(long value) { } /** - * Return an {@code OptionalLong} with the specified value present. + * Returns an {@code OptionalLong} describing the given value. * - * @param value the value to be present + * @param value the value to describe * @return an {@code OptionalLong} with the value present */ public static OptionalLong of(long value) { @@ -101,13 +111,14 @@ public static OptionalLong of(long value) { } /** - * If a value is present in this {@code OptionalLong}, returns the value, - * otherwise throws {@code NoSuchElementException}. + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @return the value held by this {@code OptionalLong} - * @throws NoSuchElementException if there is no value present + * @apiNote + * The preferred alternative to this method is {@link #orElseThrow()}. * - * @see OptionalLong#isPresent() + * @return the value described by this {@code OptionalLong} + * @throws NoSuchElementException if no value is present */ public long getAsLong() { if (!isPresent) { @@ -117,31 +128,87 @@ public long getAsLong() { } /** - * Return {@code true} if there is a value present, otherwise {@code false}. + * If a value is present, returns {@code true}, otherwise {@code false}. * - * @return {@code true} if there is a value present, otherwise {@code false} + * @return {@code true} if a value is present, otherwise {@code false} */ public boolean isPresent() { return isPresent; } /** - * Have the specified consumer accept the value if a value is present, - * otherwise do nothing. + * If a value is not present, returns {@code true}, otherwise + * {@code false}. + * + * @return {@code true} if a value is not present, otherwise {@code false} + * @since 11 + */ + public boolean isEmpty() { + return !isPresent; + } + + /** + * If a value is present, performs the given action with the value, + * otherwise does nothing. * - * @param consumer block to be executed if a value is present - * @throws NullPointerException if value is present and {@code consumer} is - * null + * @param action the action to be performed, if a value is present + * @throws NullPointerException if value is present and the given action is + * {@code null} */ - public void ifPresent(LongConsumer consumer) { - if (isPresent) - consumer.accept(value); + public void ifPresent(LongConsumer action) { + if (isPresent) { + action.accept(value); + } } /** - * Return the value if present, otherwise return {@code other}. + * If a value is present, performs the given action with the value, + * otherwise performs the given empty-based action. * - * @param other the value to be returned if there is no value present + * @param action the action to be performed, if a value is present + * @param emptyAction the empty-based action to be performed, if no value is + * present + * @throws NullPointerException if a value is present and the given action + * is {@code null}, or no value is present and the given empty-based + * action is {@code null}. + * @since 9 + */ + public void ifPresentOrElse(LongConsumer action, Runnable emptyAction) { + if (isPresent) { + action.accept(value); + } else { + emptyAction.run(); + } + } + + /** + * If a value is present, returns a sequential {@link LongStream} containing + * only that value, otherwise returns an empty {@code LongStream}. + * + * @apiNote + * This method can be used to transform a {@code Stream} of optional longs + * to an {@code LongStream} of present longs: + *

    {@code
    +     *     Stream os = ..
    +     *     LongStream s = os.flatMapToLong(OptionalLong::stream)
    +     * }
    + * + * @return the optional value as an {@code LongStream} + * @since 9 + */ + public LongStream stream() { + if (isPresent) { + return LongStream.of(value); + } else { + return LongStream.empty(); + } + } + + /** + * If a value is present, returns the value, otherwise returns + * {@code other}. + * + * @param other the value to be returned, if no value is present * @return the value, if present, otherwise {@code other} */ public long orElse(long other) { @@ -149,36 +216,52 @@ public long orElse(long other) { } /** - * Return the value if present, otherwise invoke {@code other} and return - * the result of that invocation. + * If a value is present, returns the value, otherwise returns the result + * produced by the supplying function. + * + * @param supplier the supplying function that produces a value to be returned + * @return the value, if present, otherwise the result produced by the + * supplying function + * @throws NullPointerException if no value is present and the supplying + * function is {@code null} + */ + public long orElseGet(LongSupplier supplier) { + return isPresent ? value : supplier.getAsLong(); + } + + /** + * If a value is present, returns the value, otherwise throws + * {@code NoSuchElementException}. * - * @param other a {@code LongSupplier} whose result is returned if no value - * is present - * @return the value if present otherwise the result of {@code other.getAsLong()} - * @throws NullPointerException if value is not present and {@code other} is - * null + * @return the value described by this {@code OptionalLong} + * @throws NoSuchElementException if no value is present + * @since 10 */ - public long orElseGet(LongSupplier other) { - return isPresent ? value : other.getAsLong(); + public long orElseThrow() { + if (!isPresent) { + throw new NoSuchElementException("No value present"); + } + return value; } /** - * Return the contained value, if present, otherwise throw an exception - * to be created by the provided supplier. + * If a value is present, returns the value, otherwise throws an exception + * produced by the exception supplying function. * - * @apiNote A method reference to the exception constructor with an empty - * argument list can be used as the supplier. For example, + * @apiNote + * A method reference to the exception constructor with an empty argument + * list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to - * be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and - * {@code exceptionSupplier} is null - */ - public long orElseThrow(Supplier exceptionSupplier) throws X { + * @param exceptionSupplier the supplying function that produces an + * exception to be thrown + * @return the value, if present + * @throws X if no value is present + * @throws NullPointerException if no value is present and the exception + * supplying function is {@code null} + */ + public long orElseThrow(Supplier exceptionSupplier) throws X { if (isPresent) { return value; } else { @@ -187,8 +270,8 @@ public long orElseThrow(Supplier exceptionSupplier) thro } /** - * Indicates whether some other object is "equal to" this OptionalLong. The - * other object is considered equal if: + * Indicates whether some other object is "equal to" this + * {@code OptionalLong}. The other object is considered equal if: *
      *
    • it is also an {@code OptionalLong} and; *
    • both instances have no value present or; @@ -196,8 +279,8 @@ public long orElseThrow(Supplier exceptionSupplier) thro *
    * * @param obj an object to be tested for equality - * @return {code true} if the other object is "equal to" this object - * otherwise {@code false} + * @return {@code true} if the other object is "equal to" this object + * otherwise {@code false} */ @Override public boolean equals(Object obj) { @@ -216,10 +299,11 @@ public boolean equals(Object obj) { } /** - * Returns the hash code value of the present value, if any, or 0 (zero) if - * no value is present. + * Returns the hash code of the value, if present, otherwise {@code 0} + * (zero) if no value is present. * - * @return hash code value of the present value or 0 if no value is present + * @return hash code value of the present value or {@code 0} if no value is + * present */ @Override public int hashCode() { @@ -227,14 +311,13 @@ public int hashCode() { } /** - * {@inheritDoc} - * - * Returns a non-empty string representation of this object suitable for - * debugging. The exact presentation format is unspecified and may vary - * between implementations and versions. + * Returns a non-empty string representation of this {@code OptionalLong} + * suitable for debugging. The exact presentation format is unspecified and + * may vary between implementations and versions. * - * @implSpec If a value is present the result must include its string - * representation in the result. Empty and present instances must be + * @implSpec + * If a value is present the result must include its string representation + * in the result. Empty and present {@code OptionalLong}s must be * unambiguously differentiable. * * @return the string representation of this instance diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/PriorityQueue.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/PriorityQueue.java index 7c929bda6d..48bf56adcd 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/PriorityQueue.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/PriorityQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -26,6 +26,7 @@ package java.util; import java.util.function.Consumer; +import java.util.function.Predicate; /** * An unbounded priority {@linkplain Queue queue} based on a priority heap. @@ -54,7 +55,8 @@ *

    This class and its iterator implement all of the * optional methods of the {@link Collection} and {@link * Iterator} interfaces. The Iterator provided in method {@link - * #iterator()} is not guaranteed to traverse the elements of + * #iterator()} and the Spliterator provided in method {@link #spliterator()} + * are not guaranteed to traverse the elements of * the priority queue in any particular order. If you need ordered * traversal, consider using {@code Arrays.sort(pq.toArray())}. * @@ -72,13 +74,14 @@ * ({@code peek}, {@code element}, and {@code size}). * *

    This class is a member of the - * + * * Java Collections Framework. * * @since 1.5 * @author Josh Bloch, Doug Lea * @param the type of elements held in this queue */ +@SuppressWarnings("unchecked") public class PriorityQueue extends AbstractQueue implements java.io.Serializable { @@ -185,7 +188,6 @@ public PriorityQueue(int initialCapacity, * @throws NullPointerException if the specified collection or any * of its elements are null */ - @SuppressWarnings("unchecked") public PriorityQueue(Collection c) { if (c instanceof SortedSet) { SortedSet ss = (SortedSet) c; @@ -217,7 +219,6 @@ else if (c instanceof PriorityQueue) { * @throws NullPointerException if the specified priority queue or any * of its elements are null */ - @SuppressWarnings("unchecked") public PriorityQueue(PriorityQueue c) { this.comparator = (Comparator) c.comparator(); initFromPriorityQueue(c); @@ -236,15 +237,19 @@ public PriorityQueue(PriorityQueue c) { * @throws NullPointerException if the specified sorted set or any * of its elements are null */ - @SuppressWarnings("unchecked") public PriorityQueue(SortedSet c) { this.comparator = (Comparator) c.comparator(); initElementsFromCollection(c); } + /** Ensures that queue[0] exists, helping peek() and poll(). */ + private static Object[] ensureNonEmpty(Object[] es) { + return (es.length > 0) ? es : new Object[1]; + } + private void initFromPriorityQueue(PriorityQueue c) { if (c.getClass() == PriorityQueue.class) { - this.queue = c.toArray(); + this.queue = ensureNonEmpty(c.toArray()); this.size = c.size(); } else { initFromCollection(c); @@ -252,17 +257,16 @@ private void initFromPriorityQueue(PriorityQueue c) { } private void initElementsFromCollection(Collection c) { - Object[] a = c.toArray(); - // If c.toArray incorrectly doesn't return Object[], copy it. - if (a.getClass() != Object[].class) - a = Arrays.copyOf(a, a.length, Object[].class); - int len = a.length; + Object[] es = c.toArray(); + int len = es.length; + if (c.getClass() != ArrayList.class) + es = Arrays.copyOf(es, len, Object[].class); if (len == 1 || this.comparator != null) - for (Object e : a) + for (Object e : es) if (e == null) throw new NullPointerException(); - this.queue = a; - this.size = a.length; + this.queue = ensureNonEmpty(es); + this.size = len; } /** @@ -345,15 +349,15 @@ public boolean offer(E e) { return true; } - @SuppressWarnings("unchecked") public E peek() { - return (size == 0) ? null : (E) queue[0]; + return (E) queue[0]; } private int indexOf(Object o) { if (o != null) { - for (int i = 0; i < size; i++) - if (o.equals(queue[i])) + final Object[] es = queue; + for (int i = 0, n = size; i < n; i++) + if (o.equals(es[i])) return i; } return -1; @@ -381,20 +385,18 @@ public boolean remove(Object o) { } /** - * Version of remove using reference equality, not equals. - * Needed by iterator.remove. + * Identity-based version for use in Itr.remove. * * @param o element to be removed from this queue, if present - * @return {@code true} if removed */ - boolean removeEq(Object o) { - for (int i = 0; i < size; i++) { - if (o == queue[i]) { + void removeEq(Object o) { + final Object[] es = queue; + for (int i = 0, n = size; i < n; i++) { + if (o == es[i]) { removeAt(i); - return true; + break; } } - return false; } /** @@ -462,7 +464,6 @@ public Object[] toArray() { * this queue * @throws NullPointerException if the specified array is null */ - @SuppressWarnings("unchecked") public T[] toArray(T[] a) { final int size = this.size; if (a.length < size) @@ -524,12 +525,13 @@ private final class Itr implements Iterator { */ private int expectedModCount = modCount; + Itr() {} // prevent access constructor creation + public boolean hasNext() { return cursor < size || (forgetMeNot != null && !forgetMeNot.isEmpty()); } - @SuppressWarnings("unchecked") public E next() { if (expectedModCount != modCount) throw new ConcurrentModificationException(); @@ -577,22 +579,29 @@ public int size() { */ public void clear() { modCount++; - for (int i = 0; i < size; i++) - queue[i] = null; + final Object[] es = queue; + for (int i = 0, n = size; i < n; i++) + es[i] = null; size = 0; } - @SuppressWarnings("unchecked") public E poll() { - if (size == 0) - return null; - int s = --size; - modCount++; - E result = (E) queue[0]; - E x = (E) queue[s]; - queue[s] = null; - if (s != 0) - siftDown(0, x); + final Object[] es; + final E result; + + if ((result = (E) ((es = queue)[0])) != null) { + modCount++; + final int n; + final E x = (E) es[(n = --size)]; + es[n] = null; + if (n > 0) { + final Comparator cmp; + if ((cmp = comparator) == null) + siftDownComparable(0, x, es, n); + else + siftDownUsingComparator(0, x, es, n, cmp); + } + } return result; } @@ -608,20 +617,20 @@ public E poll() { * position before i. This fact is used by iterator.remove so as to * avoid missing traversing elements. */ - @SuppressWarnings("unchecked") E removeAt(int i) { // assert i >= 0 && i < size; + final Object[] es = queue; modCount++; int s = --size; if (s == i) // removed last element - queue[i] = null; + es[i] = null; else { - E moved = (E) queue[s]; - queue[s] = null; + E moved = (E) es[s]; + es[s] = null; siftDown(i, moved); - if (queue[i] == moved) { + if (es[i] == moved) { siftUp(i, moved); - if (queue[i] != moved) + if (es[i] != moved) return moved; } } @@ -633,7 +642,7 @@ E removeAt(int i) { * promoting x up the tree until it is greater than or equal to * its parent, or is the root. * - * To simplify and speed up coercions and comparisons. the + * To simplify and speed up coercions and comparisons, the * Comparable and Comparator versions are separated into different * methods that are otherwise identical. (Similarly for siftDown.) * @@ -642,36 +651,35 @@ E removeAt(int i) { */ private void siftUp(int k, E x) { if (comparator != null) - siftUpUsingComparator(k, x); + siftUpUsingComparator(k, x, queue, comparator); else - siftUpComparable(k, x); + siftUpComparable(k, x, queue); } - @SuppressWarnings("unchecked") - private void siftUpComparable(int k, E x) { - Comparable key = (Comparable) x; + private static void siftUpComparable(int k, T x, Object[] es) { + Comparable key = (Comparable) x; while (k > 0) { int parent = (k - 1) >>> 1; - Object e = queue[parent]; - if (key.compareTo((E) e) >= 0) + Object e = es[parent]; + if (key.compareTo((T) e) >= 0) break; - queue[k] = e; + es[k] = e; k = parent; } - queue[k] = key; + es[k] = key; } - @SuppressWarnings("unchecked") - private void siftUpUsingComparator(int k, E x) { + private static void siftUpUsingComparator( + int k, T x, Object[] es, Comparator cmp) { while (k > 0) { int parent = (k - 1) >>> 1; - Object e = queue[parent]; - if (comparator.compare(x, (E) e) >= 0) + Object e = es[parent]; + if (cmp.compare(x, (T) e) >= 0) break; - queue[k] = e; + es[k] = e; k = parent; } - queue[k] = x; + es[k] = x; } /** @@ -684,56 +692,63 @@ private void siftUpUsingComparator(int k, E x) { */ private void siftDown(int k, E x) { if (comparator != null) - siftDownUsingComparator(k, x); + siftDownUsingComparator(k, x, queue, size, comparator); else - siftDownComparable(k, x); + siftDownComparable(k, x, queue, size); } - @SuppressWarnings("unchecked") - private void siftDownComparable(int k, E x) { - Comparable key = (Comparable)x; - int half = size >>> 1; // loop while a non-leaf + private static void siftDownComparable(int k, T x, Object[] es, int n) { + // assert n > 0; + Comparable key = (Comparable)x; + int half = n >>> 1; // loop while a non-leaf while (k < half) { int child = (k << 1) + 1; // assume left child is least - Object c = queue[child]; + Object c = es[child]; int right = child + 1; - if (right < size && - ((Comparable) c).compareTo((E) queue[right]) > 0) - c = queue[child = right]; - if (key.compareTo((E) c) <= 0) + if (right < n && + ((Comparable) c).compareTo((T) es[right]) > 0) + c = es[child = right]; + if (key.compareTo((T) c) <= 0) break; - queue[k] = c; + es[k] = c; k = child; } - queue[k] = key; + es[k] = key; } - @SuppressWarnings("unchecked") - private void siftDownUsingComparator(int k, E x) { - int half = size >>> 1; + private static void siftDownUsingComparator( + int k, T x, Object[] es, int n, Comparator cmp) { + // assert n > 0; + int half = n >>> 1; while (k < half) { int child = (k << 1) + 1; - Object c = queue[child]; + Object c = es[child]; int right = child + 1; - if (right < size && - comparator.compare((E) c, (E) queue[right]) > 0) - c = queue[child = right]; - if (comparator.compare(x, (E) c) <= 0) + if (right < n && cmp.compare((T) c, (T) es[right]) > 0) + c = es[child = right]; + if (cmp.compare(x, (T) c) <= 0) break; - queue[k] = c; + es[k] = c; k = child; } - queue[k] = x; + es[k] = x; } /** * Establishes the heap invariant (described above) in the entire tree, * assuming nothing about the order of the elements prior to the call. + * This classic algorithm due to Floyd (1964) is known to be O(size). */ - @SuppressWarnings("unchecked") private void heapify() { - for (int i = (size >>> 1) - 1; i >= 0; i--) - siftDown(i, (E) queue[i]); + final Object[] es = queue; + int n = size, i = (n >>> 1) - 1; + final Comparator cmp; + if ((cmp = comparator) == null) + for (; i >= 0; i--) + siftDownComparable(i, (E) es[i], es, n); + else + for (; i >= 0; i--) + siftDownUsingComparator(i, (E) es[i], es, n, cmp); } /** @@ -752,11 +767,11 @@ public Comparator comparator() { /** * Saves this queue to a stream (that is, serializes it). * + * @param s the stream + * @throws java.io.IOException if an I/O error occurs * @serialData The length of the array backing the instance is * emitted (int), followed by all of its elements * (each an {@code Object}) in the proper order. - * @param s the stream - * @throws java.io.IOException if an I/O error occurs */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -767,8 +782,9 @@ private void writeObject(java.io.ObjectOutputStream s) s.writeInt(Math.max(2, size + 1)); // Write out all elements in the "proper order". - for (int i = 0; i < size; i++) - s.writeObject(queue[i]); + final Object[] es = queue; + for (int i = 0, n = size; i < n; i++) + s.writeObject(es[i]); } /** @@ -802,7 +818,8 @@ private void readObject(java.io.ObjectInputStream s) /** * Creates a late-binding * and fail-fast {@link Spliterator} over the elements in this - * queue. + * queue. The spliterator does not traverse elements in any particular order + * (the {@link Spliterator#ORDERED ORDERED} characteristic is not reported). * *

    The {@code Spliterator} reports {@link Spliterator#SIZED}, * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}. @@ -906,4 +923,89 @@ public int characteristics() { return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL; } } + + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return bulkRemove(filter); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean removeAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> c.contains(e)); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean retainAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> !c.contains(e)); + } + + // A tiny bit set implementation + + private static long[] nBits(int n) { + return new long[((n - 1) >> 6) + 1]; + } + private static void setBit(long[] bits, int i) { + bits[i >> 6] |= 1L << i; + } + private static boolean isClear(long[] bits, int i) { + return (bits[i >> 6] & (1L << i)) == 0; + } + + /** Implementation of bulk remove methods. */ + private boolean bulkRemove(Predicate filter) { + final int expectedModCount = ++modCount; + final Object[] es = queue; + final int end = size; + int i; + // Optimize for initial run of survivors + for (i = 0; i < end && !filter.test((E) es[i]); i++) + ; + if (i >= end) { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + return false; + } + // Tolerate predicates that reentrantly access the collection for + // read (but writers still get CME), so traverse once to find + // elements to delete, a second pass to physically expunge. + final int beg = i; + final long[] deathRow = nBits(end - beg); + deathRow[0] = 1L; // set bit 0 + for (i = beg + 1; i < end; i++) + if (filter.test((E) es[i])) + setBit(deathRow, i - beg); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + int w = beg; + for (i = beg; i < end; i++) + if (isClear(deathRow, i - beg)) + es[w++] = es[i]; + for (i = size = w; i < end; i++) + es[i] = null; + heapify(); + return true; + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public void forEach(Consumer action) { + Objects.requireNonNull(action); + final int expectedModCount = modCount; + final Object[] es = queue; + for (int i = 0, n = size; i < n; i++) + action.accept((E) es[i]); + if (expectedModCount != modCount) + throw new ConcurrentModificationException(); + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java index 12214a07df..e0839bc84a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java @@ -29,6 +29,8 @@ import com.google.j2objc.LibraryNotLinkedError; import java.io.BufferedWriter; import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -40,7 +42,8 @@ import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; -// Android-changed: Removed dead native2ascii links +// Android-removed: Dead native2ascii links. +// These links are also gone in OpenJDK 9. /** * The {@code Properties} class represents a persistent set of * properties. The {@code Properties} can be saved to a stream @@ -384,9 +387,9 @@ public static void loadLineReader(LineReader lr, KeyValueLoader loader) throws I valueStart = keyLen + 1; hasSep = true; break; - } - // Android-changed: use of Character.isWhitespace(c) b/25998006 - else if (Character.isWhitespace(c) && !precedingBackslash) { + // Android-changed: Treat all whitespace the same. http://b/25998006 + // } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { + } else if (Character.isWhitespace(c) && !precedingBackslash) { valueStart = keyLen + 1; break; } @@ -399,7 +402,8 @@ else if (Character.isWhitespace(c) && !precedingBackslash) { } while (valueStart < limit) { c = lr.lineBuf[valueStart]; - // Android-changed: use of Character.isWhitespace(c) b/25998006 + // Android-changed: Treat all whitespace the same. http://b/25998006 + // if (c != ' ' && c != '\t' && c != '\f') { if (!Character.isWhitespace(c)) { if (!hasSep && (c == '=' || c == ':')) { hasSep = true; @@ -419,8 +423,7 @@ private void load0(LineReader lr) throws IOException { loadLineReader(lr, this::put); } - /** - * Read in a "logical line" from an InputStream/Reader, skip all comment + /* Read in a "logical line" from an InputStream/Reader, skip all comment * and blank lines and filter out those leading whitespace characters * (\u0020, \u0009 and \u000c) from the beginning of a "natural line". * Method returns the char length of the "logical line" and stores @@ -485,7 +488,8 @@ int readLine() throws IOException { } } if (skipWhiteSpace) { - // Android-changed: use of Character.isWhitespace(c) b/25998006 + // Android-changed: Treat all whitespace the same. http://b/25998006 + // if (c == ' ' || c == '\t' || c == '\f') { if (Character.isWhitespace(c)) { continue; } @@ -1242,4 +1246,89 @@ private static char toHex(int nibble) { private static final char[] hexDigit = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + + // Android-removed: Keep OpenJDK7u40's XmlUtils. + // XmlSupport's system property based XmlPropertiesProvider + // selection does not make sense on Android and has too many + // dependencies on classes that are not available on Android. + /* + /** + * Supporting class for loading/storing properties in XML format. + * + *

    The {@code load} and {@code store} methods defined here delegate to a + * system-wide {@code XmlPropertiesProvider}. On first invocation of either + * method then the system-wide provider is located as follows:

    + * + *
      + *
    1. If the system property {@code sun.util.spi.XmlPropertiesProvider} + * is defined then it is taken to be the full-qualified name of a concrete + * provider class. The class is loaded with the system class loader as the + * initiating loader. If it cannot be loaded or instantiated using a zero + * argument constructor then an unspecified error is thrown.
    2. + * + *
    3. If the system property is not defined then the service-provider + * loading facility defined by the {@link ServiceLoader} class is used to + * locate a provider with the system class loader as the initiating + * loader and {@code sun.util.spi.XmlPropertiesProvider} as the service + * type. If this process fails then an unspecified error is thrown. If + * there is more than one service provider installed then it is + * not specified as to which provider will be used.
    4. + * + *
    5. If the provider is not found by the above means then a system + * default provider will be instantiated and used.
    6. + *
    + * + private static class XmlSupport { + + private static XmlPropertiesProvider loadProviderFromProperty(ClassLoader cl) { + String cn = System.getProperty("sun.util.spi.XmlPropertiesProvider"); + if (cn == null) + return null; + try { + Class c = Class.forName(cn, true, cl); + return (XmlPropertiesProvider)c.newInstance(); + } catch (ClassNotFoundException | + IllegalAccessException | + InstantiationException x) { + throw new ServiceConfigurationError(null, x); + } + } + + private static XmlPropertiesProvider loadProviderAsService(ClassLoader cl) { + Iterator iterator = + ServiceLoader.load(XmlPropertiesProvider.class, cl).iterator(); + return iterator.hasNext() ? iterator.next() : null; + } + + private static XmlPropertiesProvider loadProvider() { + return AccessController.doPrivileged( + new PrivilegedAction() { + public XmlPropertiesProvider run() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + XmlPropertiesProvider provider = loadProviderFromProperty(cl); + if (provider != null) + return provider; + provider = loadProviderAsService(cl); + if (provider != null) + return provider; + return new jdk.internal.util.xml.BasicXmlPropertiesProvider(); + }}); + } + + private static final XmlPropertiesProvider PROVIDER = loadProvider(); + + static void load(Properties props, InputStream in) + throws IOException, InvalidPropertiesFormatException + { + PROVIDER.load(props, in); + } + + static void save(Properties props, OutputStream os, String comment, + String encoding) + throws IOException + { + PROVIDER.store(props, os, comment, encoding); + } + } + */ } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Queue.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Queue.java index cbdc205a1c..a3ff4bee07 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Queue.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Queue.java @@ -41,38 +41,41 @@ /** * A collection designed for holding elements prior to processing. - * Besides basic {@link java.util.Collection Collection} operations, - * queues provide additional insertion, extraction, and inspection - * operations. Each of these methods exists in two forms: one throws - * an exception if the operation fails, the other returns a special - * value (either {@code null} or {@code false}, depending on the - * operation). The latter form of the insert operation is designed - * specifically for use with capacity-restricted {@code Queue} - * implementations; in most implementations, insert operations cannot - * fail. + * Besides basic {@link Collection} operations, queues provide + * additional insertion, extraction, and inspection operations. + * Each of these methods exists in two forms: one throws an exception + * if the operation fails, the other returns a special value (either + * {@code null} or {@code false}, depending on the operation). The + * latter form of the insert operation is designed specifically for + * use with capacity-restricted {@code Queue} implementations; in most + * implementations, insert operations cannot fail. * - * + *
    * + * * * - * - * + * + * * + * + * * - * - * - * + * + * + * * * - * - * - * + * + * + * * * - * - * - * + * + * + * * + * *
    Summary of Queue methods
    Throws exceptionReturns special valueThrows exceptionReturns special value
    Insert{@link Queue#add add(e)}{@link Queue#offer offer(e)}Insert{@link #add(Object) add(e)}{@link #offer(Object) offer(e)}
    Remove{@link Queue#remove remove()}{@link Queue#poll poll()}Remove{@link #remove() remove()}{@link #poll() poll()}
    Examine{@link Queue#element element()}{@link Queue#peek peek()}Examine{@link #element() element()}{@link #peek() peek()}
    * *

    Queues typically, but do not necessarily, order elements in a @@ -81,7 +84,7 @@ * comparator, or the elements' natural ordering, and LIFO queues (or * stacks) which order the elements LIFO (last-in-first-out). * Whatever the ordering used, the head of the queue is that - * element which would be removed by a call to {@link #remove() } or + * element which would be removed by a call to {@link #remove()} or * {@link #poll()}. In a FIFO queue, all new elements are inserted at * the tail of the queue. Other kinds of queues may use * different placement rules. Every {@code Queue} implementation @@ -173,8 +176,8 @@ public interface Queue extends Collection { /** * Retrieves and removes the head of this queue. This method differs - * from {@link #poll poll} only in that it throws an exception if this - * queue is empty. + * from {@link #poll() poll()} only in that it throws an exception if + * this queue is empty. * * @return the head of this queue * @throws NoSuchElementException if this queue is empty diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Random.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Random.java index 1061b59361..6982f0d940 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Random.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Random.java @@ -110,7 +110,7 @@ private static long seedUniquifier() { // Different Sizes and Good Lattice Structure", 1999 for (;;) { long current = seedUniquifier.get(); - long next = current * 181783497276652981L; + long next = current * 1181783497276652981L; if (seedUniquifier.compareAndSet(current, next)) return next; } @@ -165,7 +165,7 @@ private static long initialScramble(long seed) { * * @param seed the initial seed */ - synchronized public void setSeed(long seed) { + public synchronized void setSeed(long seed) { this.seed.set(initialScramble(seed)); haveNextNextGaussian = false; } @@ -187,7 +187,7 @@ synchronized public void setSeed(long seed) { * * This is a linear congruential pseudorandom number generator, as * defined by D. H. Lehmer and described by Donald E. Knuth in - * The Art of Computer Programming, Volume 3: + * The Art of Computer Programming, Volume 2: * Seminumerical Algorithms, section 3.2.1. * * @param bits random bits @@ -570,7 +570,7 @@ public double nextDouble() { * }}

    * This uses the polar method of G. E. P. Box, M. E. Muller, and * G. Marsaglia, as described by Donald E. Knuth in The Art of - * Computer Programming, Volume 3: Seminumerical Algorithms, + * Computer Programming, Volume 2: Seminumerical Algorithms, * section 3.4.1, subsection C, algorithm P. Note that it generates two * independent values at the cost of only one call to {@code StrictMath.log} * and one call to {@code StrictMath.sqrt}. @@ -580,7 +580,7 @@ public double nextDouble() { * standard deviation {@code 1.0} from this random number * generator's sequence */ - synchronized public double nextGaussian() { + public synchronized double nextGaussian() { // See Knuth, ACP, Section 3.4.1 Algorithm C. if (haveNextNextGaussian) { haveNextNextGaussian = false; @@ -1197,7 +1197,7 @@ private void readObject(java.io.ObjectInputStream s) /** * Save the {@code Random} instance to a stream. */ - synchronized private void writeObject(ObjectOutputStream s) + private synchronized void writeObject(ObjectOutputStream s) throws IOException { // set the values of the Serializable fields diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RandomAccess.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RandomAccess.java index 09ce29edce..52de56d9fa 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RandomAccess.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RandomAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -26,27 +26,27 @@ package java.util; /** - * Marker interface used by List implementations to indicate that + * Marker interface used by {@code List} implementations to indicate that * they support fast (generally constant time) random access. The primary * purpose of this interface is to allow generic algorithms to alter their * behavior to provide good performance when applied to either random or * sequential access lists. * *

    The best algorithms for manipulating random access lists (such as - * ArrayList) can produce quadratic behavior when applied to - * sequential access lists (such as LinkedList). Generic list + * {@code ArrayList}) can produce quadratic behavior when applied to + * sequential access lists (such as {@code LinkedList}). Generic list * algorithms are encouraged to check whether the given list is an - * instanceof this interface before applying an algorithm that would + * {@code instanceof} this interface before applying an algorithm that would * provide poor performance if it were applied to a sequential access list, * and to alter their behavior if necessary to guarantee acceptable * performance. * *

    It is recognized that the distinction between random and sequential - * access is often fuzzy. For example, some List implementations + * access is often fuzzy. For example, some {@code List} implementations * provide asymptotically linear access times if they get huge, but constant - * access times in practice. Such a List implementation + * access times in practice. Such a {@code List} implementation * should generally implement this interface. As a rule of thumb, a - * List implementation should implement this interface if, + * {@code List} implementation should implement this interface if, * for typical instances of the class, this loop: *

      *     for (int i=0, n=list.size(); i < n; i++)
    @@ -59,7 +59,7 @@
      * 
    * *

    This interface is a member of the - * + * * Java Collections Framework. * * @since 1.4 diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RegularEnumSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RegularEnumSet.java index 31a63f15cc..eef447eeb4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RegularEnumSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/RegularEnumSet.java @@ -123,19 +123,19 @@ public int size() { } /** - * Returns true if this set contains no elements. + * Returns {@code true} if this set contains no elements. * - * @return true if this set contains no elements + * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return elements == 0; } /** - * Returns true if this set contains the specified element. + * Returns {@code true} if this set contains the specified element. * * @param e element to be checked for containment in this collection - * @return true if this set contains the specified element + * @return {@code true} if this set contains the specified element */ public boolean contains(Object e) { if (e == null) @@ -153,9 +153,9 @@ public boolean contains(Object e) { * Adds the specified element to this set if it is not already present. * * @param e element to be added to this set - * @return true if the set changed as a result of the call + * @return {@code true} if the set changed as a result of the call * - * @throws NullPointerException if e is null + * @throws NullPointerException if {@code e} is null */ public boolean add(E e) { typeCheck(e); @@ -169,7 +169,7 @@ public boolean add(E e) { * Removes the specified element from this set if it is present. * * @param e element to be removed from this set, if present - * @return true if the set contained the specified element + * @return {@code true} if the set contained the specified element */ public boolean remove(Object e) { if (e == null) @@ -186,11 +186,11 @@ public boolean remove(Object e) { // Bulk Operations /** - * Returns true if this set contains all of the elements + * Returns {@code true} if this set contains all of the elements * in the specified collection. * * @param c collection to be checked for containment in this set - * @return true if this set contains all of the elements + * @return {@code true} if this set contains all of the elements * in the specified collection * @throws NullPointerException if the specified collection is null */ @@ -209,7 +209,7 @@ public boolean containsAll(Collection c) { * Adds all of the elements in the specified collection to this set. * * @param c collection whose elements are to be added to this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection or any * of its elements are null */ @@ -236,7 +236,7 @@ public boolean addAll(Collection c) { * the specified collection. * * @param c elements to be removed from this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean removeAll(Collection c) { @@ -257,7 +257,7 @@ public boolean removeAll(Collection c) { * specified collection. * * @param c elements to be retained in this set - * @return true if this set changed as a result of the call + * @return {@code true} if this set changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean retainAll(Collection c) { @@ -285,12 +285,12 @@ public void clear() { /** * Compares the specified object with this set for equality. Returns - * true if the given object is also a set, the two sets have + * {@code true} if the given object is also a set, the two sets have * the same size, and every member of the given set is contained in * this set. * * @param o object to be compared for equality with this set - * @return true if the specified object is equal to this set + * @return {@code true} if the specified object is equal to this set */ public boolean equals(Object o) { if (!(o instanceof RegularEnumSet)) diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ResourceBundle.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ResourceBundle.java index 8cec47c0f5..7c5b025e84 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ResourceBundle.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ResourceBundle.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, 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 @@ -41,6 +41,17 @@ package java.util; +/* J2ObjC removed +import java.io.UncheckedIOException; +import java.lang.ref.Reference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.util.jar.JarEntry; +import sun.security.action.GetPropertyAction; +*/ + import com.google.j2objc.annotations.Weak; import java.io.IOException; import java.io.InputStream; @@ -48,7 +59,6 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; -//import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; @@ -58,18 +68,16 @@ import java.security.PrivilegedExceptionAction; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -//import java.util.jar.JarEntry; - import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.util.locale.BaseLocale; import sun.util.locale.LocaleObjectCache; - // Android-removed: Support for ResourceBundleControlProvider. // Removed references to ResourceBundleControlProvider from the documentation. // The service provider interface ResourceBundleControlProvider is not // available on Android. +// Android-removed: Mentions of modules as they are not supported. /** * * Resource bundles contain locale-specific objects. When your program needs a @@ -278,13 +286,56 @@ * @see ListResourceBundle * @see PropertyResourceBundle * @see MissingResourceException - * @since JDK1.1 + * @since 1.1 + * @revised 9 */ public abstract class ResourceBundle { /** initial size of the bundle cache */ private static final int INITIAL_CACHE_SIZE = 32; + // Android-removed: JavaUtilResourceBundleAccess is absent. + /* + static { + SharedSecrets.setJavaUtilResourceBundleAccess( + new JavaUtilResourceBundleAccess() { + @Override + public void setParent(ResourceBundle bundle, + ResourceBundle parent) { + bundle.setParent(parent); + } + + @Override + public ResourceBundle getParent(ResourceBundle bundle) { + return bundle.parent; + } + + @Override + public void setLocale(ResourceBundle bundle, Locale locale) { + bundle.locale = locale; + } + + @Override + public void setName(ResourceBundle bundle, String name) { + bundle.name = name; + } + + @Override + public ResourceBundle getBundle(String baseName, Locale locale, Module module) { + // use the given module as the caller to bypass the access check + return getBundleImpl(module, module, + baseName, locale, + getDefaultControl(module, baseName)); + } + + @Override + public ResourceBundle newResourceBundle(Class bundleClass) { + return ResourceBundleProviderHelper.newResourceBundle(bundleClass); + } + }); + } + */ + /** constant indicating that no resource bundle exists */ private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() { public Enumeration getKeys() { return null; } @@ -364,24 +415,6 @@ public String getBaseBundleName() { */ private volatile Set keySet; - // Android-removed: Support for ResourceBundleControlProvider. - /* - private static final List providers; - - static { - List list = null; - ServiceLoader serviceLoaders - = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class); - for (ResourceBundleControlProvider provider : serviceLoaders) { - if (list == null) { - list = new ArrayList<>(); - } - list.add(provider); - } - providers = list; - } - */ - /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) @@ -488,11 +521,11 @@ private static ClassLoader getLoader(Class caller) { */ private static class RBClassLoader extends ClassLoader { private static final RBClassLoader INSTANCE = AccessController.doPrivileged( - new PrivilegedAction() { - public RBClassLoader run() { - return new RBClassLoader(); - } - }); + new PrivilegedAction() { + public RBClassLoader run() { + return new RBClassLoader(); + } + }); private static final ClassLoader loader = ClassLoader.getSystemClassLoader(); private RBClassLoader() { @@ -517,6 +550,24 @@ public InputStream getResourceAsStream(String name) { } } + // Android-removed: modules are not supported. + /* + private static ClassLoader getLoader(Module module) { + PrivilegedAction pa = module::getClassLoader; + return AccessController.doPrivileged(pa); + } + + /** + * @param module a non-null-screened module form the {@link CacheKey#getModule()}. + * @return the ClassLoader to use in {@link Control#needsReload} + * and {@link Control#newBundle} + * + private static ClassLoader getLoaderForControl(Module module) { + ClassLoader loader = getLoader(module); + return loader == null ? ClassLoader.getPlatformClassLoader() : loader; + } + */ + /** * Sets the parent bundle of this bundle. * The parent bundle is searched by {@link #getObject getObject} @@ -529,6 +580,8 @@ protected void setParent(ResourceBundle parent) { this.parent = parent; } + // Android-changed: as modules are not supported keep using ClassLoader as part + // of CacheKey. /** * Key used for cached resource bundles. The key checks the base * name, the locale, and the class loader to determine if the @@ -536,15 +589,23 @@ protected void setParent(ResourceBundle parent) { * null, but the base name and the locale must have a non-null * value. */ - private static class CacheKey implements Cloneable { + private static final class CacheKey implements Cloneable { // These three are the actual keys for lookup in Map. - private String name; - private Locale locale; - private LoaderReference loaderRef; + private final String name; + private volatile Locale locale; + private KeyElementReference loaderRef; + // Android-removed: modules are not supported. + /* + private final KeyElementReference moduleRef; + private final KeyElementReference callerRef; + // this is the part of hashCode that pertains to module and callerModule + // which can be GCed.. + private final int modulesHash; + */ // bundle format which is necessary for calling // Control.needsReload(). - private String format; + private volatile String format; // These time values are in CacheKey so that NONEXISTENT_BUNDLE // doesn't need to be cloned for caching. @@ -557,33 +618,64 @@ private static class CacheKey implements Cloneable { private volatile long expirationTime; // Placeholder for an error report by a Throwable - private Throwable cause; + private volatile Throwable cause; - // Hash code value cache to avoid recalculating the hash code - // of this instance. - private int hashCodeCache; + // Android-removed: Support for ResourceBundleControlProvider. + /* + // ResourceBundleProviders for loading ResourceBundles + private volatile ServiceLoader providers; + private volatile boolean providersChecked; + + // Boolean.TRUE if the factory method caller provides a ResourceBundleProvier. + private volatile Boolean callerHasProvider; + */ + // Android-changed: keep Java 8 constructor. + // CacheKey(String baseName, Locale locale, Module module, Module caller) { CacheKey(String baseName, Locale locale, ClassLoader loader) { + // Objects.requireNonNull(module); + // Objects.requireNonNull(caller); + this.name = baseName; this.locale = locale; + // this.moduleRef = new KeyElementReference<>(module, referenceQueue, this); + // this.callerRef = new KeyElementReference<>(caller, referenceQueue, this); + // this.modulesHash = module.hashCode() ^ caller.hashCode(); if (loader == null) { this.loaderRef = null; } else { - loaderRef = new LoaderReference(loader, referenceQueue, this); + this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this); } - calculateHashCode(); } - String getName() { - return name; + CacheKey(CacheKey src) { + // Android-removed: modules are not supported. + /* + // Create References to src's modules + this.moduleRef = new KeyElementReference<>( + Objects.requireNonNull(src.getModule()), referenceQueue, this); + this.callerRef = new KeyElementReference<>( + Objects.requireNonNull(src.getCallerModule()), referenceQueue, this); + */ + // Copy fields from src. ResourceBundleProviders related fields + // and "cause" should not be copied. + this.name = src.name; + this.locale = src.locale; + if (src.loaderRef == null) { + this.loaderRef = null; + } else { + ClassLoader loader = src.loaderRef.get(); + this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this); + } + // Android-removed: modules are not supported. + // this.modulesHash = src.modulesHash; + this.format = src.format; + this.loadTime = src.loadTime; + this.expirationTime = src.expirationTime; } - CacheKey setName(String baseName) { - if (!this.name.equals(baseName)) { - this.name = baseName; - calculateHashCode(); - } - return this; + String getName() { + return name; } Locale getLocale() { @@ -591,27 +683,53 @@ Locale getLocale() { } CacheKey setLocale(Locale locale) { - if (!this.locale.equals(locale)) { - this.locale = locale; - calculateHashCode(); - } + this.locale = locale; return this; } + // Android-removed: modules are not supported. + /* + Module getModule() { + return moduleRef.get(); + } + + Module getCallerModule() { + return callerRef.get(); + } + + ServiceLoader getProviders() { + if (!providersChecked) { + providers = getServiceLoader(getModule(), name); + providersChecked = true; + } + return providers; + } + + boolean hasProviders() { + return getProviders() != null; + } + + boolean callerHasProvider() { + return callerHasProvider == Boolean.TRUE; + } + */ + ClassLoader getLoader() { - return (loaderRef != null) ? loaderRef.get() : null; + return loaderRef != null ? loaderRef.get() : null; } + @Override public boolean equals(Object other) { if (this == other) { return true; } try { final CacheKey otherEntry = (CacheKey)other; + // Android-removed: modules are not supported. //quick check to see if they are not equal - if (hashCodeCache != otherEntry.hashCodeCache) { - return false; - } + // if (modulesHash != otherEntry.modulesHash) { + // return false; + // } //are the names the same? if (!name.equals(otherEntry.name)) { return false; @@ -620,6 +738,7 @@ public boolean equals(Object other) { if (!locale.equals(otherEntry.locale)) { return false; } + //are refs (both non-null) or (both null)? if (loaderRef == null) { return otherEntry.loaderRef == null; @@ -636,24 +755,21 @@ public boolean equals(Object other) { return false; } + @Override public int hashCode() { - return hashCodeCache; - } - - private void calculateHashCode() { - hashCodeCache = name.hashCode() << 3; - hashCodeCache ^= locale.hashCode(); + int hashCode = (name.hashCode() << 3) ^ locale.hashCode(); ClassLoader loader = getLoader(); if (loader != null) { - hashCodeCache ^= loader.hashCode(); + hashCode ^= loader.hashCode(); } + return hashCode; } public Object clone() { try { CacheKey clone = (CacheKey) super.clone(); if (loaderRef != null) { - clone.loaderRef = new LoaderReference(loaderRef.get(), + clone.loaderRef = new KeyElementReference(loaderRef.get(), referenceQueue, clone); } // Clear the reference to a Throwable @@ -689,17 +805,24 @@ private Throwable getCause() { return cause; } + @Override public String toString() { String l = locale.toString(); - if (l.length() == 0) { - if (locale.getVariant().length() != 0) { + if (l.isEmpty()) { + if (!locale.getVariant().isEmpty()) { l = "__" + locale.getVariant(); } else { l = "\"\""; } } - return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader() - + "(format=" + format + ")]"; + return "CacheKey[" + name + + ", locale=" + l + + ", classLoader" + getLoader() + + // Android-removed: modules are not supported. + // ", module=" + getModule() + + // ", callerModule=" + getCallerModule() + + ", format=" + format + + "]"; } } @@ -712,20 +835,20 @@ private static interface CacheKeyReference { } /** - * References to class loaders are weak references, so that they can be - * garbage collected when nobody else is using them. The ResourceBundle - * class has no reason to keep class loaders alive. + * References to a CacheKey element as a WeakReference so that it can be + * garbage collected when nobody else is using it. */ - private static class LoaderReference extends WeakReference - implements CacheKeyReference { + private static class KeyElementReference extends WeakReference + implements CacheKeyReference { @Weak - private CacheKey cacheKey; + private final CacheKey cacheKey; - LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) { + KeyElementReference(T referent, ReferenceQueue q, CacheKey key) { super(referent, q); cacheKey = key; } + @Override public CacheKey getCacheKey() { return cacheKey; } @@ -737,13 +860,14 @@ public CacheKey getCacheKey() { */ private static class BundleReference extends SoftReference implements CacheKeyReference { - private CacheKey cacheKey; + private final CacheKey cacheKey; BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) { super(referent, q); cacheKey = key; } + @Override public CacheKey getCacheKey() { return cacheKey; } @@ -755,10 +879,6 @@ public CacheKey getCacheKey() { *
    * getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader()), *
    - * except that getClassLoader() is run with the security - * privileges of ResourceBundle. - * See {@link #getBundle(String, Locale, ClassLoader) getBundle} - * for a complete description of the search and instantiation strategy. * * @param baseName the base name of the resource bundle, a fully qualified class name * @exception java.lang.NullPointerException @@ -766,13 +886,15 @@ public CacheKey getCacheKey() { * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and the default locale + * + * @see Resource Bundle Search and Loading Strategy */ @CallerSensitive public static final ResourceBundle getBundle(String baseName) { + Class caller = Reflection.getCallerClass(); return getBundleImpl(baseName, Locale.getDefault(), - getLoader(Reflection.getCallerClass()), - getDefaultControl(baseName)); + caller, getDefaultControl(caller, baseName)); } /** @@ -795,26 +917,28 @@ public static final ResourceBundle getBundle(String baseName) * @param control * the control which gives information for the resource bundle * loading process - * @return a resource bundle for the given base name and the default - * locale - * @exception NullPointerException - * if baseName or control is - * null - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @exception IllegalArgumentException - * if the given control doesn't perform properly - * (e.g., control.getCandidateLocales returns null.) - * Note that validation of control is performed as - * needed. + * @return a resource bundle for the given base name and the default locale + * @throws NullPointerException + * if baseName or control is + * null + * @throws MissingResourceException + * if no resource bundle for the specified base name can be found + * @throws IllegalArgumentException + * if the given control doesn't perform properly + * (e.g., control.getCandidateLocales returns null.) + * Note that validation of control is performed as + * needed. * @since 1.6 + * @revised 9 */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Control control) { - return getBundleImpl(baseName, Locale.getDefault(), - getLoader(Reflection.getCallerClass()), - control); + Class caller = Reflection.getCallerClass(); + Locale targetLocale = Locale.getDefault(); + // Android-removed: modules are not supported. + // checkNamedModule(caller); + return getBundleImpl(baseName, targetLocale, caller, control); } /** @@ -823,10 +947,6 @@ public static final ResourceBundle getBundle(String baseName, *
    * getBundle(baseName, locale, this.getClass().getClassLoader()), *
    - * except that getClassLoader() is run with the security - * privileges of ResourceBundle. - * See {@link #getBundle(String, Locale, ClassLoader) getBundle} - * for a complete description of the search and instantiation strategy. * * @param baseName * the base name of the resource bundle, a fully qualified class name @@ -837,16 +957,104 @@ public static final ResourceBundle getBundle(String baseName, * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and locale + * + * @see Resource Bundle Search and Loading Strategy */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale locale) { + Class caller = Reflection.getCallerClass(); return getBundleImpl(baseName, locale, - getLoader(Reflection.getCallerClass()), - getDefaultControl(baseName)); + caller, getDefaultControl(caller, baseName)); + } + + // Android-removed: modules are not supported. + /* + * Gets a resource bundle using the specified base name and the default locale + * on behalf of the specified module. This method is equivalent to calling + *
    + * getBundle(baseName, Locale.getDefault(), module) + *
    + * + * @param baseName the base name of the resource bundle, + * a fully qualified class name + * @param module the module for which the resource bundle is searched + * @throws NullPointerException + * if {@code baseName} or {@code module} is {@code null} + * @throws SecurityException + * if a security manager exists and the caller is not the specified + * module and doesn't have {@code RuntimePermission("getClassLoader")} + * @throws MissingResourceException + * if no resource bundle for the specified base name can be found in the + * specified module + * @return a resource bundle for the given base name and the default locale + * @since 9 + * @spec JPMS + * @see ResourceBundleProvider + * @see Resource Bundle Search and Loading Strategy + * @see Resource Bundles and Named Modules + * + @CallerSensitive + public static ResourceBundle getBundle(String baseName, Module module) { + return getBundleFromModule(Reflection.getCallerClass(), module, baseName, + Locale.getDefault(), + getDefaultControl(module, baseName)); } + /* + * Gets a resource bundle using the specified base name and locale + * on behalf of the specified module. + * + *

    Resource bundles in named modules may be encapsulated. When + * the resource bundle is loaded from a + * {@linkplain ResourceBundleProvider service provider}, the caller module + * must have an appropriate uses clause in its module descriptor + * to declare that the module uses of {@link ResourceBundleProvider} + * for the named resource bundle. + * Otherwise, it will load the resource bundles that are local in the + * given module as if calling {@link Module#getResourceAsStream(String)} + * or that are visible to the class loader of the given module + * as if calling {@link ClassLoader#getResourceAsStream(String)}. + * When the resource bundle is loaded from the specified module, it is + * subject to the encapsulation rules specified by + * {@link Module#getResourceAsStream Module.getResourceAsStream}. + * + *

    + * If the given {@code module} is an unnamed module, then this method is + * equivalent to calling {@link #getBundle(String, Locale, ClassLoader) + * getBundle(baseName, targetLocale, module.getClassLoader()} to load + * resource bundles that are visible to the class loader of the given + * unnamed module. Custom {@link java.util.spi.ResourceBundleControlProvider} + * implementations, if present, will only be invoked if the specified + * module is an unnamed module. + * + * @param baseName the base name of the resource bundle, + * a fully qualified class name + * @param targetLocale the locale for which a resource bundle is desired + * @param module the module for which the resource bundle is searched + * @throws NullPointerException + * if {@code baseName}, {@code targetLocale}, or {@code module} is + * {@code null} + * @throws SecurityException + * if a security manager exists and the caller is not the specified + * module and doesn't have {@code RuntimePermission("getClassLoader")} + * @throws MissingResourceException + * if no resource bundle for the specified base name and locale can + * be found in the specified {@code module} + * @return a resource bundle for the given base name and locale in the module + * @since 9 + * @spec JPMS + * @see Resource Bundle Search and Loading Strategy + * @see Resource Bundles and Named Modules + * + @CallerSensitive + public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) { + return getBundleFromModule(Reflection.getCallerClass(), module, baseName, targetLocale, + getDefaultControl(module, baseName)); + } + */ + /** * Returns a resource bundle using the specified base name, target * locale and control, and the caller's class loader. Calling this @@ -870,26 +1078,28 @@ public static final ResourceBundle getBundle(String baseName, * the control which gives information for the resource * bundle loading process * @return a resource bundle for the given base name and a - * Locale in locales - * @exception NullPointerException - * if baseName, locales or - * control is null - * @exception MissingResourceException - * if no resource bundle for the specified base name in any - * of the locales can be found. - * @exception IllegalArgumentException - * if the given control doesn't perform properly - * (e.g., control.getCandidateLocales returns null.) - * Note that validation of control is performed as - * needed. + * Locale in locales + * @throws NullPointerException + * if baseName, locales or + * control is null + * @throws MissingResourceException + * if no resource bundle for the specified base name in any + * of the locales can be found. + * @throws IllegalArgumentException + * if the given control doesn't perform properly + * (e.g., control.getCandidateLocales returns null.) + * Note that validation of control is performed as + * needed. * @since 1.6 + * @revised 9 */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale targetLocale, Control control) { - return getBundleImpl(baseName, targetLocale, - getLoader(Reflection.getCallerClass()), - control); + Class caller = Reflection.getCallerClass(); + // Android-removed: modules are not supported. + // checkNamedModule(caller); + return getBundleImpl(baseName, targetLocale, caller, control); } // Android-removed: Support for ResourceBundleControlProvider. @@ -898,14 +1108,22 @@ public static final ResourceBundle getBundle(String baseName, Locale targetLocal * Gets a resource bundle using the specified base name, locale, and class * loader. * - *

    This method behaves the same as calling - * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a - * default instance of {@link Control}. + * This is equivalent to calling: + *

    +     * getBundle(baseName, targetLocale, loader, control)
    +     * 
    + * passing a default instance of {@link Control}. + * Refer to the + * description of modifying the default + * behavior. The following describes the default behavior. + * + *

    + * Resource Bundle Search and Loading Strategy * *

    getBundle uses the base name, the specified locale, and * the default locale (obtained from {@link java.util.Locale#getDefault() * Locale.getDefault}) to generate a sequence of candidate bundle names. If the specified + * id="candidates">candidate bundle names. If the specified * locale's language, script, country, and variant are all empty strings, * then the base name is the only candidate bundle name. Otherwise, a list * of candidate locales is generated from the attribute values of the @@ -990,12 +1208,12 @@ public static final ResourceBundle getBundle(String baseName, Locale targetLocal * bundle is found, the default control's {@link Control#getFallbackLocale * getFallbackLocale} method is called, which returns the current default * locale. A new sequence of candidate locale names is generated using this - * locale and and searched again, as above. + * locale and searched again, as above. * *

    If still no result bundle is found, the base name alone is looked up. If * this still fails, a MissingResourceException is thrown. * - *

    Once a result resource bundle has been found, + *

    Once a result resource bundle has been found, * its parent chain is instantiated. If the result bundle already * has a parent (perhaps because it was returned from a cache) the chain is * complete. @@ -1020,24 +1238,24 @@ public static final ResourceBundle getBundle(String baseName, Locale targetLocal * *

    Note:The baseName argument should be a fully * qualified class name. However, for compatibility with earlier versions, - * Sun's Java SE Runtime Environments do not verify this, and so it is + * Java SE Runtime Environments do not verify this, and so it is * possible to access PropertyResourceBundles by specifying a * path name (using "/") instead of a fully qualified class name (using * "."). * - *

    + *

    * Example: *

    * The following class and property files are provided: - *

    -     *     MyResources.class
    -     *     MyResources.properties
    -     *     MyResources_fr.properties
    -     *     MyResources_fr_CH.class
    -     *     MyResources_fr_CH.properties
    -     *     MyResources_en.properties
    -     *     MyResources_es_ES.class
    -     * 
    + *
      + *
    • MyResources.class + *
    • MyResources.properties + *
    • MyResources_fr.properties + *
    • MyResources_fr_CH.class + *
    • MyResources_fr_CH.properties + *
    • MyResources_en.properties + *
    • MyResources_es_ES.class + *
    * * The contents of all files are valid (that is, public non-abstract * subclasses of ResourceBundle for the ".class" files, @@ -1047,12 +1265,18 @@ public static final ResourceBundle getBundle(String baseName, Locale targetLocal *

    Calling getBundle with the locale arguments below will * instantiate resource bundles as follows: * - * - * - * - * - * - * + *
    Locale("fr", "CH")MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class
    Locale("fr", "FR")MyResources_fr.properties, parent MyResources.class
    Locale("de", "DE")MyResources_en.properties, parent MyResources.class
    Locale("en", "US")MyResources_en.properties, parent MyResources.class
    Locale("es", "ES")MyResources_es_ES.class, parent MyResources.class
    + * + * + * + * + * + * + * + * + * + * + * *
    getBundle() locale to resource bundle mapping
    LocaleResource bundle
    Locale("fr", "CH")MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class
    Locale("fr", "FR")MyResources_fr.properties, parent MyResources.class
    Locale("de", "DE")MyResources_en.properties, parent MyResources.class
    Locale("en", "US")MyResources_en.properties, parent MyResources.class
    Locale("es", "ES")MyResources_es_ES.class, parent MyResources.class
    * *

    The file MyResources_fr_CH.properties is never used because it is @@ -1068,21 +1292,24 @@ public static final ResourceBundle getBundle(String baseName, Locale targetLocal * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @since 1.2 + * @revised 9 */ + @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale locale, ClassLoader loader) { if (loader == null) { throw new NullPointerException(); } - return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName)); + Class caller = Reflection.getCallerClass(); + return getBundleImpl(baseName, locale, caller, loader, getDefaultControl(caller, baseName)); } /** * Returns a resource bundle using the specified base name, target - * locale, class loader and control. Unlike the {@linkplain - * #getBundle(String, Locale, ClassLoader) getBundle - * factory methods with no control argument}, the given + * locale, class loader and control. Unlike the {@link + * #getBundle(String, Locale, ClassLoader) getBundle} + * factory methods with no {@code control} argument, the given * control specifies how to locate and instantiate resource * bundles. Conceptually, the bundle loading process with the given * control is performed in the following steps. @@ -1125,44 +1352,45 @@ public static ResourceBundle getBundle(String baseName, Locale locale, * sequence of locale-format combinations to be used to call * control.newBundle. * - * - * + *
    + * + * * - * - * + * + * + * * + * + * * - * - * + * + * + * * * - * - * + * + * + * * * - * - * + * + * + * * * - * - * + * + * + * * * - * - * + * + * + * * * - * - * + * + * + * * * *
    locale-format combinations for newBundle
    Locale
    - *
    format
    - *
    IndexLocaleformat
    Locale("de", "DE")
    - *
    java.class
    - *
    1Locale("de", "DE")java.class
    Locale("de", "DE")java.properties
    - *
    2Locale("de", "DE")java.properties
    Locale("de")java.class3Locale("de")java.class
    Locale("de")java.properties4Locale("de")java.properties
    Locale("")
    - *
    java.class5Locale("")java.class
    Locale("")java.properties6Locale("")java.properties
    @@ -1274,25 +1502,30 @@ public static ResourceBundle getBundle(String baseName, Locale locale, * the control which gives information for the resource * bundle loading process * @return a resource bundle for the given base name and locale - * @exception NullPointerException - * if baseName, targetLocale, - * loader, or control is - * null - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @exception IllegalArgumentException - * if the given control doesn't perform properly - * (e.g., control.getCandidateLocales returns null.) - * Note that validation of control is performed as - * needed. + * @throws NullPointerException + * if baseName, targetLocale, + * loader, or control is + * null + * @throws MissingResourceException + * if no resource bundle for the specified base name can be found + * @throws IllegalArgumentException + * if the given control doesn't perform properly + * (e.g., control.getCandidateLocales returns null.) + * Note that validation of control is performed as + * needed. * @since 1.6 + * @revised 9 */ + @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale targetLocale, ClassLoader loader, Control control) { if (loader == null || control == null) { throw new NullPointerException(); } - return getBundleImpl(baseName, targetLocale, loader, control); + Class caller = Reflection.getCallerClass(); + // Android-removed: modules are not supported. + // checkNamedModule(caller); + return getBundleImpl(baseName, targetLocale, caller, loader, control); } private static Control getDefaultControl(String baseName) { @@ -1310,16 +1543,138 @@ private static Control getDefaultControl(String baseName) { return Control.INSTANCE; } + private static Control getDefaultControl(Class caller, String baseName) { + // Android-removed: modules are not supported. + // return getDefaultControl(caller.getModule(), baseName); + return getDefaultControl(baseName); + } + + // Android-removed: modules are not supported + /* + private static Control getDefaultControl(Module targetModule, String baseName) { + return targetModule.isNamed() ? + Control.INSTANCE : + ResourceBundleControlProviderHolder.getControl(baseName); + } + */ + + // Android-removed: support for ResourceBundleControlProvider + /* + private static class ResourceBundleControlProviderHolder { + private static final PrivilegedAction> pa = + () -> { + return Collections.unmodifiableList( + ServiceLoader.load(ResourceBundleControlProvider.class, + ClassLoader.getSystemClassLoader()).stream() + .map(ServiceLoader.Provider::get) + .collect(Collectors.toList())); + }; + + private static final List CONTROL_PROVIDERS = + AccessController.doPrivileged(pa); + + private static Control getControl(String baseName) { + return CONTROL_PROVIDERS.isEmpty() ? + Control.INSTANCE : + CONTROL_PROVIDERS.stream() + .flatMap(provider -> Stream.ofNullable(provider.getControl(baseName))) + .findFirst() + .orElse(Control.INSTANCE); + } + } + */ + + // Android-removed: modules are not supported + /* + private static void checkNamedModule(Class caller) { + if (caller.getModule().isNamed()) { + throw new UnsupportedOperationException( + "ResourceBundle.Control not supported in named modules"); + } + } + */ + + private static ResourceBundle getBundleImpl(String baseName, + Locale locale, + Class caller, + Control control) { + return getBundleImpl(baseName, locale, caller, caller.getClassLoader(), control); + } + + /** + * This method will find resource bundles using the legacy mechanism + * if the caller is unnamed module or the given class loader is + * not the class loader of the caller module getting the resource + * bundle, i.e. find the class that is visible to the class loader + * and properties from unnamed module. + * + * The module-aware resource bundle lookup mechanism will load + * the service providers using the service loader mechanism + * as well as properties local in the caller module. + */ + private static ResourceBundle getBundleImpl(String baseName, + Locale locale, + Class caller, + ClassLoader loader, + Control control) { + if (caller == null) { + throw new InternalError("null caller"); + } + + // Android-removed: modules are not supported. + /* + Module callerModule = caller.getModule(); + + // get resource bundles for a named module only if loader is the module's class loader + if (callerModule.isNamed() && loader == getLoader(callerModule)) { + return getBundleImpl(callerModule, callerModule, baseName, locale, control); + } + + // find resource bundles from unnamed module of given class loader + // Java agent can add to the bootclasspath e.g. via + // java.lang.instrument.Instrumentation and load classes in unnamed module. + // It may call RB::getBundle that will end up here with loader == null. + Module unnamedModule = loader != null + ? loader.getUnnamedModule() + : BootLoader.getUnnamedModule(); + */ + // return getBundleImpl(callerModule, unnamedModule, baseName, locale, control); + return getBundleImpl(baseName, locale, loader, control); + } + + // Android-removed: modules are not supported. + /* + private static ResourceBundle getBundleFromModule(Class caller, + Module module, + String baseName, + Locale locale, + Control control) { + Objects.requireNonNull(module); + Module callerModule = caller.getModule(); + if (callerModule != module) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(GET_CLASSLOADER_PERMISSION); + } + } + return getBundleImpl(callerModule, module, baseName, locale, control); + } + */ + + // Android-changed: modules are not supported. + // private static ResourceBundle getBundleImpl(Module callerModule, + // Module module, private static ResourceBundle getBundleImpl(String baseName, Locale locale, ClassLoader loader, Control control) { if (locale == null || control == null) { throw new NullPointerException(); } - // We create a CacheKey here for use by this call. The base - // name and loader will never change during the bundle loading + // We create a CacheKey here for use by this call. The base name + // and modules will never change during the bundle loading // process. We have to make sure that the locale is set before // using it as a cache key. + // CacheKey cacheKey = new CacheKey(baseName, locale, module, callerModule); CacheKey cacheKey = new CacheKey(baseName, locale, loader); ResourceBundle bundle = null; @@ -1356,7 +1711,10 @@ private static ResourceBundle getBundleImpl(String baseName, Locale locale, if (!isKnownControl && !checkList(candidateLocales)) { throw new IllegalArgumentException("Invalid Control: getCandidateLocales"); } - + /* + bundle = findBundle(callerModule, module, cacheKey, + candidateLocales, formats, 0, control, baseBundle); + */ bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle); // If the loaded bundle is the base bundle and exactly for the @@ -1388,6 +1746,11 @@ private static ResourceBundle getBundleImpl(String baseName, Locale locale, bundle = baseBundle; } + // keep callerModule and module reachable for as long as we are operating + // with WeakReference(s) to them (in CacheKey)... + // Reference.reachabilityFence(callerModule); + // Reference.reachabilityFence(module); + return bundle; } @@ -1406,6 +1769,8 @@ private static boolean checkList(List a) { return valid; } + // private static ResourceBundle findBundle(Module callerModule, + // Module module, private static ResourceBundle findBundle(CacheKey cacheKey, List candidateLocales, List formats, @@ -1415,6 +1780,11 @@ private static ResourceBundle findBundle(CacheKey cacheKey, Locale targetLocale = candidateLocales.get(index); ResourceBundle parent = null; if (index != candidateLocales.size() - 1) { + /* + parent = findBundle(callerModule, module, cacheKey, + candidateLocales, formats, index + 1, + control, baseBundle); + */ parent = findBundle(cacheKey, candidateLocales, formats, index + 1, control, baseBundle); } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) { @@ -1422,7 +1792,7 @@ private static ResourceBundle findBundle(CacheKey cacheKey, } // Before we do the real loading work, see whether we need to - // do some housekeeping: If references to class loaders or + // do some housekeeping: If references to modules or // resource bundles have been nulled out, remove all related // information from the cache. Object ref; @@ -1451,6 +1821,7 @@ private static ResourceBundle findBundle(CacheKey cacheKey, // Otherwise, remove the cached one since we can't keep // the same bundles having different parents. BundleReference bundleRef = cacheList.get(cacheKey); + // Android-changed: Use refersTo(). if (bundleRef != null && bundleRef.get() == bundle) { cacheList.remove(cacheKey, bundleRef); } @@ -1483,6 +1854,187 @@ private static ResourceBundle findBundle(CacheKey cacheKey, return parent; } + private static final String UNKNOWN_FORMAT = ""; + + + // Android-removed: modules are not supported. + /* + * Loads a ResourceBundle in named modules + * + private static ResourceBundle loadBundle(CacheKey cacheKey, + List formats, + Control control, + Module module, + Module callerModule) { + String baseName = cacheKey.getName(); + Locale targetLocale = cacheKey.getLocale(); + + ResourceBundle bundle = null; + if (cacheKey.hasProviders()) { + if (callerModule == module) { + bundle = loadBundleFromProviders(baseName, + targetLocale, + cacheKey.getProviders(), + cacheKey); + } else { + // load from provider if the caller module has access to the + // service type and also declares `uses` + ClassLoader loader = getLoader(module); + Class svc = + getResourceBundleProviderType(baseName, loader); + if (svc != null + && Reflection.verifyModuleAccess(callerModule, svc) + && callerModule.canUse(svc)) { + bundle = loadBundleFromProviders(baseName, + targetLocale, + cacheKey.getProviders(), + cacheKey); + } + } + + if (bundle != null) { + cacheKey.setFormat(UNKNOWN_FORMAT); + } + } + + // If none of providers returned a bundle and the caller has no provider, + // look up module-local bundles or from the class path + if (bundle == null && !cacheKey.callerHasProvider()) { + for (String format : formats) { + try { + switch (format) { + case "java.class": + bundle = ResourceBundleProviderHelper + .loadResourceBundle(callerModule, module, baseName, targetLocale); + + break; + case "java.properties": + bundle = ResourceBundleProviderHelper + .loadPropertyResourceBundle(callerModule, module, baseName, targetLocale); + break; + default: + throw new InternalError("unexpected format: " + format); + } + + if (bundle != null) { + cacheKey.setFormat(format); + break; + } + } catch (LinkageError|Exception e) { + cacheKey.setCause(e); + } + } + } + return bundle; + } + + /* + * Returns a ServiceLoader that will find providers that are bound to + * a given named module. + * + private static ServiceLoader getServiceLoader(Module module, + String baseName) + { + if (!module.isNamed()) { + return null; + } + + ClassLoader loader = getLoader(module); + Class service = + getResourceBundleProviderType(baseName, loader); + if (service != null && Reflection.verifyModuleAccess(module, service)) { + try { + // locate providers that are visible to the class loader + // ServiceConfigurationError will be thrown if the module + // does not declare `uses` the service type + return ServiceLoader.load(service, loader, module); + } catch (ServiceConfigurationError e) { + // "uses" not declared + return null; + } + } + return null; + } + + /** + * Returns the service type of the given baseName that is visible + * to the given class loader + * + private static Class + getResourceBundleProviderType(String baseName, ClassLoader loader) + { + // Look up + ".spi." + "Provider" + int i = baseName.lastIndexOf('.'); + if (i <= 0) { + return null; + } + + String name = baseName.substring(i+1, baseName.length()) + "Provider"; + String providerName = baseName.substring(0, i) + ".spi." + name; + + // Use the class loader of the getBundle caller so that the caller's + // visibility of the provider type is checked. + return AccessController.doPrivileged( + new PrivilegedAction<>() { + @Override + public Class run() { + try { + Class c = Class.forName(providerName, false, loader); + if (ResourceBundleProvider.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class s = (Class) c; + return s; + } + } catch (ClassNotFoundException e) {} + return null; + } + }); + } + + /** + * Loads ResourceBundle from service providers. + * + private static ResourceBundle loadBundleFromProviders(String baseName, + Locale locale, + ServiceLoader providers, + CacheKey cacheKey) + { + if (providers == null) return null; + + return AccessController.doPrivileged( + new PrivilegedAction<>() { + public ResourceBundle run() { + for (Iterator itr = providers.iterator(); itr.hasNext(); ) { + try { + ResourceBundleProvider provider = itr.next(); + if (cacheKey != null && cacheKey.callerHasProvider == null + && cacheKey.getModule() == provider.getClass().getModule()) { + cacheKey.callerHasProvider = Boolean.TRUE; + } + ResourceBundle bundle = provider.getBundle(baseName, locale); + trace("provider %s %s locale: %s bundle: %s%n", provider, baseName, locale, bundle); + if (bundle != null) { + return bundle; + } + } catch (ServiceConfigurationError | SecurityException e) { + if (cacheKey != null) { + cacheKey.setCause(e); + } + } + } + if (cacheKey != null && cacheKey.callerHasProvider == null) { + cacheKey.callerHasProvider = Boolean.FALSE; + } + return null; + } + }); + + } + */ + + /* + * Legacy mechanism to load resource bundles + */ private static ResourceBundle loadBundle(CacheKey cacheKey, List formats, Control control, @@ -1492,20 +2044,28 @@ private static ResourceBundle loadBundle(CacheKey cacheKey, // specified by the getFormats() value. Locale targetLocale = cacheKey.getLocale(); + // Android-removed: modules are not supported + /* + Module module = cacheKey.getModule(); + if (module == null) { + // should not happen + throw new InternalError( + "Module for cache key: " + cacheKey + " has been GCed."); + } + ClassLoader loader = getLoaderForControl(module); + */ + ResourceBundle bundle = null; - int size = formats.size(); - for (int i = 0; i < size; i++) { - String format = formats.get(i); + for (String format : formats) { try { + // ResourceBundle.Control.newBundle may be overridden bundle = control.newBundle(cacheKey.getName(), targetLocale, format, cacheKey.getLoader(), reload); - } catch (LinkageError error) { + } catch (LinkageError | Exception error) { // We need to handle the LinkageError case due to // inconsistent case-sensitivity in ClassLoader. // See 6572242 for details. cacheKey.setCause(error); - } catch (Exception cause) { - cacheKey.setCause(cause); } if (bundle != null) { // Set the format in the cache key so that it can be @@ -1642,12 +2202,19 @@ private static ResourceBundle findBundleInCache(CacheKey cacheKey, if (!bundle.expired && expirationTime >= 0 && expirationTime <= System.currentTimeMillis()) { try { + // Android-changed: modules are not supported. + /* + Module module = cacheKey.getModule(); + bundle.expired = + module == null || // already GCed + */ bundle.expired = control.needsReload(key.getName(), - key.getLocale(), - key.getFormat(), - key.getLoader(), - bundle, - key.loadTime); + key.getLocale(), + key.getFormat(), + // getLoaderForControl(module), + key.getLoader(), + bundle, + key.loadTime); } catch (Exception e) { cacheKey.setCause(e); } @@ -1738,16 +2305,24 @@ private static void setExpirationTime(CacheKey cacheKey, Control control) { * using the caller's class loader. * * @since 1.6 + * @revised 9 * @see ResourceBundle.Control#getTimeToLive(String,Locale) */ @CallerSensitive public static final void clearCache() { + // Android-changed: modules are not supported. + /* + Class caller = Reflection.getCallerClass(); + cacheList.keySet().removeIf( + key -> key.getCallerModule() == caller.getModule() + ); + */ clearCache(getLoader(Reflection.getCallerClass())); } /** * Removes all resource bundles from the cache that have been loaded - * using the given class loader. + * by the given class loader. * * @param loader the class loader * @exception NullPointerException if loader is null @@ -1755,15 +2330,18 @@ public static final void clearCache() { * @see ResourceBundle.Control#getTimeToLive(String,Locale) */ public static final void clearCache(ClassLoader loader) { - if (loader == null) { - throw new NullPointerException(); - } - Set set = cacheList.keySet(); - for (CacheKey key : set) { - if (key.getLoader() == loader) { - set.remove(key); + Objects.requireNonNull(loader); + // Android-changed: modules are no supported. + /* + cacheList.keySet().removeIf( + key -> { + Module m; + return (m = key.getModule()) != null && + getLoader(m) == loader; } - } + ); + */ + cacheList.keySet().removeIf(key -> key.getLoader() == loader); } /** @@ -2010,39 +2588,35 @@ protected Set handleKeySet() { * * * @since 1.6 + * @revised 9 */ public static class Control { /** * The default format List, which contains the strings * "java.class" and "java.properties", in - * this order. This List is {@linkplain - * Collections#unmodifiableList(List) unmodifiable}. + * this order. This List is unmodifiable. * * @see #getFormats(String) */ public static final List FORMAT_DEFAULT - = Collections.unmodifiableList(Arrays.asList("java.class", - "java.properties")); + = List.of("java.class", "java.properties"); /** * The class-only format List containing - * "java.class". This List is {@linkplain - * Collections#unmodifiableList(List) unmodifiable}. + * "java.class". This List is unmodifiable. * * @see #getFormats(String) */ - public static final List FORMAT_CLASS - = Collections.unmodifiableList(Arrays.asList("java.class")); + public static final List FORMAT_CLASS = List.of("java.class"); /** * The properties-only format List containing - * "java.properties". This List is - * {@linkplain Collections#unmodifiableList(List) unmodifiable}. + * "java.properties". This List is unmodifiable. * * @see #getFormats(String) */ public static final List FORMAT_PROPERTIES - = Collections.unmodifiableList(Arrays.asList("java.properties")); + = List.of("java.properties"); /** * The time-to-live constant for not caching loaded resource bundle @@ -2247,7 +2821,7 @@ public List getFormats(String baseName) { * of multiple subtags separated by underscore, generate candidate * Locales by omitting the variant subtags one by one, then * insert them after every occurrence of Locales with the - * full variant value in the original list. For example, if the + * full variant value in the original list. For example, if * the variant consists of two subtags V1 and V2: * *

      @@ -2392,7 +2966,7 @@ protected List createObject(BaseLocale base) { List bokmalList = new LinkedList<>(); for (Locale l : tmpList) { bokmalList.add(l); - if (l.getLanguage().length() == 0) { + if (l.getLanguage().isEmpty()) { break; } bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(), @@ -2410,7 +2984,7 @@ protected List createObject(BaseLocale base) { } // Special handling for Chinese else if (language.equals("zh")) { - if (script.length() == 0 && region.length() > 0) { + if (script.isEmpty() && !region.isEmpty()) { // Supply script for users who want to use zh_Hans/zh_Hant // as bundle names (recommended for Java7+) switch (region) { @@ -2424,17 +2998,6 @@ else if (language.equals("zh")) { script = "Hans"; break; } - } else if (script.length() > 0 && region.length() == 0) { - // Supply region(country) for users who still package Chinese - // bundles using old convension. - switch (script) { - case "Hans": - region = "CN"; - break; - case "Hant": - region = "TW"; - break; - } } } @@ -2444,7 +3007,7 @@ else if (language.equals("zh")) { private static List getDefaultList(String language, String script, String region, String variant) { List variants = null; - if (variant.length() > 0) { + if (!variant.isEmpty()) { variants = new LinkedList<>(); int idx = variant.length(); while (idx != -1) { @@ -2460,11 +3023,26 @@ private static List getDefaultList(String language, String script, Strin list.add(Locale.getInstance(language, script, region, v, null)); } } - if (region.length() > 0) { + if (!region.isEmpty()) { list.add(Locale.getInstance(language, script, region, "", null)); } - if (script.length() > 0) { + if (!script.isEmpty()) { list.add(Locale.getInstance(language, script, "", "", null)); + // Special handling for Chinese + if (language.equals("zh")) { + if (region.isEmpty()) { + // Supply region(country) for users who still package Chinese + // bundles using old convension. + switch (script) { + case "Hans": + region = "CN"; + break; + case "Hant": + region = "TW"; + break; + } + } + } // With script, after truncating variant, region and script, // start over without script. @@ -2473,11 +3051,11 @@ private static List getDefaultList(String language, String script, Strin list.add(Locale.getInstance(language, "", region, v, null)); } } - if (region.length() > 0) { + if (!region.isEmpty()) { list.add(Locale.getInstance(language, "", region, "", null)); } } - if (language.length() > 0) { + if (!language.isEmpty()) { list.add(Locale.getInstance(language, "", "", "", null)); } // Add root locale at the end @@ -2555,12 +3133,15 @@ public Locale getFallbackLocale(String baseName, Locale locale) { * locale)}. * *
    • If format is "java.class", the - * {@link Class} specified by the bundle name is loaded by calling - * {@link ClassLoader#loadClass(String)}. Then, a - * ResourceBundle is instantiated by calling {@link - * Class#newInstance()}. Note that the reload flag is - * ignored for loading class-based resource bundles in this default - * implementation.
    • + * {@link Class} specified by the bundle name is loaded with the + * given class loader. If the {@code Class} is found and accessible + * then the ResourceBundle is instantiated. The + * resource bundle is accessible if the package of the bundle class file + * is open unconditionally; otherwise, {@code IllegalAccessException} + * will be thrown. + * Note that the reload flag is ignored for loading + * class-based resource bundles in this default implementation. + * * *
    • If format is "java.properties", * {@link #toResourceName(String, String) toResourceName(bundlename, @@ -2626,6 +3207,7 @@ public Locale getFallbackLocale(String baseName, Locale locale) { * @exception IOException * if an error occurred when reading resources using * any I/O operations + * @revised 9 */ public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) @@ -2759,6 +3341,7 @@ public long getTimeToLive(String baseName, Locale locale) { * the Calendar * Epoch. * + *

      * The calling ResourceBundle.getBundle factory method * calls this method on the ResourceBundle.Control * instance used for its current invocation, not on the instance @@ -2923,15 +3506,15 @@ public String toBundleName(String baseName, Locale locale) { } /** - * Converts the given bundleName to the form required + * Converts the given {@code bundleName} to the form required * by the {@link ClassLoader#getResource ClassLoader.getResource} - * method by replacing all occurrences of '.' in - * bundleName with '/' and appending a - * '.' and the given file suffix. For - * example, if bundleName is - * "foo.bar.MyResources_ja_JP" and suffix - * is "properties", then - * "foo/bar/MyResources_ja_JP.properties" is returned. + * method by replacing all occurrences of {@code '.'} in + * {@code bundleName} with {@code '/'} and appending a + * {@code '.'} and the given file {@code suffix}. For + * example, if {@code bundleName} is + * {@code "foo.bar.MyResources_ja_JP"} and {@code suffix} + * is {@code "properties"}, then + * {@code "foo/bar/MyResources_ja_JP.properties"} is returned. * * @param bundleName * the bundle name @@ -2939,8 +3522,8 @@ public String toBundleName(String baseName, Locale locale) { * the file type suffix * @return the converted resource name * @exception NullPointerException - * if bundleName or suffix - * is null + * if {@code bundleName} or {@code suffix} + * is {@code null} */ public final String toResourceName(String bundleName, String suffix) { StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length()); @@ -2958,6 +3541,14 @@ private String toResourceName0(String bundleName, String suffix) { } } + @SuppressWarnings("unchecked") + private static void uncheckedThrow(Throwable t) throws T { + if (t != null) + throw (T)t; + else + throw new Error("Unknown Exception"); + } + private static class SingleFormatControl extends Control { private static final Control PROPERTIES_ONLY = new SingleFormatControl(FORMAT_PROPERTIES); @@ -3000,4 +3591,177 @@ public Locale getFallbackLocale(String baseName, Locale locale) { return null; } } + + // Android-removed: modules are not supported. + /* + private static class ResourceBundleProviderHelper { + /** + * Returns a new ResourceBundle instance of the given bundleClass + * + static ResourceBundle newResourceBundle(Class bundleClass) { + try { + @SuppressWarnings("unchecked") + Constructor ctor = + bundleClass.getConstructor(); + if (!Modifier.isPublic(ctor.getModifiers())) { + return null; + } + // java.base may not be able to read the bundleClass's module. + PrivilegedAction pa = () -> { ctor.setAccessible(true); return null;}; + AccessController.doPrivileged(pa); + try { + return ctor.newInstance((Object[]) null); + } catch (InvocationTargetException e) { + uncheckedThrow(e); + } catch (InstantiationException | IllegalAccessException e) { + throw new InternalError(e); + } + } catch (NoSuchMethodException e) { + throw new InternalError(e); + } + return null; + } + + /** + * Loads a {@code ResourceBundle} of the given {@code bundleName} local to + * the given {@code module}. If not found, search the bundle class + * that is visible from the module's class loader. + * + * The caller module is used for access check only. + * + static ResourceBundle loadResourceBundle(Module callerModule, + Module module, + String baseName, + Locale locale) + { + String bundleName = Control.INSTANCE.toBundleName(baseName, locale); + try { + PrivilegedAction> pa = () -> Class.forName(module, bundleName); + Class c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION); + trace("local in %s %s caller %s: %s%n", module, bundleName, callerModule, c); + + if (c == null) { + // if not found from the given module, locate resource bundle + // that is visible to the module's class loader + ClassLoader loader = getLoader(module); + if (loader != null) { + c = Class.forName(bundleName, false, loader); + } else { + c = BootLoader.loadClassOrNull(bundleName); + } + trace("loader for %s %s caller %s: %s%n", module, bundleName, callerModule, c); + } + + if (c != null && ResourceBundle.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class bundleClass = (Class) c; + Module m = bundleClass.getModule(); + if (!isAccessible(callerModule, m, bundleClass.getPackageName())) { + trace(" %s does not have access to %s/%s%n", callerModule, + m.getName(), bundleClass.getPackageName()); + return null; + } + + return newResourceBundle(bundleClass); + } + } catch (ClassNotFoundException e) {} + return null; + } + + /** + * Tests if resources of the given package name from the given module are + * open to the caller module. + * + static boolean isAccessible(Module callerModule, Module module, String pn) { + if (!module.isNamed() || callerModule == module) + return true; + + return module.isOpen(pn, callerModule); + } + + /** + * Loads properties of the given {@code bundleName} local in the given + * {@code module}. If the .properties is not found or not open + * to the caller module to access, it will find the resource that + * is visible to the module's class loader. + * + * The caller module is used for access check only. + * + static ResourceBundle loadPropertyResourceBundle(Module callerModule, + Module module, + String baseName, + Locale locale) + throws IOException + { + String bundleName = Control.INSTANCE.toBundleName(baseName, locale); + + PrivilegedAction pa = () -> { + try { + String resourceName = Control.INSTANCE + .toResourceName0(bundleName, "properties"); + if (resourceName == null) { + return null; + } + trace("local in %s %s caller %s%n", module, resourceName, callerModule); + + // if the package is in the given module but not opened + // locate it from the given module first. + String pn = toPackageName(bundleName); + trace(" %s/%s is accessible to %s : %s%n", + module.getName(), pn, callerModule, + isAccessible(callerModule, module, pn)); + if (isAccessible(callerModule, module, pn)) { + InputStream in = module.getResourceAsStream(resourceName); + if (in != null) { + return in; + } + } + + ClassLoader loader = module.getClassLoader(); + trace("loader for %s %s caller %s%n", module, resourceName, callerModule); + + try { + if (loader != null) { + return loader.getResourceAsStream(resourceName); + } else { + URL url = BootLoader.findResource(resourceName); + if (url != null) { + return url.openStream(); + } + } + } catch (Exception e) {} + return null; + + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + + try (InputStream stream = AccessController.doPrivileged(pa)) { + if (stream != null) { + return new PropertyResourceBundle(stream); + } else { + return null; + } + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + private static String toPackageName(String bundleName) { + int i = bundleName.lastIndexOf('.'); + return i != -1 ? bundleName.substring(0, i) : ""; + } + } + */ + + /* J2ObjC removed + private static final boolean TRACE_ON = Boolean.valueOf( + GetPropertyAction.privilegedGetProperty("resource.bundle.debug", "false")); + + private static void trace(String format, Object... params) { + if (TRACE_ON) + System.out.format(format, params); + } + */ } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Scanner.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Scanner.java index 46aaf0915e..5aada6138a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Scanner.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Scanner.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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 @@ -26,37 +26,37 @@ package java.util; -import java.nio.file.Path; -import java.nio.file.Files; -import java.util.regex.*; import java.io.*; import java.math.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; +import java.nio.file.Path; +import java.nio.file.Files; import java.text.*; -import java.util.Locale; - -import sun.misc.LRUCache; +import java.util.function.Consumer; +import java.util.regex.*; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * A simple text scanner which can parse primitive types and strings using * regular expressions. * - *

      A Scanner breaks its input into tokens using a + *

      A {@code Scanner} breaks its input into tokens using a * delimiter pattern, which by default matches whitespace. The resulting * tokens may then be converted into values of different types using the - * various next methods. + * various {@code next} methods. * *

      For example, this code allows a user to read a number from - * System.in: + * {@code System.in}: *

      {@code
        *     Scanner sc = new Scanner(System.in);
        *     int i = sc.nextInt();
        * }
      * - *

      As another example, this code allows long types to be - * assigned from entries in a file myNumbers: + *

      As another example, this code allows {@code long} types to be + * assigned from entries in a file {@code myNumbers}: *

      {@code
        *      Scanner sc = new Scanner(new File("myNumbers"));
        *      while (sc.hasNextLong()) {
      @@ -96,23 +96,26 @@
        *     s.close();
        * }
      * - *

      The default whitespace delimiter used - * by a scanner is as recognized by {@link java.lang.Character}.{@link - * java.lang.Character#isWhitespace(char) isWhitespace}. The {@link #reset} + *

      The default whitespace delimiter used + * by a scanner is as recognized by {@link Character#isWhitespace(char) + * Character.isWhitespace()}. The {@link #reset reset()} * method will reset the value of the scanner's delimiter to the default * whitespace delimiter regardless of whether it was previously changed. * *

      A scanning operation may block waiting for input. * *

      The {@link #next} and {@link #hasNext} methods and their - * primitive-type companion methods (such as {@link #nextInt} and + * companion methods (such as {@link #nextInt} and * {@link #hasNextInt}) first skip any input that matches the delimiter - * pattern, and then attempt to return the next token. Both hasNext - * and next methods may block waiting for further input. Whether a - * hasNext method blocks has no connection to whether or not its - * associated next method will block. + * pattern, and then attempt to return the next token. Both {@code hasNext()} + * and {@code next()} methods may block waiting for further input. Whether a + * {@code hasNext()} method blocks has no connection to whether or not its + * associated {@code next()} method will block. The {@link #tokens} method + * may also block waiting for input. * - *

      The {@link #findInLine}, {@link #findWithinHorizon}, and {@link #skip} + *

      The {@link #findInLine findInLine()}, + * {@link #findWithinHorizon findWithinHorizon()}, + * {@link #skip skip()}, and {@link #findAll findAll()} * methods operate independently of the delimiter pattern. These methods will * attempt to match the specified pattern with no regard to delimiters in the * input and thus can be used in special circumstances where delimiters are @@ -123,95 +126,95 @@ * retrieved or skipped via some other method. * *

      Depending upon the type of delimiting pattern, empty tokens may be - * returned. For example, the pattern "\\s+" will return no empty + * returned. For example, the pattern {@code "\\s+"} will return no empty * tokens since it matches multiple instances of the delimiter. The delimiting - * pattern "\\s" could return empty tokens since it only passes one + * pattern {@code "\\s"} could return empty tokens since it only passes one * space at a time. * *

      A scanner can read text from any object which implements the {@link * java.lang.Readable} interface. If an invocation of the underlying - * readable's {@link java.lang.Readable#read} method throws an {@link + * readable's {@link java.lang.Readable#read read()} method throws an {@link * java.io.IOException} then the scanner assumes that the end of the input - * has been reached. The most recent IOException thrown by the + * has been reached. The most recent {@code IOException} thrown by the * underlying readable can be retrieved via the {@link #ioException} method. * - *

      When a Scanner is closed, it will close its input source + *

      When a {@code Scanner} is closed, it will close its input source * if the source implements the {@link java.io.Closeable} interface. * - *

      A Scanner is not safe for multithreaded use without + *

      A {@code Scanner} is not safe for multithreaded use without * external synchronization. * - *

      Unless otherwise mentioned, passing a null parameter into - * any method of a Scanner will cause a - * NullPointerException to be thrown. + *

      Unless otherwise mentioned, passing a {@code null} parameter into + * any method of a {@code Scanner} will cause a + * {@code NullPointerException} to be thrown. * *

      A scanner will default to interpreting numbers as decimal unless a * different radix has been set by using the {@link #useRadix} method. The * {@link #reset} method will reset the value of the scanner's radix to - * 10 regardless of whether it was previously changed. + * {@code 10} regardless of whether it was previously changed. * - *

      Localized numbers

      + *

      Localized numbers

      * *

      An instance of this class is capable of scanning numbers in the standard * formats as well as in the formats of the scanner's locale. A scanner's - * initial locale is the value returned by the {@link + * initial locale is the value returned by the {@link * java.util.Locale#getDefault(Locale.Category) * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link - * #useLocale} method. The {@link #reset} method will reset the value of the + * #useLocale useLocale()} method. The {@link #reset} method will reset the value of the * scanner's locale to the initial locale regardless of whether it was * previously changed. * *

      The localized formats are defined in terms of the following parameters, * which for a particular locale are taken from that locale's {@link - * java.text.DecimalFormat DecimalFormat} object, df, and its and + * java.text.DecimalFormat DecimalFormat} object, {@code df}, and its and * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object, - * dfs. + * {@code dfs}. * *

      *
      LocalGroupSeparator   *
      The character used to separate thousands groups, - * i.e., dfs.{@link + * i.e., {@code dfs.}{@link * java.text.DecimalFormatSymbols#getGroupingSeparator * getGroupingSeparator()} *
      LocalDecimalSeparator   *
      The character used for the decimal point, - * i.e., dfs.{@link + * i.e., {@code dfs.}{@link * java.text.DecimalFormatSymbols#getDecimalSeparator * getDecimalSeparator()} *
      LocalPositivePrefix   *
      The string that appears before a positive number (may - * be empty), i.e., df.{@link + * be empty), i.e., {@code df.}{@link * java.text.DecimalFormat#getPositivePrefix * getPositivePrefix()} *
      LocalPositiveSuffix   *
      The string that appears after a positive number (may be - * empty), i.e., df.{@link + * empty), i.e., {@code df.}{@link * java.text.DecimalFormat#getPositiveSuffix * getPositiveSuffix()} *
      LocalNegativePrefix   *
      The string that appears before a negative number (may - * be empty), i.e., df.{@link + * be empty), i.e., {@code df.}{@link * java.text.DecimalFormat#getNegativePrefix * getNegativePrefix()} *
      LocalNegativeSuffix   *
      The string that appears after a negative number (may be - * empty), i.e., df.{@link + * empty), i.e., {@code df.}{@link * java.text.DecimalFormat#getNegativeSuffix * getNegativeSuffix()} *
      LocalNaN   *
      The string that represents not-a-number for * floating-point values, - * i.e., dfs.{@link + * i.e., {@code dfs.}{@link * java.text.DecimalFormatSymbols#getNaN * getNaN()} *
      LocalInfinity   *
      The string that represents infinity for floating-point - * values, i.e., dfs.{@link + * values, i.e., {@code dfs.}{@link * java.text.DecimalFormatSymbols#getInfinity * getInfinity()} *
      * - *

      Number syntax

      + *

      Number syntax

      * *

      The strings that can be parsed as numbers by an instance of this class * are specified in terms of the following regular-expression grammar, where @@ -220,82 +223,82 @@ *

      *
      NonAsciiDigit: *
      A non-ASCII character c for which - * {@link java.lang.Character#isDigit Character.isDigit}(c) + * {@link java.lang.Character#isDigit Character.isDigit}{@code (c)} * returns true * *
      Non0Digit: - *
      [1-Rmax] | NonASCIIDigit + *
      {@code [1-}Rmax{@code ] | }NonASCIIDigit * *
      Digit: - *
      [0-Rmax] | NonASCIIDigit + *
      {@code [0-}Rmax{@code ] | }NonASCIIDigit * *
      GroupedNumeral: - *
      Non0Digit - * Digit? - * Digit? - *
          LocalGroupSeparator + *
      Non0Digit + * Digit{@code ? + * }Digit{@code ?} + *
          LocalGroupSeparator * Digit * Digit - * Digit )+ ) + * Digit{@code )+ )} * *
      Numeral: - *
      ( ( Digit+ ) - * | GroupedNumeral ) + *
      {@code ( ( }Digit{@code + ) + * | }GroupedNumeral{@code )} * - *
      Integer: - *
      ( [-+]? ( Numeral - * ) ) - *
      | LocalPositivePrefix Numeral + *
      Integer: + *
      {@code ( [-+]? ( }Numeral{@code + * ) )} + *
      {@code | }LocalPositivePrefix Numeral * LocalPositiveSuffix - *
      | LocalNegativePrefix Numeral + *
      {@code | }LocalNegativePrefix Numeral * LocalNegativeSuffix * *
      DecimalNumeral: *
      Numeral - *
      | Numeral + *
      {@code | }Numeral * LocalDecimalSeparator - * Digit* - *
      | LocalDecimalSeparator - * Digit+ + * Digit{@code *} + *
      {@code | }LocalDecimalSeparator + * Digit{@code +} * *
      Exponent: - *
      ( [eE] [+-]? Digit+ ) + *
      {@code ( [eE] [+-]? }Digit{@code + )} * - *
      Decimal: - *
      ( [-+]? DecimalNumeral - * Exponent? ) - *
      | LocalPositivePrefix + *
      Decimal: + *
      {@code ( [-+]? }DecimalNumeral + * Exponent{@code ? )} + *
      {@code | }LocalPositivePrefix * DecimalNumeral * LocalPositiveSuffix - * Exponent? - *
      | LocalNegativePrefix + * Exponent{@code ?} + *
      {@code | }LocalNegativePrefix * DecimalNumeral * LocalNegativeSuffix - * Exponent? + * Exponent{@code ?} * *
      HexFloat: - *
      [-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+ - * ([pP][-+]?[0-9]+)? + *
      {@code [-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+ + * ([pP][-+]?[0-9]+)?} * *
      NonNumber: - *
      NaN - * | LocalNan + *
      {@code NaN + * | }LocalNan{@code * | Infinity - * | LocalInfinity + * | }LocalInfinity * *
      SignedNonNumber: - *
      ( [-+]? NonNumber ) - *
      | LocalPositivePrefix + *
      {@code ( [-+]? }NonNumber{@code )} + *
      {@code | }LocalPositivePrefix * NonNumber * LocalPositiveSuffix - *
      | LocalNegativePrefix + *
      {@code | }LocalNegativePrefix * NonNumber * LocalNegativeSuffix * - *
      Float: + *
      Float: *
      Decimal - * | HexFloat - * | SignedNonNumber + * {@code | }HexFloat + * {@code | }SignedNonNumber * *
      *

      Whitespace is not significant in the above regular expressions. @@ -362,19 +365,16 @@ public final class Scanner implements Iterator, Closeable { private Locale locale = null; // A cache of the last few recently used Patterns - private LRUCache patternCache = - new LRUCache(7) { - protected Pattern create(String s) { - return Pattern.compile(s); - } - protected boolean hasName(Pattern p, String s) { - return p.pattern().equals(s); - } - }; + private PatternLRUCache patternCache = new PatternLRUCache(7); // A holder of the last IOException encountered private IOException lastException; + // Number of times this scanner's state has been modified. + // Generally incremented on most public APIs and checked + // within spliterator implementations. + int modCount; + // A pattern for java whitespace private static Pattern WHITESPACE_PATTERN = Pattern.compile( "\\p{javaWhitespace}+"); @@ -426,7 +426,7 @@ private String buildIntegerPatternString() { // here but what can we do? The final authority will be // whatever parse method is invoked, so ultimately the // Scanner will do the right thing - String digit = "((?i)["+radixDigits+"]|\\p{javaDigit})"; + String digit = "((?i)["+radixDigits+"\\p{javaDigit}])"; // BEGIN Android-changed: Support non-decimal starting digits. // Ie., in addition to 1-9, a-z are also valid radix digits. /* @@ -484,7 +484,7 @@ private static Pattern linePattern() { private Pattern decimalPattern; private void buildFloatAndDecimalPattern() { // \\p{javaDigit} may not be perfect, see above - String digit = "([0-9]|(\\p{javaDigit}))"; + String digit = "(([0-9\\p{javaDigit}]))"; String exponent = "([eE][+-]?"+digit+"+)?"; String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+ groupSeparator+digit+digit+digit+")+)"; @@ -530,7 +530,7 @@ private Pattern decimalPattern() { // Constructors /** - * Constructs a Scanner that returns values scanned + * Constructs a {@code Scanner} that returns values scanned * from the specified source delimited by the specified pattern. * * @param source A character source implementing the Readable interface @@ -550,7 +550,7 @@ private Scanner(Readable source, Pattern pattern) { } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified source. * * @param source A character source implementing the {@link Readable} @@ -561,7 +561,7 @@ public Scanner(Readable source) { } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified input stream. Bytes from the stream are converted * into characters using the underlying platform's * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. @@ -573,7 +573,7 @@ public Scanner(InputStream source) { } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified input stream. Bytes from the stream are converted * into characters using the specified charset. * @@ -584,7 +584,21 @@ public Scanner(InputStream source) { * does not exist */ public Scanner(InputStream source, String charsetName) { - this(makeReadable(Objects.requireNonNull(source, "source"), toCharset(charsetName)), + // this(source, toCharset(charsetName)); + } + + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified input stream. Bytes from the stream are converted + * into characters using the specified charset. + * + * @param source an input stream to be scanned + * @param charset the charset used to convert bytes from the file + * into characters to be scanned + * @since 10 + */ + public Scanner(InputStream source, Charset charset) { + this(makeReadable(Objects.requireNonNull(source, "source"), charset), WHITESPACE_PATTERN); } @@ -603,12 +617,24 @@ private static Charset toCharset(String csn) { } } + /* + * This method is added so that null-check on charset can be performed before + * creating InputStream as an existing test required it. + */ + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // private static Readable makeReadable(Path source, Charset charset) + // throws IOException { + // Objects.requireNonNull(charset, "charset"); + // return makeReadable(Files.newInputStream(source), charset); + // } + private static Readable makeReadable(InputStream source, Charset charset) { + Objects.requireNonNull(charset, "charset"); return new InputStreamReader(source, charset); } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified file. Bytes from the file are converted into * characters using the underlying platform's * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. @@ -621,7 +647,7 @@ public Scanner(File source) throws FileNotFoundException { } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified file. Bytes from the file are converted into * characters using the specified charset. * @@ -638,6 +664,22 @@ public Scanner(File source, String charsetName) this(Objects.requireNonNull(source), toDecoder(charsetName)); } + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the specified charset. + * + * @param source A file to be scanned + * @param charset The charset used to convert bytes from the file + * into characters to be scanned + * @throws IOException + * if an I/O error occurs opening the source + * @since 10 + */ + public Scanner(File source, Charset charset) throws IOException { + this(Objects.requireNonNull(source), charset.newDecoder()); + } + private Scanner(File source, CharsetDecoder dec) throws FileNotFoundException { @@ -662,8 +704,74 @@ private static Readable makeReadable(ReadableByteChannel source, return Channels.newReader(source, dec, -1); } + private static Readable makeReadable(ReadableByteChannel source, + Charset charset) { + Objects.requireNonNull(charset, "charset"); + return Channels.newReader(source, charset); + } + /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the underlying platform's + * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. + * + * @param source + * the path to the file to be scanned + * @throws IOException + * if an I/O error occurs opening source + * + * @since 1.7 + */ + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // public Scanner(Path source) + // throws IOException + // { + // this(Files.newInputStream(source)); + // } + + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the specified charset. + * + * @param source + * the path to the file to be scanned + * @param charsetName + * The encoding type used to convert bytes from the file + * into characters to be scanned + * @throws IOException + * if an I/O error occurs opening source + * @throws IllegalArgumentException + * if the specified encoding is not found + * @since 1.7 + */ + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // public Scanner(Path source, String charsetName) throws IOException { + // this(Objects.requireNonNull(source), toCharset(charsetName)); + // } + + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the specified charset. + * + * @param source + * the path to the file to be scanned + * @param charset + * the charset used to convert bytes from the file + * into characters to be scanned + * @throws IOException + * if an I/O error occurs opening the source + * @since 10 + */ + // TODO(b/287571490): Reimplement code with dependencies outside of the core JRE subset + // public Scanner(Path source, Charset charset) throws IOException { + // this(makeReadable(source, charset)); + // } + + /** + * Constructs a new {@code Scanner} that produces values scanned * from the specified string. * * @param source A string to scan @@ -673,7 +781,7 @@ public Scanner(String source) { } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified channel. Bytes from the source are converted into * characters using the underlying platform's * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. @@ -690,7 +798,7 @@ private static Readable makeReadable(ReadableByteChannel source) { } /** - * Constructs a new Scanner that produces values scanned + * Constructs a new {@code Scanner} that produces values scanned * from the specified channel. Bytes from the source are converted into * characters using the specified charset. * @@ -705,6 +813,21 @@ public Scanner(ReadableByteChannel source, String charsetName) { WHITESPACE_PATTERN); } + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified channel. Bytes from the source are converted into + * characters using the specified charset. + * + * @param source a channel to scan + * @param charset the encoding type used to convert bytes from the + * channel into characters to be scanned + * @since 10 + */ + public Scanner(ReadableByteChannel source, Charset charset) { + this(makeReadable(Objects.requireNonNull(source, "source"), charset), + WHITESPACE_PATTERN); + } + // Private primitives used to support scanning private void saveState() { @@ -763,7 +886,6 @@ private void useTypeCache() { private void readInput() { if (buf.limit() == buf.capacity()) makeSpace(); - // Prepare to receive data int p = buf.position(); buf.position(buf.limit()); @@ -776,15 +898,12 @@ private void readInput() { lastException = ioe; n = -1; } - if (n == -1) { sourceClosed = true; needInput = false; } - if (n > 0) needInput = false; - // Restore current position and limit for reading buf.limit(buf.position()); buf.position(p); @@ -845,15 +964,20 @@ private boolean hasTokenInBuffer() { matchValid = false; matcher.usePattern(delimPattern); matcher.region(position, buf.limit()); - // Skip delims first - if (matcher.lookingAt()) + if (matcher.lookingAt()) { + if (matcher.hitEnd() && !sourceClosed) { + // more input might change the match of delims, in which + // might change whether or not if there is token left in + // buffer (don't update the "position" in this case) + needInput = true; + return false; + } position = matcher.end(); - + } // If we are sitting at the end, no more tokens in buffer if (position == buf.limit()) return false; - return true; } @@ -874,7 +998,6 @@ private boolean hasTokenInBuffer() { */ private String getCompleteTokenInBuffer(Pattern pattern) { matchValid = false; - // Skip delims first matcher.usePattern(delimPattern); if (!skipped) { // Enforcing only one skip of leading delims @@ -899,7 +1022,6 @@ private String getCompleteTokenInBuffer(Pattern pattern) { needInput = true; return null; } - // Must look for next delims. Simply attempting to match the // pattern at this point may find a match but it might not be // the first longest match because of missing input, or it might @@ -969,8 +1091,9 @@ private String getCompleteTokenInBuffer(Pattern pattern) { } // Finds the specified pattern in the buffer up to horizon. - // Returns a match for the specified input pattern. - private String findPatternInBuffer(Pattern pattern, int horizon) { + // Returns true if the specified input pattern was matched, + // and leaves the matcher field with the current match state. + private boolean findPatternInBuffer(Pattern pattern, int horizon) { matchValid = false; matcher.usePattern(pattern); int bufferLimit = buf.limit(); @@ -988,7 +1111,7 @@ private String findPatternInBuffer(Pattern pattern, int horizon) { if (searchLimit != horizonLimit) { // Hit an artificial end; try to extend the match needInput = true; - return null; + return false; } // The match could go away depending on what is next if ((searchLimit == horizonLimit) && matcher.requireEnd()) { @@ -996,27 +1119,28 @@ private String findPatternInBuffer(Pattern pattern, int horizon) { // that it is at the horizon and the end of input is // required for the match. needInput = true; - return null; + return false; } } // Did not hit end, or hit real end, or hit horizon position = matcher.end(); - return matcher.group(); + return true; } if (sourceClosed) - return null; + return false; // If there is no specified horizon, or if we have not searched // to the specified horizon yet, get more input if ((horizon == 0) || (searchLimit != horizonLimit)) needInput = true; - return null; + return false; } - // Returns a match for the specified input pattern anchored at - // the current position - private String matchPatternInBuffer(Pattern pattern) { + // Attempts to match a pattern anchored at the current position. + // Returns true if the specified input pattern was matched, + // and leaves the matcher field with the current match state. + private boolean matchPatternInBuffer(Pattern pattern) { matchValid = false; matcher.usePattern(pattern); matcher.region(position, buf.limit()); @@ -1024,18 +1148,18 @@ private String matchPatternInBuffer(Pattern pattern) { if (matcher.hitEnd() && (!sourceClosed)) { // Get more input and try again needInput = true; - return null; + return false; } position = matcher.end(); - return matcher.group(); + return true; } if (sourceClosed) - return null; + return false; // Read more to find pattern needInput = true; - return null; + return false; } // Throws if the scanner is closed @@ -1051,7 +1175,7 @@ private void ensureOpen() { * *

      If this scanner has not yet been closed then if its underlying * {@linkplain java.lang.Readable readable} also implements the {@link - * java.io.Closeable} interface then the readable's close method + * java.io.Closeable} interface then the readable's {@code close} method * will be invoked. If this scanner is already closed then invoking this * method will have no effect. * @@ -1075,9 +1199,9 @@ public void close() { } /** - * Returns the IOException last thrown by this - * Scanner's underlying Readable. This method - * returns null if no such exception exists. + * Returns the {@code IOException} last thrown by this + * {@code Scanner}'s underlying {@code Readable}. This method + * returns {@code null} if no such exception exists. * * @return the last exception thrown by this scanner's readable */ @@ -1086,7 +1210,7 @@ public IOException ioException() { } /** - * Returns the Pattern this Scanner is currently + * Returns the {@code Pattern} this {@code Scanner} is currently * using to match delimiters. * * @return this scanner's delimiting pattern. @@ -1102,17 +1226,18 @@ public Pattern delimiter() { * @return this scanner */ public Scanner useDelimiter(Pattern pattern) { + modCount++; delimPattern = pattern; return this; } /** * Sets this scanner's delimiting pattern to a pattern constructed from - * the specified String. + * the specified {@code String}. * *

      An invocation of this method of the form - * useDelimiter(pattern) behaves in exactly the same way as the - * invocation useDelimiter(Pattern.compile(pattern)). + * {@code useDelimiter(pattern)} behaves in exactly the same way as the + * invocation {@code useDelimiter(Pattern.compile(pattern))}. * *

      Invoking the {@link #reset} method will set the scanner's delimiter * to the default. @@ -1121,6 +1246,7 @@ public Scanner useDelimiter(Pattern pattern) { * @return this scanner */ public Scanner useDelimiter(String pattern) { + modCount++; delimPattern = patternCache.forName(pattern); return this; } @@ -1155,32 +1281,56 @@ public Scanner useLocale(Locale locale) { if (locale.equals(this.locale)) return this; + modCount++; this.locale = locale; - DecimalFormat df = - (DecimalFormat)NumberFormat.getNumberInstance(locale); + + DecimalFormat df = null; + NumberFormat nf = NumberFormat.getNumberInstance(locale); DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale); + // Android-changed: nf is DecimalFormat. + /* + if (nf instanceof DecimalFormat) { + df = (DecimalFormat) nf; + } else { + + // In case where NumberFormat.getNumberInstance() returns + // other instance (non DecimalFormat) based on the provider + // used and java.text.spi.NumberFormatProvider implementations, + // DecimalFormat constructor is used to obtain the instance + LocaleProviderAdapter adapter = LocaleProviderAdapter + .getAdapter(NumberFormatProvider.class, locale); + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + String[] all = adapter.getLocaleResources(locale) + .getNumberPatterns(); + df = new DecimalFormat(all[0], dfs); + } + */ + df = (DecimalFormat) nf; + // These must be literalized to avoid collision with regex // metacharacters such as dot or parenthesis - groupSeparator = "\\" + dfs.getGroupingSeparator(); - decimalSeparator = "\\" + dfs.getDecimalSeparator(); + groupSeparator = "\\x{" + Integer.toHexString(dfs.getGroupingSeparator()) + "}"; + decimalSeparator = "\\x{" + Integer.toHexString(dfs.getDecimalSeparator()) + "}"; // Quoting the nonzero length locale-specific things // to avoid potential conflict with metacharacters - nanString = "\\Q" + dfs.getNaN() + "\\E"; - infinityString = "\\Q" + dfs.getInfinity() + "\\E"; + nanString = Pattern.quote(dfs.getNaN()); + infinityString = Pattern.quote(dfs.getInfinity()); positivePrefix = df.getPositivePrefix(); - if (positivePrefix.length() > 0) - positivePrefix = "\\Q" + positivePrefix + "\\E"; + if (!positivePrefix.isEmpty()) + positivePrefix = Pattern.quote(positivePrefix); negativePrefix = df.getNegativePrefix(); - if (negativePrefix.length() > 0) - negativePrefix = "\\Q" + negativePrefix + "\\E"; + if (!negativePrefix.isEmpty()) + negativePrefix = Pattern.quote(negativePrefix); positiveSuffix = df.getPositiveSuffix(); - if (positiveSuffix.length() > 0) - positiveSuffix = "\\Q" + positiveSuffix + "\\E"; + if (!positiveSuffix.isEmpty()) + positiveSuffix = Pattern.quote(positiveSuffix); negativeSuffix = df.getNegativeSuffix(); - if (negativeSuffix.length() > 0) - negativeSuffix = "\\Q" + negativeSuffix + "\\E"; + if (!negativeSuffix.isEmpty()) + negativeSuffix = Pattern.quote(negativeSuffix); // Force rebuilding and recompilation of locale dependent // primitive patterns @@ -1210,12 +1360,12 @@ public int radix() { * number matching regular expressions; see * localized numbers above. * - *

      If the radix is less than Character.MIN_RADIX - * or greater than Character.MAX_RADIX, then an - * IllegalArgumentException is thrown. + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. * *

      Invoking the {@link #reset} method will set the scanner's radix to - * 10. + * {@code 10}. * * @param radix The radix to use when scanning numbers * @return this scanner @@ -1227,6 +1377,7 @@ public Scanner useRadix(int radix) { if (this.defaultRadix == radix) return this; + modCount++; this.defaultRadix = radix; // Force rebuilding and recompilation of radix dependent patterns integerPattern = null; @@ -1236,11 +1387,8 @@ public Scanner useRadix(int radix) { // The next operation should occur in the specified radix but // the default is left untouched. private void setRadix(int radix) { - // BEGIN Android-added: Complain loudly if a bogus radix is being set. - if (radix > Character.MAX_RADIX) { - throw new IllegalArgumentException("radix == " + radix); - } - // END Android-added: Complain loudly if a bogus radix is being set. + if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) + throw new IllegalArgumentException("radix:"+radix); if (this.radix != radix) { // Force rebuilding and recompilation of radix dependent patterns @@ -1251,19 +1399,19 @@ private void setRadix(int radix) { /** * Returns the match result of the last scanning operation performed - * by this scanner. This method throws IllegalStateException + * by this scanner. This method throws {@code IllegalStateException} * if no match has been performed, or if the last match was * not successful. * - *

      The various nextmethods of Scanner + *

      The various {@code next} methods of {@code Scanner} * make a match result available if they complete without throwing an * exception. For instance, after an invocation of the {@link #nextInt} * method that returned an int, this method returns a - * MatchResult for the search of the + * {@code MatchResult} for the search of the * Integer regular expression - * defined above. Similarly the {@link #findInLine}, - * {@link #findWithinHorizon}, and {@link #skip} methods will make a - * match available if they succeed. + * defined above. Similarly the {@link #findInLine findInLine()}, + * {@link #findWithinHorizon findWithinHorizon()}, and {@link #skip skip()} + * methods will make a match available if they succeed. * * @return a match result for the last match operation * @throws IllegalStateException If no match result is available @@ -1275,8 +1423,8 @@ public MatchResult match() { } /** - *

      Returns the string representation of this Scanner. The - * string representation of a Scanner contains information + *

      Returns the string representation of this {@code Scanner}. The + * string representation of a {@code Scanner} contains information * that may be useful for debugging. The exact format is unspecified. * * @return The string representation of this scanner @@ -1313,9 +1461,11 @@ public String toString() { public boolean hasNext() { ensureOpen(); saveState(); + modCount++; while (!sourceClosed) { - if (hasTokenInBuffer()) + if (hasTokenInBuffer()) { return revertState(true); + } readInput(); } boolean result = hasTokenInBuffer(); @@ -1327,7 +1477,7 @@ public boolean hasNext() { * A complete token is preceded and followed by input that matches * the delimiter pattern. This method may block while waiting for input * to scan, even if a previous invocation of {@link #hasNext} returned - * true. + * {@code true}. * * @return the next token * @throws NoSuchElementException if no more tokens are available @@ -1337,7 +1487,7 @@ public boolean hasNext() { public String next() { ensureOpen(); clearCaches(); - + modCount++; while (true) { String token = getCompleteTokenInBuffer(null); if (token != null) { @@ -1354,7 +1504,7 @@ public String next() { /** * The remove operation is not supported by this implementation of - * Iterator. + * {@code Iterator}. * * @throws UnsupportedOperationException if this method is invoked. * @see java.util.Iterator @@ -1367,9 +1517,9 @@ public void remove() { * Returns true if the next token matches the pattern constructed from the * specified string. The scanner does not advance past any input. * - *

      An invocation of this method of the form hasNext(pattern) + *

      An invocation of this method of the form {@code hasNext(pattern)} * behaves in exactly the same way as the invocation - * hasNext(Pattern.compile(pattern)). + * {@code hasNext(Pattern.compile(pattern))}. * * @param pattern a string specifying the pattern to scan * @return true if and only if this scanner has another token matching @@ -1385,9 +1535,9 @@ public boolean hasNext(String pattern) { * specified string. If the match is successful, the scanner advances * past the input that matched the pattern. * - *

      An invocation of this method of the form next(pattern) + *

      An invocation of this method of the form {@code next(pattern)} * behaves in exactly the same way as the invocation - * next(Pattern.compile(pattern)). + * {@code next(Pattern.compile(pattern))}. * * @param pattern a string specifying the pattern to scan * @return the next token @@ -1415,6 +1565,7 @@ public boolean hasNext(Pattern pattern) { throw new NullPointerException(); hasNextPattern = null; saveState(); + modCount++; while (true) { if (getCompleteTokenInBuffer(pattern) != null) { @@ -1432,7 +1583,7 @@ public boolean hasNext(Pattern pattern) { /** * Returns the next token if it matches the specified pattern. This * method may block while waiting for input to scan, even if a previous - * invocation of {@link #hasNext(Pattern)} returned true. + * invocation of {@link #hasNext(Pattern)} returned {@code true}. * If the match is successful, the scanner advances past the input that * matched the pattern. * @@ -1446,6 +1597,7 @@ public String next(Pattern pattern) { if (pattern == null) throw new NullPointerException(); + modCount++; // Did we already find this pattern? if (hasNextPattern == pattern) return getCachedResult(); @@ -1477,6 +1629,7 @@ public String next(Pattern pattern) { public boolean hasNextLine() { saveState(); + modCount++; String result = findWithinHorizon(linePattern(), 0); if (result != null) { MatchResult mr = this.match(); @@ -1511,6 +1664,7 @@ public boolean hasNextLine() { * @throws IllegalStateException if this scanner is closed */ public String nextLine() { + modCount++; if (hasNextPattern == linePattern()) return getCachedResult(); clearCaches(); @@ -1534,9 +1688,9 @@ public String nextLine() { * Attempts to find the next occurrence of a pattern constructed from the * specified string, ignoring delimiters. * - *

      An invocation of this method of the form findInLine(pattern) + *

      An invocation of this method of the form {@code findInLine(pattern)} * behaves in exactly the same way as the invocation - * findInLine(Pattern.compile(pattern)). + * {@code findInLine(Pattern.compile(pattern))}. * * @param pattern a string specifying the pattern to search for * @return the text that matched the specified pattern @@ -1552,7 +1706,7 @@ public String findInLine(String pattern) { * scanner advances past the input that matched and returns the string that * matched the pattern. * If no such pattern is detected in the input up to the next line - * separator, then null is returned and the scanner's + * separator, then {@code null} is returned and the scanner's * position is unchanged. This method may block waiting for input that * matches the pattern. * @@ -1569,12 +1723,12 @@ public String findInLine(Pattern pattern) { if (pattern == null) throw new NullPointerException(); clearCaches(); + modCount++; // Expand buffer to include the next newline or end of input int endPosition = 0; saveState(); while (true) { - String token = findPatternInBuffer(separatorPattern(), 0); - if (token != null) { + if (findPatternInBuffer(separatorPattern(), 0)) { endPosition = matcher.start(); break; // up to next newline } @@ -1601,9 +1755,9 @@ public String findInLine(Pattern pattern) { * specified string, ignoring delimiters. * *

      An invocation of this method of the form - * findWithinHorizon(pattern) behaves in exactly the same way as + * {@code findWithinHorizon(pattern)} behaves in exactly the same way as * the invocation - * findWithinHorizon(Pattern.compile(pattern, horizon)). + * {@code findWithinHorizon(Pattern.compile(pattern), horizon)}. * * @param pattern a string specifying the pattern to search for * @param horizon the search horizon @@ -1625,14 +1779,14 @@ public String findWithinHorizon(String pattern, int horizon) { * null is returned and the scanner's position remains unchanged. This * method may block waiting for input that matches the pattern. * - *

      A scanner will never search more than horizon code + *

      A scanner will never search more than {@code horizon} code * points beyond its current position. Note that a match may be clipped * by the horizon; that is, an arbitrary match result may have been * different if the horizon had been larger. The scanner treats the * horizon as a transparent, non-anchoring bound (see {@link * Matcher#useTransparentBounds} and {@link Matcher#useAnchoringBounds}). * - *

      If horizon is 0, then the horizon is ignored and + *

      If horizon is {@code 0}, then the horizon is ignored and * this method continues to search through the input looking for the * specified pattern without bound. In this case it may buffer all of * the input searching for the pattern. @@ -1653,13 +1807,13 @@ public String findWithinHorizon(Pattern pattern, int horizon) { if (horizon < 0) throw new IllegalArgumentException("horizon < 0"); clearCaches(); + modCount++; // Search for the pattern while (true) { - String token = findPatternInBuffer(pattern, horizon); - if (token != null) { + if (findPatternInBuffer(pattern, horizon)) { matchValid = true; - return token; + return matcher.group(); } if (needInput) readInput(); @@ -1676,7 +1830,7 @@ public String findWithinHorizon(Pattern pattern, int horizon) { * *

      If a match to the specified pattern is not found at the * current position, then no input is skipped and a - * NoSuchElementException is thrown. + * {@code NoSuchElementException} is thrown. * *

      Since this method seeks to match the specified pattern starting at * the scanner's current position, patterns that can match a lot of @@ -1684,8 +1838,8 @@ public String findWithinHorizon(Pattern pattern, int horizon) { * amount of input. * *

      Note that it is possible to skip something without risking a - * NoSuchElementException by using a pattern that can - * match nothing, e.g., sc.skip("[ \t]*"). + * {@code NoSuchElementException} by using a pattern that can + * match nothing, e.g., {@code sc.skip("[ \t]*")}. * * @param pattern a string specifying the pattern to skip over * @return this scanner @@ -1697,11 +1851,11 @@ public Scanner skip(Pattern pattern) { if (pattern == null) throw new NullPointerException(); clearCaches(); + modCount++; // Search for the pattern while (true) { - String token = matchPatternInBuffer(pattern); - if (token != null) { + if (matchPatternInBuffer(pattern)) { matchValid = true; position = matcher.end(); return this; @@ -1717,9 +1871,9 @@ public Scanner skip(Pattern pattern) { * Skips input that matches a pattern constructed from the specified * string. * - *

      An invocation of this method of the form skip(pattern) + *

      An invocation of this method of the form {@code skip(pattern)} * behaves in exactly the same way as the invocation - * skip(Pattern.compile(pattern)). + * {@code skip(Pattern.compile(pattern))}. * * @param pattern a string specifying the pattern to skip over * @return this scanner @@ -1747,7 +1901,7 @@ public boolean hasNextBoolean() { /** * Scans the next token of the input into a boolean value and returns - * that value. This method will throw InputMismatchException + * that value. This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid boolean value. * If the match is successful, the scanner advances past the input that * matched. @@ -1780,10 +1934,15 @@ public boolean hasNextByte() { * interpreted as a byte value in the specified radix using the * {@link #nextByte} method. The scanner does not advance past any input. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a byte value * @return true if and only if this scanner's next token is a valid * byte value * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextByte(int radix) { setRadix(radix); @@ -1802,14 +1961,14 @@ public boolean hasNextByte(int radix) { } /** - * Scans the next token of the input as a byte. + * Scans the next token of the input as a {@code byte}. * *

      An invocation of this method of the form - * nextByte() behaves in exactly the same way as the - * invocation nextByte(radix), where radix + * {@code nextByte()} behaves in exactly the same way as the + * invocation {@code nextByte(radix)}, where {@code radix} * is the default radix of this scanner. * - * @return the byte scanned from the input + * @return the {@code byte} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range @@ -1821,15 +1980,15 @@ public byte nextByte() { } /** - * Scans the next token of the input as a byte. - * This method will throw InputMismatchException + * Scans the next token of the input as a {@code byte}. + * This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid byte value as * described below. If the translation is successful, the scanner advances * past the input that matched. * *

      If the next token matches the Integer regular expression defined - * above then the token is converted into a byte value as if by + * above then the token is converted into a {@code byte} value as if by * removing all locale specific prefixes, group separators, and locale * specific suffixes, then mapping non-ASCII digits into ASCII * digits via {@link Character#digit Character.digit}, prepending a @@ -1838,13 +1997,18 @@ public byte nextByte() { * {@link Byte#parseByte(String, int) Byte.parseByte} with the * specified radix. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a byte value - * @return the byte scanned from the input + * @return the {@code byte} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public byte nextByte(int radix) { // Check cached result @@ -1886,10 +2050,15 @@ public boolean hasNextShort() { * interpreted as a short value in the specified radix using the * {@link #nextShort} method. The scanner does not advance past any input. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a short value * @return true if and only if this scanner's next token is a valid * short value in the specified radix * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextShort(int radix) { setRadix(radix); @@ -1908,14 +2077,14 @@ public boolean hasNextShort(int radix) { } /** - * Scans the next token of the input as a short. + * Scans the next token of the input as a {@code short}. * *

      An invocation of this method of the form - * nextShort() behaves in exactly the same way as the - * invocation nextShort(radix), where radix + * {@code nextShort()} behaves in exactly the same way as the + * invocation {@link #nextShort(int) nextShort(radix)}, where {@code radix} * is the default radix of this scanner. * - * @return the short scanned from the input + * @return the {@code short} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range @@ -1927,15 +2096,15 @@ public short nextShort() { } /** - * Scans the next token of the input as a short. - * This method will throw InputMismatchException + * Scans the next token of the input as a {@code short}. + * This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid short value as * described below. If the translation is successful, the scanner advances * past the input that matched. * *

      If the next token matches the Integer regular expression defined - * above then the token is converted into a short value as if by + * above then the token is converted into a {@code short} value as if by * removing all locale specific prefixes, group separators, and locale * specific suffixes, then mapping non-ASCII digits into ASCII * digits via {@link Character#digit Character.digit}, prepending a @@ -1944,13 +2113,18 @@ public short nextShort() { * {@link Short#parseShort(String, int) Short.parseShort} with the * specified radix. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a short value - * @return the short scanned from the input + * @return the {@code short} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public short nextShort(int radix) { // Check cached result @@ -1992,10 +2166,15 @@ public boolean hasNextInt() { * interpreted as an int value in the specified radix using the * {@link #nextInt} method. The scanner does not advance past any input. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an int value * @return true if and only if this scanner's next token is a valid * int value * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextInt(int radix) { setRadix(radix); @@ -2038,14 +2217,14 @@ private String processIntegerToken(String token) { } /** - * Scans the next token of the input as an int. + * Scans the next token of the input as an {@code int}. * *

      An invocation of this method of the form - * nextInt() behaves in exactly the same way as the - * invocation nextInt(radix), where radix + * {@code nextInt()} behaves in exactly the same way as the + * invocation {@code nextInt(radix)}, where {@code radix} * is the default radix of this scanner. * - * @return the int scanned from the input + * @return the {@code int} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range @@ -2057,15 +2236,15 @@ public int nextInt() { } /** - * Scans the next token of the input as an int. - * This method will throw InputMismatchException + * Scans the next token of the input as an {@code int}. + * This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid int value as * described below. If the translation is successful, the scanner advances * past the input that matched. * *

      If the next token matches the Integer regular expression defined - * above then the token is converted into an int value as if by + * above then the token is converted into an {@code int} value as if by * removing all locale specific prefixes, group separators, and locale * specific suffixes, then mapping non-ASCII digits into ASCII * digits via {@link Character#digit Character.digit}, prepending a @@ -2074,13 +2253,18 @@ public int nextInt() { * {@link Integer#parseInt(String, int) Integer.parseInt} with the * specified radix. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an int value - * @return the int scanned from the input + * @return the {@code int} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public int nextInt(int radix) { // Check cached result @@ -2122,10 +2306,15 @@ public boolean hasNextLong() { * interpreted as a long value in the specified radix using the * {@link #nextLong} method. The scanner does not advance past any input. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a long value * @return true if and only if this scanner's next token is a valid * long value * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextLong(int radix) { setRadix(radix); @@ -2144,14 +2333,14 @@ public boolean hasNextLong(int radix) { } /** - * Scans the next token of the input as a long. + * Scans the next token of the input as a {@code long}. * *

      An invocation of this method of the form - * nextLong() behaves in exactly the same way as the - * invocation nextLong(radix), where radix + * {@code nextLong()} behaves in exactly the same way as the + * invocation {@code nextLong(radix)}, where {@code radix} * is the default radix of this scanner. * - * @return the long scanned from the input + * @return the {@code long} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range @@ -2163,15 +2352,15 @@ public long nextLong() { } /** - * Scans the next token of the input as a long. - * This method will throw InputMismatchException + * Scans the next token of the input as a {@code long}. + * This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid long value as * described below. If the translation is successful, the scanner advances * past the input that matched. * *

      If the next token matches the Integer regular expression defined - * above then the token is converted into a long value as if by + * above then the token is converted into a {@code long} value as if by * removing all locale specific prefixes, group separators, and locale * specific suffixes, then mapping non-ASCII digits into ASCII * digits via {@link Character#digit Character.digit}, prepending a @@ -2180,13 +2369,18 @@ public long nextLong() { * {@link Long#parseLong(String, int) Long.parseLong} with the * specified radix. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an int value - * @return the long scanned from the input + * @return the {@code long} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public long nextLong(int radix) { // Check cached result @@ -2290,15 +2484,15 @@ public boolean hasNextFloat() { } /** - * Scans the next token of the input as a float. - * This method will throw InputMismatchException + * Scans the next token of the input as a {@code float}. + * This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid float value as * described below. If the translation is successful, the scanner advances * past the input that matched. * *

      If the next token matches the Float regular expression defined above - * then the token is converted into a float value as if by + * then the token is converted into a {@code float} value as if by * removing all locale specific prefixes, group separators, and locale * specific suffixes, then mapping non-ASCII digits into ASCII * digits via {@link Character#digit Character.digit}, prepending a @@ -2309,7 +2503,7 @@ public boolean hasNextFloat() { * is passed to {@link Float#parseFloat(String) Float.parseFloat} as * appropriate. * - * @return the float scanned from the input + * @return the {@code float} scanned from the input * @throws InputMismatchException * if the next token does not match the Float * regular expression, or is out of range @@ -2357,15 +2551,15 @@ public boolean hasNextDouble() { } /** - * Scans the next token of the input as a double. - * This method will throw InputMismatchException + * Scans the next token of the input as a {@code double}. + * This method will throw {@code InputMismatchException} * if the next token cannot be translated into a valid double value. * If the translation is successful, the scanner advances past the input * that matched. * *

      If the next token matches the Float regular expression defined above - * then the token is converted into a double value as if by + * then the token is converted into a {@code double} value as if by * removing all locale specific prefixes, group separators, and locale * specific suffixes, then mapping non-ASCII digits into ASCII * digits via {@link Character#digit Character.digit}, prepending a @@ -2376,7 +2570,7 @@ public boolean hasNextDouble() { * is passed to {@link Double#parseDouble(String) Double.parseDouble} as * appropriate. * - * @return the double scanned from the input + * @return the {@code double} scanned from the input * @throws InputMismatchException * if the next token does not match the Float * regular expression, or is out of range @@ -2405,12 +2599,12 @@ public double nextDouble() { /** * Returns true if the next token in this scanner's input can be - * interpreted as a BigInteger in the default radix using the + * interpreted as a {@code BigInteger} in the default radix using the * {@link #nextBigInteger} method. The scanner does not advance past any * input. * * @return true if and only if this scanner's next token is a valid - * BigInteger + * {@code BigInteger} * @throws IllegalStateException if this scanner is closed */ public boolean hasNextBigInteger() { @@ -2419,14 +2613,19 @@ public boolean hasNextBigInteger() { /** * Returns true if the next token in this scanner's input can be - * interpreted as a BigInteger in the specified radix using + * interpreted as a {@code BigInteger} in the specified radix using * the {@link #nextBigInteger} method. The scanner does not advance past * any input. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an integer * @return true if and only if this scanner's next token is a valid - * BigInteger + * {@code BigInteger} * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextBigInteger(int radix) { setRadix(radix); @@ -2449,11 +2648,11 @@ public boolean hasNextBigInteger(int radix) { * BigInteger}. * *

      An invocation of this method of the form - * nextBigInteger() behaves in exactly the same way as the - * invocation nextBigInteger(radix), where radix + * {@code nextBigInteger()} behaves in exactly the same way as the + * invocation {@code nextBigInteger(radix)}, where {@code radix} * is the default radix of this scanner. * - * @return the BigInteger scanned from the input + * @return the {@code BigInteger} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range @@ -2470,26 +2669,31 @@ public BigInteger nextBigInteger() { * *

      If the next token matches the Integer regular expression defined - * above then the token is converted into a BigInteger value as if + * above then the token is converted into a {@code BigInteger} value as if * by removing all group separators, mapping non-ASCII digits into ASCII * digits via the {@link Character#digit Character.digit}, and passing the * resulting string to the {@link * java.math.BigInteger#BigInteger(java.lang.String) * BigInteger(String, int)} constructor with the specified radix. * + *

      If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token - * @return the BigInteger scanned from the input + * @return the {@code BigInteger} scanned from the input * @throws InputMismatchException * if the next token does not match the Integer * regular expression, or is out of range * @throws NoSuchElementException if the input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public BigInteger nextBigInteger(int radix) { // Check cached result if ((typeCache != null) && (typeCache instanceof BigInteger) && this.radix == radix) { - BigInteger val = (BigInteger)typeCache; + var val = (BigInteger) typeCache; useTypeCache(); return val; } @@ -2509,12 +2713,12 @@ public BigInteger nextBigInteger(int radix) { /** * Returns true if the next token in this scanner's input can be - * interpreted as a BigDecimal using the + * interpreted as a {@code BigDecimal} using the * {@link #nextBigDecimal} method. The scanner does not advance past any * input. * * @return true if and only if this scanner's next token is a valid - * BigDecimal + * {@code BigDecimal} * @throws IllegalStateException if this scanner is closed */ public boolean hasNextBigDecimal() { @@ -2537,14 +2741,14 @@ public boolean hasNextBigDecimal() { * *

      If the next token matches the Decimal regular expression defined - * above then the token is converted into a BigDecimal value as if + * above then the token is converted into a {@code BigDecimal} value as if * by removing all group separators, mapping non-ASCII digits into ASCII * digits via the {@link Character#digit Character.digit}, and passing the * resulting string to the {@link * java.math.BigDecimal#BigDecimal(java.lang.String) BigDecimal(String)} * constructor. * - * @return the BigDecimal scanned from the input + * @return the {@code BigDecimal} scanned from the input * @throws InputMismatchException * if the next token does not match the Decimal * regular expression, or is out of range @@ -2554,7 +2758,7 @@ public boolean hasNextBigDecimal() { public BigDecimal nextBigDecimal() { // Check cached result if ((typeCache != null) && (typeCache instanceof BigDecimal)) { - BigDecimal val = (BigDecimal)typeCache; + var val = (BigDecimal)typeCache; useTypeCache(); return val; } @@ -2574,11 +2778,13 @@ public BigDecimal nextBigDecimal() { * Resets this scanner. * *

      Resetting a scanner discards all of its explicit state - * information which may have been changed by invocations of {@link - * #useDelimiter}, {@link #useLocale}, or {@link #useRadix}. + * information which may have been changed by invocations of + * {@link #useDelimiter useDelimiter()}, + * {@link #useLocale useLocale()}, or + * {@link #useRadix useRadix()}. * *

      An invocation of this method of the form - * scanner.reset() behaves in exactly the same way as the + * {@code scanner.reset()} behaves in exactly the same way as the * invocation * *

      {@code
      @@ -2596,6 +2802,279 @@ public Scanner reset() {
               useLocale(Locale.getDefault(Locale.Category.FORMAT));
               useRadix(10);
               clearCaches();
      +        modCount++;
               return this;
           }
      +
      +    /**
      +     * Returns a stream of delimiter-separated tokens from this scanner. The
      +     * stream contains the same tokens that would be returned, starting from
      +     * this scanner's current state, by calling the {@link #next} method
      +     * repeatedly until the {@link #hasNext} method returns false.
      +     *
      +     * 

      The resulting stream is sequential and ordered. All stream elements are + * non-null. + * + *

      Scanning starts upon initiation of the terminal stream operation, using the + * current state of this scanner. Subsequent calls to any methods on this scanner + * other than {@link #close} and {@link #ioException} may return undefined results + * or may cause undefined effects on the returned stream. The returned stream's source + * {@code Spliterator} is fail-fast and will, on a best-effort basis, throw a + * {@link java.util.ConcurrentModificationException} if any such calls are detected + * during stream pipeline execution. + * + *

      After stream pipeline execution completes, this scanner is left in an indeterminate + * state and cannot be reused. + * + *

      If this scanner contains a resource that must be released, this scanner + * should be closed, either by calling its {@link #close} method, or by + * closing the returned stream. Closing the stream will close the underlying scanner. + * {@code IllegalStateException} is thrown if the scanner has been closed when this + * method is called, or if this scanner is closed during stream pipeline execution. + * + *

      This method might block waiting for more input. + * + * @apiNote + * For example, the following code will create a list of + * comma-delimited tokens from a string: + * + *

      {@code
      +     * List result = new Scanner("abc,def,,ghi")
      +     *     .useDelimiter(",")
      +     *     .tokens()
      +     *     .collect(Collectors.toList());
      +     * }
      + * + *

      The resulting list would contain {@code "abc"}, {@code "def"}, + * the empty string, and {@code "ghi"}. + * + * @return a sequential stream of token strings + * @throws IllegalStateException if this scanner is closed + * @since 9 + */ + public Stream tokens() { + ensureOpen(); + Stream stream = StreamSupport.stream(new TokenSpliterator(), false); + return stream.onClose(this::close); + } + + class TokenSpliterator extends Spliterators.AbstractSpliterator { + int expectedCount = -1; + + TokenSpliterator() { + super(Long.MAX_VALUE, + Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED); + } + + @Override + public boolean tryAdvance(Consumer cons) { + if (expectedCount >= 0 && expectedCount != modCount) { + throw new ConcurrentModificationException(); + } + + if (hasNext()) { + String token = next(); + expectedCount = modCount; + cons.accept(token); + if (expectedCount != modCount) { + throw new ConcurrentModificationException(); + } + return true; + } else { + expectedCount = modCount; + return false; + } + } + } + + /** + * Returns a stream of match results from this scanner. The stream + * contains the same results in the same order that would be returned by + * calling {@code findWithinHorizon(pattern, 0)} and then {@link #match} + * successively as long as {@link #findWithinHorizon findWithinHorizon()} + * finds matches. + * + *

      The resulting stream is sequential and ordered. All stream elements are + * non-null. + * + *

      Scanning starts upon initiation of the terminal stream operation, using the + * current state of this scanner. Subsequent calls to any methods on this scanner + * other than {@link #close} and {@link #ioException} may return undefined results + * or may cause undefined effects on the returned stream. The returned stream's source + * {@code Spliterator} is fail-fast and will, on a best-effort basis, throw a + * {@link java.util.ConcurrentModificationException} if any such calls are detected + * during stream pipeline execution. + * + *

      After stream pipeline execution completes, this scanner is left in an indeterminate + * state and cannot be reused. + * + *

      If this scanner contains a resource that must be released, this scanner + * should be closed, either by calling its {@link #close} method, or by + * closing the returned stream. Closing the stream will close the underlying scanner. + * {@code IllegalStateException} is thrown if the scanner has been closed when this + * method is called, or if this scanner is closed during stream pipeline execution. + * + *

      As with the {@link #findWithinHorizon findWithinHorizon()} methods, this method + * might block waiting for additional input, and it might buffer an unbounded amount of + * input searching for a match. + * + * @apiNote + * For example, the following code will read a file and return a list + * of all sequences of characters consisting of seven or more Latin capital + * letters: + * + *

      {@code
      +     * try (Scanner sc = new Scanner(Path.of("input.txt"))) {
      +     *     Pattern pat = Pattern.compile("[A-Z]{7,}");
      +     *     List capWords = sc.findAll(pat)
      +     *                               .map(MatchResult::group)
      +     *                               .collect(Collectors.toList());
      +     * }
      +     * }
      + * + * @param pattern the pattern to be matched + * @return a sequential stream of match results + * @throws NullPointerException if pattern is null + * @throws IllegalStateException if this scanner is closed + * @since 9 + */ + public Stream findAll(Pattern pattern) { + Objects.requireNonNull(pattern); + ensureOpen(); + Stream stream = StreamSupport.stream(new FindSpliterator(pattern), false); + return stream.onClose(this::close); + } + + /** + * Returns a stream of match results that match the provided pattern string. + * The effect is equivalent to the following code: + * + *
      {@code
      +     *     scanner.findAll(Pattern.compile(patString))
      +     * }
      + * + * @param patString the pattern string + * @return a sequential stream of match results + * @throws NullPointerException if patString is null + * @throws IllegalStateException if this scanner is closed + * @throws PatternSyntaxException if the regular expression's syntax is invalid + * @since 9 + * @see java.util.regex.Pattern + */ + public Stream findAll(String patString) { + Objects.requireNonNull(patString); + ensureOpen(); + return findAll(patternCache.forName(patString)); + } + + class FindSpliterator extends Spliterators.AbstractSpliterator { + final Pattern pattern; + int expectedCount = -1; + private boolean advance = false; // true if we need to auto-advance + + FindSpliterator(Pattern pattern) { + super(Long.MAX_VALUE, + Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED); + this.pattern = pattern; + } + + @Override + public boolean tryAdvance(Consumer cons) { + ensureOpen(); + if (expectedCount >= 0) { + if (expectedCount != modCount) { + throw new ConcurrentModificationException(); + } + } else { + // init + matchValid = false; + matcher.usePattern(pattern); + expectedCount = modCount; + } + + while (true) { + // assert expectedCount == modCount + if (nextInBuffer()) { // doesn't increment modCount + cons.accept(matcher.toMatchResult()); + if (expectedCount != modCount) { + throw new ConcurrentModificationException(); + } + return true; + } + if (needInput) + readInput(); // doesn't increment modCount + else + return false; // reached end of input + } + } + + // reimplementation of findPatternInBuffer with auto-advance on zero-length matches + private boolean nextInBuffer() { + if (advance) { + if (position + 1 > buf.limit()) { + if (!sourceClosed) + needInput = true; + return false; + } + position++; + advance = false; + } + matcher.region(position, buf.limit()); + if (matcher.find() && (!matcher.hitEnd() || sourceClosed)) { + // Did not hit end, or hit real end + position = matcher.end(); + advance = matcher.start() == position; + return true; + } + if (!sourceClosed) + needInput = true; + return false; + } + } + + /** Small LRU cache of Patterns. */ + private static class PatternLRUCache { + + private Pattern[] oa = null; + private final int size; + + PatternLRUCache(int size) { + this.size = size; + } + + boolean hasName(Pattern p, String s) { + return p.pattern().equals(s); + } + + void moveToFront(Object[] oa, int i) { + Object ob = oa[i]; + for (int j = i; j > 0; j--) + oa[j] = oa[j - 1]; + oa[0] = ob; + } + + Pattern forName(String name) { + if (oa == null) { + Pattern[] temp = new Pattern[size]; + oa = temp; + } else { + for (int i = 0; i < oa.length; i++) { + Pattern ob = oa[i]; + if (ob == null) + continue; + if (hasName(ob, name)) { + if (i > 0) + moveToFront(oa, i); + return ob; + } + } + } + + // Create a new object + Pattern ob = Pattern.compile(name); + oa[oa.length - 1] = ob; + moveToFront(oa, oa.length - 1); + return ob; + } + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ServiceConfigurationError.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ServiceConfigurationError.java index e0335f676f..2852384eb4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ServiceConfigurationError.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/ServiceConfigurationError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -27,33 +27,12 @@ /** - * Error thrown when something goes wrong while loading a service provider. - * - *

      This error will be thrown in the following situations: - * - *

        - * - *
      • The format of a provider-configuration file violates the specification;
      • - * - *
      • An {@link java.io.IOException IOException} occurs while reading a - * provider-configuration file;
      • - * - *
      • A concrete provider class named in a provider-configuration file - * cannot be found;
      • - * - *
      • A concrete provider class is not a subclass of the service class; - *
      • - * - *
      • A concrete provider class cannot be instantiated; or - * - *
      • Some other kind of error occurs.
      • - * - *
      - * + * Error thrown when something goes wrong while locating, loading, or + * instantiating a service provider. * * @author Mark Reinhold * @since 1.6 + * @see ServiceLoader */ public class ServiceConfigurationError @@ -65,7 +44,7 @@ public class ServiceConfigurationError /** * Constructs a new instance with the specified message. * - * @param msg The message, or null if there is no message + * @param msg The message, or {@code null} if there is no message * */ public ServiceConfigurationError(String msg) { @@ -75,9 +54,9 @@ public ServiceConfigurationError(String msg) { /** * Constructs a new instance with the specified message and cause. * - * @param msg The message, or null if there is no message + * @param msg The message, or {@code null} if there is no message * - * @param cause The cause, or null if the cause is nonexistent + * @param cause The cause, or {@code null} if the cause is nonexistent * or unknown */ public ServiceConfigurationError(String msg, Throwable cause) { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Set.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Set.java index df3f1cea91..504904f226 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Set.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Set.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -63,15 +63,16 @@ * Such exceptions are marked as "optional" in the specification for this * interface. * - *

      Immutable Set Static Factory Methods

      - *

      The {@link Set#of(Object...) Set.of()} static factory methods - * provide a convenient way to create immutable sets. The {@code Set} + *

      Unmodifiable Sets

      + *

      The {@link Set#of(Object...) Set.of} and + * {@link Set#copyOf Set.copyOf} static factory methods + * provide a convenient way to create unmodifiable sets. The {@code Set} * instances created by these methods have the following characteristics: * *

        - *
      • They are structurally immutable. Elements cannot be added or - * removed. Calling any mutator method will always cause - * {@code UnsupportedOperationException} to be thrown. + *
      • They are unmodifiable. Elements cannot + * be added or removed. Calling any mutator method on the Set + * will always cause {@code UnsupportedOperationException} to be thrown. * However, if the contained elements are themselves mutable, this may cause the * Set to behave inconsistently or its contents to appear to change. *
      • They disallow {@code null} elements. Attempts to create them with @@ -91,7 +92,7 @@ *
      * *

      This interface is a member of the - * + * * Java Collections Framework. * * @param the type of elements maintained by this set @@ -437,4 +438,293 @@ public interface Set extends Collection { default Spliterator spliterator() { return Spliterators.spliterator(this, Spliterator.DISTINCT); } + + /** + * Returns an unmodifiable set containing zero elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @return an empty {@code Set} + * + * @since 9 + */ + static Set of() { + return ImmutableCollections.emptySet(); + } + + /** + * Returns an unmodifiable set containing one element. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the single element + * @return a {@code Set} containing the specified element + * @throws NullPointerException if the element is {@code null} + * + * @since 9 + */ + static Set of(E e1) { + return new ImmutableCollections.Set12<>(e1); + } + + /** + * Returns an unmodifiable set containing two elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if the elements are duplicates + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2) { + return new ImmutableCollections.Set12<>(e1, e2); + } + + /** + * Returns an unmodifiable set containing three elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3) { + return new ImmutableCollections.SetN<>(e1, e2, e3); + } + + /** + * Returns an unmodifiable set containing four elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4); + } + + /** + * Returns an unmodifiable set containing five elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5); + } + + /** + * Returns an unmodifiable set containing six elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6); + } + + /** + * Returns an unmodifiable set containing seven elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7); + } + + /** + * Returns an unmodifiable set containing eight elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @param e8 the eighth element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7, e8); + } + + /** + * Returns an unmodifiable set containing nine elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @param e8 the eighth element + * @param e9 the ninth element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9); + } + + /** + * Returns an unmodifiable set containing ten elements. + * See Unmodifiable Sets for details. + * + * @param the {@code Set}'s element type + * @param e1 the first element + * @param e2 the second element + * @param e3 the third element + * @param e4 the fourth element + * @param e5 the fifth element + * @param e6 the sixth element + * @param e7 the seventh element + * @param e8 the eighth element + * @param e9 the ninth element + * @param e10 the tenth element + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} + * + * @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) { + return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10); + } + + /** + * Returns an unmodifiable set containing an arbitrary number of elements. + * See Unmodifiable Sets for details. + * + * @apiNote + * This method also accepts a single array as an argument. The element type of + * the resulting set will be the component type of the array, and the size of + * the set will be equal to the length of the array. To create a set with + * a single element that is an array, do the following: + * + *

      {@code
      +     *     String[] array = ... ;
      +     *     Set list = Set.of(array);
      +     * }
      + * + * This will cause the {@link Set#of(Object) Set.of(E)} method + * to be invoked instead. + * + * @param the {@code Set}'s element type + * @param elements the elements to be contained in the set + * @return a {@code Set} containing the specified elements + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is {@code null} or if the array is {@code null} + * + * @since 9 + */ + @SafeVarargs + @SuppressWarnings("varargs") + static Set of(E... elements) { + switch (elements.length) { // implicit null check of elements + case 0: + return ImmutableCollections.emptySet(); + case 1: + return new ImmutableCollections.Set12<>(elements[0]); + case 2: + return new ImmutableCollections.Set12<>(elements[0], elements[1]); + default: + return new ImmutableCollections.SetN<>(elements); + } + } + + /** + * Returns an unmodifiable Set containing the elements + * of the given Collection. The given Collection must not be null, and it must not + * contain any null elements. If the given Collection contains duplicate elements, + * an arbitrary element of the duplicates is preserved. If the given Collection is + * subsequently modified, the returned Set will not reflect such modifications. + * + * @implNote + * If the given Collection is an unmodifiable Set, + * calling copyOf will generally not create a copy. + * + * @param the {@code Set}'s element type + * @param coll a {@code Collection} from which elements are drawn, must be non-null + * @return a {@code Set} containing the elements of the given {@code Collection} + * @throws NullPointerException if coll is null, or if it contains any nulls + * @since 10 + */ + @SuppressWarnings("unchecked") + static Set copyOf(Collection coll) { + if (coll instanceof ImmutableCollections.AbstractImmutableSet) { + return (Set)coll; + } else { + return (Set)Set.of(new HashSet<>(coll).toArray()); + } + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SimpleTimeZone.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SimpleTimeZone.java index ef70b960ee..d72594e7a2 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SimpleTimeZone.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SimpleTimeZone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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 @@ -41,13 +41,14 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.IOException; +import java.io.InvalidObjectException; import sun.util.calendar.CalendarSystem; import sun.util.calendar.CalendarUtils; import sun.util.calendar.BaseCalendar; import sun.util.calendar.Gregorian; /** - * SimpleTimeZone is a concrete subclass of TimeZone + * {@code SimpleTimeZone} is a concrete subclass of {@code TimeZone} * that represents a time zone for use with a Gregorian calendar. * The class holds an offset from GMT, called raw offset, and start * and end rules for a daylight saving time schedule. Since it only holds @@ -56,7 +57,7 @@ * #setStartYear setStartYear} method can specify the year when the daylight * saving time schedule starts in effect. *

      - * To construct a SimpleTimeZone with a daylight saving time + * To construct a {@code SimpleTimeZone} with a daylight saving time * schedule, the schedule can be described with a set of rules, * start-rule and end-rule. A day when daylight saving time * starts or ends is specified by a combination of month, @@ -80,7 +81,7 @@ * or after which the rule is applied, and day-of-week to a negative {@link * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the * second Sunday of April, set month to {@link Calendar#APRIL APRIL}, - * day-of-month to 8, and day-of-week to -{@link + * day-of-month to 8, and day-of-week to {@code -}{@link * Calendar#SUNDAY SUNDAY}.

    • * *
    • Day of week on or before day of month
      @@ -88,7 +89,7 @@ * day-of-month and day-of-week to a negative value. For * example, to specify the last Wednesday on or before the 21st of March, set * month to {@link Calendar#MARCH MARCH}, day-of-month is -21 - * and day-of-week is -{@link Calendar#WEDNESDAY WEDNESDAY}.
    • + * and day-of-week is {@code -}{@link Calendar#WEDNESDAY WEDNESDAY}. * *
    • Last day-of-week of month
      * To specify, the last day-of-week of the month, set day-of-week to a @@ -138,7 +139,7 @@ * 3600000) * * These parameter rules are also applicable to the set rule methods, such as - * setStartRule. + * {@code setStartRule}. * * @since 1.1 * @see Calendar @@ -166,7 +167,7 @@ public SimpleTimeZone(int rawOffset, String ID) * Constructs a SimpleTimeZone with the given base time zone offset from * GMT, time zone ID, and rules for starting and ending the daylight * time. - * Both startTime and endTime are specified to be + * Both {@code startTime} and {@code endTime} are specified to be * represented in the wall clock time. The amount of daylight saving is * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is * equivalent to: @@ -208,7 +209,7 @@ public SimpleTimeZone(int rawOffset, String ID) * @param endTime The daylight saving ending time in local wall clock time, * (in milliseconds within the day) which is local daylight * time in this case. - * @exception IllegalArgumentException if the month, day, dayOfWeek, or time + * @throws IllegalArgumentException if the month, day, dayOfWeek, or time * parameters are out of range for the start or end rule */ public SimpleTimeZone(int rawOffset, String ID, @@ -225,7 +226,7 @@ public SimpleTimeZone(int rawOffset, String ID, * Constructs a SimpleTimeZone with the given base time zone offset from * GMT, time zone ID, and rules for starting and ending the daylight * time. - * Both startTime and endTime are assumed to be + * Both {@code startTime} and {@code endTime} are assumed to be * represented in the wall clock time. This constructor is equivalent to: *
      
            *     SimpleTimeZone(rawOffset,
      @@ -265,7 +266,7 @@ public SimpleTimeZone(int rawOffset, String ID,
            *                        which is local daylight time in this case.
            * @param dstSavings      The amount of time in milliseconds saved during
            *                        daylight saving time.
      -     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
      +     * @throws    IllegalArgumentException if the month, day, dayOfWeek, or time
            * parameters are out of range for the start or end rule
            * @since 1.2
            */
      @@ -285,8 +286,8 @@ public SimpleTimeZone(int rawOffset, String ID,
            * GMT, time zone ID, and rules for starting and ending the daylight
            * time.
            * This constructor takes the full set of the start and end rules
      -     * parameters, including modes of startTime and
      -     * endTime. The mode specifies either {@link #WALL_TIME wall
      +     * parameters, including modes of {@code startTime} and
      +     * {@code endTime}. The mode specifies either {@link #WALL_TIME wall
            * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
            * time}.
            *
      @@ -300,7 +301,7 @@ public SimpleTimeZone(int rawOffset, String ID,
            * @param startDayOfWeek  The daylight saving time starting day-of-week.
            *                        See the class description for the special cases of this parameter.
            * @param startTime       The daylight saving time starting time in the time mode
      -     *                        specified by startTimeMode.
      +     *                        specified by {@code startTimeMode}.
            * @param startTimeMode   The mode of the start time specified by startTime.
            * @param endMonth        The daylight saving time ending month. Month is
            *                        a {@link Calendar#MONTH MONTH} field
      @@ -309,13 +310,13 @@ public SimpleTimeZone(int rawOffset, String ID,
            *                        See the class description for the special cases of this parameter.
            * @param endDayOfWeek    The daylight saving time ending day-of-week.
            *                        See the class description for the special cases of this parameter.
      -     * @param endTime         The daylight saving ending time in time time mode
      -     *                        specified by endTimeMode.
      +     * @param endTime         The daylight saving ending time in time mode
      +     *                        specified by {@code endTimeMode}.
            * @param endTimeMode     The mode of the end time specified by endTime
            * @param dstSavings      The amount of time in milliseconds saved during
            *                        daylight saving time.
            *
      -     * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
      +     * @throws    IllegalArgumentException if the month, day, dayOfWeek, time more, or
            * time parameters are out of range for the start or end rule, or if a time mode
            * value is invalid.
            *
      @@ -368,7 +369,7 @@ public void setStartYear(int year)
            * Sets the daylight saving time start rule. For example, if daylight saving
            * time starts on the first Sunday in April at 2 am in local wall clock
            * time, you can set the start rule by calling:
      -     * 
      setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);
      + *
      {@code setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);}
      * * @param startMonth The daylight saving time starting month. Month is * a {@link Calendar#MONTH MONTH} field @@ -379,8 +380,8 @@ public void setStartYear(int year) * See the class description for the special cases of this parameter. * @param startTime The daylight saving time starting time in local wall clock * time, which is local standard time in this case. - * @exception IllegalArgumentException if the startMonth, startDay, - * startDayOfWeek, or startTime parameters are out of range + * @throws IllegalArgumentException if the {@code startMonth}, {@code startDay}, + * {@code startDayOfWeek}, or {@code startTime} parameters are out of range */ public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime) { @@ -396,7 +397,7 @@ public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int s /** * Sets the daylight saving time start rule to a fixed date within a month. * This method is equivalent to: - *
      setStartRule(startMonth, startDay, 0, startTime)
      + *
      {@code setStartRule(startMonth, startDay, 0, startTime)}
      * * @param startMonth The daylight saving time starting month. Month is * a {@link Calendar#MONTH MONTH} field @@ -405,8 +406,8 @@ public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int s * @param startTime The daylight saving time starting time in local wall clock * time, which is local standard time in this case. * See the class description for the special cases of this parameter. - * @exception IllegalArgumentException if the startMonth, - * startDayOfMonth, or startTime parameters are out of range + * @throws IllegalArgumentException if the {@code startMonth}, + * {@code startDayOfMonth}, or {@code startTime} parameters are out of range * @since 1.2 */ public void setStartRule(int startMonth, int startDay, int startTime) { @@ -424,12 +425,12 @@ public void setStartRule(int startMonth, int startDay, int startTime) { * @param startDayOfWeek The daylight saving time starting day-of-week. * @param startTime The daylight saving time starting time in local wall clock * time, which is local standard time in this case. - * @param after If true, this rule selects the first dayOfWeek on or - * after dayOfMonth. If false, this rule - * selects the last dayOfWeek on or before - * dayOfMonth. - * @exception IllegalArgumentException if the startMonth, startDay, - * startDayOfWeek, or startTime parameters are out of range + * @param after If true, this rule selects the first {@code dayOfWeek} on or + * after {@code dayOfMonth}. If false, this rule + * selects the last {@code dayOfWeek} on or before + * {@code dayOfMonth}. + * @throws IllegalArgumentException if the {@code startMonth}, {@code startDay}, + * {@code startDayOfWeek}, or {@code startTime} parameters are out of range * @since 1.2 */ public void setStartRule(int startMonth, int startDay, int startDayOfWeek, @@ -447,7 +448,7 @@ public void setStartRule(int startMonth, int startDay, int startDayOfWeek, * Sets the daylight saving time end rule. For example, if daylight saving time * ends on the last Sunday in October at 2 am in wall clock time, * you can set the end rule by calling: - * setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000); + * {@code setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);} * * @param endMonth The daylight saving time ending month. Month is * a {@link Calendar#MONTH MONTH} field @@ -459,8 +460,8 @@ public void setStartRule(int startMonth, int startDay, int startDayOfWeek, * @param endTime The daylight saving ending time in local wall clock time, * (in milliseconds within the day) which is local daylight * time in this case. - * @exception IllegalArgumentException if the endMonth, endDay, - * endDayOfWeek, or endTime parameters are out of range + * @throws IllegalArgumentException if the {@code endMonth}, {@code endDay}, + * {@code endDayOfWeek}, or {@code endTime} parameters are out of range */ public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime) @@ -477,7 +478,7 @@ public void setEndRule(int endMonth, int endDay, int endDayOfWeek, /** * Sets the daylight saving time end rule to a fixed date within a month. * This method is equivalent to: - *
      setEndRule(endMonth, endDay, 0, endTime)
      + *
      {@code setEndRule(endMonth, endDay, 0, endTime)}
      * * @param endMonth The daylight saving time ending month. Month is * a {@link Calendar#MONTH MONTH} field @@ -486,8 +487,8 @@ public void setEndRule(int endMonth, int endDay, int endDayOfWeek, * @param endTime The daylight saving ending time in local wall clock time, * (in milliseconds within the day) which is local daylight * time in this case. - * @exception IllegalArgumentException the endMonth, endDay, - * or endTime parameters are out of range + * @throws IllegalArgumentException the {@code endMonth}, {@code endDay}, + * or {@code endTime} parameters are out of range * @since 1.2 */ public void setEndRule(int endMonth, int endDay, int endTime) @@ -507,12 +508,12 @@ public void setEndRule(int endMonth, int endDay, int endTime) * @param endTime The daylight saving ending time in local wall clock time, * (in milliseconds within the day) which is local daylight * time in this case. - * @param after If true, this rule selects the first endDayOfWeek on - * or after endDay. If false, this rule - * selects the last endDayOfWeek on or before - * endDay of the month. - * @exception IllegalArgumentException the endMonth, endDay, - * endDayOfWeek, or endTime parameters are out of range + * @param after If true, this rule selects the first {@code endDayOfWeek} on + * or after {@code endDay}. If false, this rule + * selects the last {@code endDayOfWeek} on or before + * {@code endDay} of the month. + * @throws IllegalArgumentException the {@code endMonth}, {@code endDay}, + * {@code endDayOfWeek}, or {@code endTime} parameters are out of range * @since 1.2 */ public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after) @@ -547,12 +548,11 @@ int getOffsets(long date, int[] offsets) { computeOffset: if (useDaylight) { - synchronized (this) { - if (cacheStart != 0) { - if (date >= cacheStart && date < cacheEnd) { - offset += dstSavings; - break computeOffset; - } + Cache cache = this.cache; + if (cache != null) { + if (date >= cache.start && date < cache.end) { + offset += dstSavings; + break computeOffset; } } BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ? @@ -575,7 +575,7 @@ int getOffsets(long date, int[] offsets) { return offset; } - /** + /** * Returns the difference in milliseconds between local time and * UTC, taking into account both the raw offset and the effect of * daylight saving, for the specified date and time. This method @@ -583,10 +583,10 @@ int getOffsets(long date, int[] offsets) { * uses a default {@link GregorianCalendar} object as its * underlying calendar, such as for determining leap years. Do * not use the result of this method with a calendar other than a - * default GregorianCalendar. + * default {@code GregorianCalendar}. * *

      Note: In general, clients should use - * Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET) + * {@code Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)} * instead of calling this method. * * @param era The era of the given date. @@ -597,9 +597,9 @@ int getOffsets(long date, int[] offsets) { * @param dayOfWeek The day-of-week of the given date. * @param millis The milliseconds in day in standard local time. * @return The milliseconds to add to UTC to get local time. - * @exception IllegalArgumentException the era, - * month, day, dayOfWeek, - * or millis parameters are out of range + * @throws IllegalArgumentException the {@code era}, + * {@code month}, {@code day}, {@code dayOfWeek}, + * or {@code millis} parameters are out of range */ public int getOffset(int era, int year, int month, int day, int dayOfWeek, int millis) @@ -670,14 +670,13 @@ public int getOffset(int era, int year, int month, int day, int dayOfWeek, } private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) { - synchronized (this) { - if (cacheStart != 0) { - if (time >= cacheStart && time < cacheEnd) { - return rawOffset + dstSavings; - } - if (year == cacheYear) { - return rawOffset; - } + Cache cache = this.cache; + if (cache != null) { + if (time >= cache.start && time < cache.end) { + return rawOffset + dstSavings; + } + if (year == cache.year) { + return rawOffset; } } @@ -688,11 +687,7 @@ private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long if (time >= start && time < end) { offset += dstSavings; } - synchronized (this) { - cacheYear = year; - cacheStart = start; - cacheEnd = end; - } + this.cache = new Cache(year, start, end); } else { if (time < end) { // TODO: support Gregorian cutover. The previous year @@ -710,12 +705,7 @@ private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long } } if (start <= end) { - synchronized (this) { - // The start and end transitions are in multiple years. - cacheYear = (long) startYear - 1; - cacheStart = start; - cacheEnd = end; - } + this.cache = new Cache((long) startYear - 1, start, end); } } return offset; @@ -748,6 +738,25 @@ private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate, cdate.setNormalizedYear(year); cdate.setMonth(month + 1); switch (mode) { + // Android-changed: instanceof pattern variable is not yet supported + /* + case DOM_MODE -> cdate.setDayOfMonth(dayOfMonth); + case DOW_IN_MONTH_MODE -> { + cdate.setDayOfMonth(1); + if (dayOfMonth < 0) { + cdate.setDayOfMonth(cal.getMonthLength(cdate)); + } + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate); + } + case DOW_GE_DOM_MODE -> { + cdate.setDayOfMonth(dayOfMonth); + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate); + } + case DOW_LE_DOM_MODE -> { + cdate.setDayOfMonth(dayOfMonth); + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate); + } + */ case DOM_MODE: cdate.setDayOfMonth(dayOfMonth); break; @@ -863,7 +872,7 @@ public boolean inDaylightTime(Date date) } /** - * Returns a clone of this SimpleTimeZone instance. + * Returns a clone of this {@code SimpleTimeZone} instance. * @return a clone of this instance. */ public Object clone() @@ -875,24 +884,30 @@ public Object clone() * Generates the hash code for the SimpleDateFormat object. * @return the hash code for this object */ - public synchronized int hashCode() + public int hashCode() { return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset; } /** - * Compares the equality of two SimpleTimeZone objects. + * Compares the equality of two {@code SimpleTimeZone} objects. * - * @param obj The SimpleTimeZone object to be compared with. - * @return True if the given obj is the same as this - * SimpleTimeZone object; false otherwise. + * @param obj The {@code SimpleTimeZone} object to be compared with. + * @return True if the given {@code obj} is the same as this + * {@code SimpleTimeZone} object; false otherwise. */ - public boolean equals(Object obj) - { + public boolean equals(Object obj) { if (this == obj) { return true; } + + // Android-changed: instanceof pattern variable is not yet supported. + /* + return obj instanceof SimpleTimeZone that + && getID().equals(that.getID()) + && hasSameRules(that); + */ if (!(obj instanceof SimpleTimeZone)) { return false; } @@ -904,9 +919,9 @@ public boolean equals(Object obj) } /** - * Returns true if this zone has the same rules and offset as another zone. + * Returns {@code true} if this zone has the same rules and offset as another zone. * @param other the TimeZone object to be compared with - * @return true if the given zone is a SimpleTimeZone and has the + * @return {@code true} if the given zone is a SimpleTimeZone and has the * same rules and offset as this one * @since 1.2 */ @@ -914,6 +929,29 @@ public boolean hasSameRules(TimeZone other) { if (this == other) { return true; } + // Android-changed: instanceof pattern variable is not yet supported + /* + return other instanceof SimpleTimeZone that + && rawOffset == that.rawOffset + && useDaylight == that.useDaylight + && (!useDaylight || + // Only check rules if using DST + (dstSavings == that.dstSavings + && startMode == that.startMode + && startMonth == that.startMonth + && startDay == that.startDay + && startDayOfWeek == that.startDayOfWeek + && startTime == that.startTime + && startTimeMode == that.startTimeMode + && endMode == that.endMode + && endMonth == that.endMonth + && endDay == that.endDay + && endDayOfWeek == that.endDayOfWeek + && endTime == that.endTime + && endTimeMode == that.endTimeMode + && startYear == that.startYear) + ); + */ if (!(other instanceof SimpleTimeZone)) { return false; } @@ -967,10 +1005,10 @@ public String toString() { /** * The month in which daylight saving time starts. This value must be - * between Calendar.JANUARY and - * Calendar.DECEMBER inclusive. This value must not equal - * endMonth. - *

      If useDaylight is false, this value is ignored. + * between {@code Calendar.JANUARY} and + * {@code Calendar.DECEMBER} inclusive. This value must not equal + * {@code endMonth}. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int startMonth; @@ -978,34 +1016,34 @@ public String toString() { /** * This field has two possible interpretations: *

      - *
      startMode == DOW_IN_MONTH
      + *
      {@code startMode == DOW_IN_MONTH}
      *
      - * startDay indicates the day of the month of - * startMonth on which daylight + * {@code startDay} indicates the day of the month of + * {@code startMonth} on which daylight * saving time starts, from 1 to 28, 30, or 31, depending on the - * startMonth. + * {@code startMonth}. *
      - *
      startMode != DOW_IN_MONTH
      + *
      {@code startMode != DOW_IN_MONTH}
      *
      - * startDay indicates which startDayOfWeek in the - * month startMonth daylight + * {@code startDay} indicates which {@code startDayOfWeek} in the + * month {@code startMonth} daylight * saving time starts on. For example, a value of +1 and a - * startDayOfWeek of Calendar.SUNDAY indicates the - * first Sunday of startMonth. Likewise, +2 would indicate the + * {@code startDayOfWeek} of {@code Calendar.SUNDAY} indicates the + * first Sunday of {@code startMonth}. Likewise, +2 would indicate the * second Sunday, and -1 the last Sunday. A value of 0 is illegal. *
      *
      - *

      If useDaylight is false, this value is ignored. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int startDay; /** * The day of the week on which daylight saving time starts. This value - * must be between Calendar.SUNDAY and - * Calendar.SATURDAY inclusive. - *

      If useDaylight is false or - * startMode == DAY_OF_MONTH, this value is ignored. + * must be between {@code Calendar.SUNDAY} and + * {@code Calendar.SATURDAY} inclusive. + *

      If {@code useDaylight} is false or + * {@code startMode == DAY_OF_MONTH}, this value is ignored. * @serial */ private int startDayOfWeek; @@ -1013,8 +1051,8 @@ public String toString() { /** * The time in milliseconds after midnight at which daylight saving * time starts. This value is expressed as wall time, standard time, - * or UTC time, depending on the setting of startTimeMode. - *

      If useDaylight is false, this value is ignored. + * or UTC time, depending on the setting of {@code startTimeMode}. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int startTime; @@ -1028,10 +1066,10 @@ public String toString() { /** * The month in which daylight saving time ends. This value must be - * between Calendar.JANUARY and - * Calendar.UNDECIMBER. This value must not equal - * startMonth. - *

      If useDaylight is false, this value is ignored. + * between {@code Calendar.JANUARY} and + * {@code Calendar.UNDECIMBER}. This value must not equal + * {@code startMonth}. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int endMonth; @@ -1039,34 +1077,34 @@ public String toString() { /** * This field has two possible interpretations: *

      - *
      endMode == DOW_IN_MONTH
      + *
      {@code endMode == DOW_IN_MONTH}
      *
      - * endDay indicates the day of the month of - * endMonth on which daylight + * {@code endDay} indicates the day of the month of + * {@code endMonth} on which daylight * saving time ends, from 1 to 28, 30, or 31, depending on the - * endMonth. + * {@code endMonth}. *
      - *
      endMode != DOW_IN_MONTH
      + *
      {@code endMode != DOW_IN_MONTH}
      *
      - * endDay indicates which endDayOfWeek in th - * month endMonth daylight + * {@code endDay} indicates which {@code endDayOfWeek} in th + * month {@code endMonth} daylight * saving time ends on. For example, a value of +1 and a - * endDayOfWeek of Calendar.SUNDAY indicates the - * first Sunday of endMonth. Likewise, +2 would indicate the + * {@code endDayOfWeek} of {@code Calendar.SUNDAY} indicates the + * first Sunday of {@code endMonth}. Likewise, +2 would indicate the * second Sunday, and -1 the last Sunday. A value of 0 is illegal. *
      *
      - *

      If useDaylight is false, this value is ignored. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int endDay; /** * The day of the week on which daylight saving time ends. This value - * must be between Calendar.SUNDAY and - * Calendar.SATURDAY inclusive. - *

      If useDaylight is false or - * endMode == DAY_OF_MONTH, this value is ignored. + * must be between {@code Calendar.SUNDAY} and + * {@code Calendar.SATURDAY} inclusive. + *

      If {@code useDaylight} is false or + * {@code endMode == DAY_OF_MONTH}, this value is ignored. * @serial */ private int endDayOfWeek; @@ -1074,15 +1112,15 @@ public String toString() { /** * The time in milliseconds after midnight at which daylight saving * time ends. This value is expressed as wall time, standard time, - * or UTC time, depending on the setting of endTimeMode. - *

      If useDaylight is false, this value is ignored. + * or UTC time, depending on the setting of {@code endTimeMode}. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int endTime; /** - * The format of endTime, either WALL_TIME, - * STANDARD_TIME, or UTC_TIME. + * The format of endTime, either {@code WALL_TIME}, + * {@code STANDARD_TIME}, or {@code UTC_TIME}. * @serial * @since 1.3 */ @@ -1091,8 +1129,8 @@ public String toString() { /** * The year in which daylight saving time is first observed. This is an {@link GregorianCalendar#AD AD} * value. If this value is less than 1 then daylight saving time is observed - * for all AD years. - *

      If useDaylight is false, this value is ignored. + * for all {@code AD} years. + *

      If {@code useDaylight} is false, this value is ignored. * @serial */ private int startYear; @@ -1101,7 +1139,7 @@ public String toString() { * The offset in milliseconds between this zone and GMT. Negative offsets * are to the west of Greenwich. To obtain local standard time, * add the offset to GMT time. To obtain local wall time it may also be - * necessary to add dstSavings. + * necessary to add {@code dstSavings}. * @serial */ private int rawOffset; @@ -1125,33 +1163,33 @@ public String toString() { * be streamed out for compatibility with JDK 1.1. */ private final byte monthLength[] = staticMonthLength; - private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31}; - private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31}; + private static final byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31}; + private static final byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31}; /** * Variables specifying the mode of the start rule. Takes the following * values: *

      - *
      DOM_MODE
      + *
      {@code DOM_MODE}
      *
      * Exact day of week; e.g., March 1. *
      - *
      DOW_IN_MONTH_MODE
      + *
      {@code DOW_IN_MONTH_MODE}
      *
      * Day of week in month; e.g., last Sunday in March. *
      - *
      DOW_GE_DOM_MODE
      + *
      {@code DOW_GE_DOM_MODE}
      *
      * Day of week after day of month; e.g., Sunday on or after March 15. *
      - *
      DOW_LE_DOM_MODE
      + *
      {@code DOW_LE_DOM_MODE}
      *
      * Day of week before day of month; e.g., Sunday on or before March 15. *
      *
      * The setting of this field affects the interpretation of the - * startDay field. - *

      If useDaylight is false, this value is ignored. + * {@code startDay} field. + *

      If {@code useDaylight} is false, this value is ignored. * @serial * @since 1.1.4 */ @@ -1161,26 +1199,26 @@ public String toString() { * Variables specifying the mode of the end rule. Takes the following * values: *

      - *
      DOM_MODE
      + *
      {@code DOM_MODE}
      *
      * Exact day of week; e.g., March 1. *
      - *
      DOW_IN_MONTH_MODE
      + *
      {@code DOW_IN_MONTH_MODE}
      *
      * Day of week in month; e.g., last Sunday in March. *
      - *
      DOW_GE_DOM_MODE
      + *
      {@code DOW_GE_DOM_MODE}
      *
      * Day of week after day of month; e.g., Sunday on or after March 15. *
      - *
      DOW_LE_DOM_MODE
      + *
      {@code DOW_LE_DOM_MODE}
      *
      * Day of week before day of month; e.g., Sunday on or before March 15. *
      *
      * The setting of this field affects the interpretation of the - * endDay field. - *

      If useDaylight is false, this value is ignored. + * {@code endDay} field. + *

      If {@code useDaylight} is false, this value is ignored. * @serial * @since 1.1.4 */ @@ -1190,7 +1228,7 @@ public String toString() { * A positive value indicating the amount of time saved during DST in * milliseconds. * Typically one hour (3600000); sometimes 30 minutes (1800000). - *

      If useDaylight is false, this value is ignored. + *

      If {@code useDaylight} is false, this value is ignored. * @serial * @since 1.1.4 */ @@ -1200,19 +1238,27 @@ public String toString() { /** * Cache values representing a single period of daylight saving - * time. When the cache values are valid, cacheStart is the start - * time (inclusive) of daylight saving time and cacheEnd is the - * end time (exclusive). + * time. Cache.start is the start time (inclusive) of daylight + * saving time and Cache.end is the end time (exclusive). * - * cacheYear has a year value if both cacheStart and cacheEnd are - * in the same year. cacheYear is set to startYear - 1 if - * cacheStart and cacheEnd are in different years. cacheStart is 0 - * if the cache values are void. cacheYear is a long to support - * Integer.MIN_VALUE - 1 (JCK requirement). + * Cache.year has a year value if both Cache.start and Cache.end are + * in the same year. Cache.year is set to startYear - 1 if + * Cache.start and Cache.end are in different years. + * Cache.year is a long to support Integer.MIN_VALUE - 1 (JCK requirement). */ - private transient long cacheYear; - private transient long cacheStart; - private transient long cacheEnd; + private static final class Cache { + final long year; + final long start; + final long end; + + Cache(long year, long start, long end) { + this.year = year; + this.start = start; + this.end = end; + } + } + + private transient volatile Cache cache; /** * Constants specifying values of startMode and endMode. @@ -1244,6 +1290,7 @@ public String toString() { public static final int UTC_TIME = 2; // Proclaim compatibility with 1.1 + @java.io.Serial static final long serialVersionUID = -403250971215465050L; // the internal serial version which says which version was written @@ -1261,26 +1308,28 @@ public String toString() { * *

      1
      *
      - * JDK 1.1.4 or later. Includes three new fields: startMode, - * endMode, and dstSavings. + * JDK 1.1.4 or later. Includes three new fields: {@code startMode}, + * {@code endMode}, and {@code dstSavings}. *
      *
      2
      *
      - * JDK 1.3 or later. Includes two new fields: startTimeMode - * and endTimeMode. + * JDK 1.3 or later. Includes two new fields: {@code startTimeMode} + * and {@code endTimeMode}. *
      * * When streaming out this class, the most recent format - * and the highest allowable serialVersionOnStream + * and the highest allowable {@code serialVersionOnStream} * is written. * @serial * @since 1.1.4 */ private int serialVersionOnStream = currentSerialVersion; - synchronized private void invalidateCache() { - cacheYear = startYear - 1; - cacheStart = cacheEnd = 0; + // Maximum number of rules. + private static final int MAX_RULE_NUM = 6; + + private void invalidateCache() { + cache = null; } //---------------------------------------------------------------------- @@ -1533,6 +1582,8 @@ private void makeRulesCompatible() * rules anyway. */ switch (startTimeMode) { + // Android-change: instanceof pattern variable is not yet supported + // case UTC_TIME -> startTime += rawOffset; case UTC_TIME: startTime += rawOffset; break; @@ -1547,6 +1598,9 @@ private void makeRulesCompatible() } switch (endTimeMode) { + // Android-change: instanceof pattern variable is not yet supported + // case UTC_TIME -> endTime += rawOffset + dstSavings; + // case STANDARD_TIME -> endTime += dstSavings; case UTC_TIME: endTime += rawOffset + dstSavings; break; @@ -1569,7 +1623,7 @@ private void makeRulesCompatible() */ private byte[] packRules() { - byte[] rules = new byte[6]; + byte[] rules = new byte[MAX_RULE_NUM]; rules[0] = (byte)startDay; rules[1] = (byte)startDayOfWeek; rules[2] = (byte)endDay; @@ -1594,7 +1648,7 @@ private void unpackRules(byte[] rules) endDayOfWeek = rules[3]; // As of serial version 2, include time modes - if (rules.length >= 6) { + if (rules.length >= MAX_RULE_NUM) { startTimeMode = rules[4]; endTimeMode = rules[5]; } @@ -1624,18 +1678,19 @@ private void unpackTimes(int[] times) { * Save the state of this object to a stream (i.e., serialize it). * * @serialData We write out two formats, a JDK 1.1 compatible format, using - * DOW_IN_MONTH_MODE rules, in the required section, followed + * {@code DOW_IN_MONTH_MODE} rules, in the required section, followed * by the full rules, in packed format, in the optional section. The * optional section will be ignored by JDK 1.1 code upon stream in. *

      Contents of the optional section: The length of a byte array is * emitted (int); this is 4 as of this release. The byte array of the given * length is emitted. The contents of the byte array are the true values of - * the fields startDay, startDayOfWeek, - * endDay, and endDayOfWeek. The values of these + * the fields {@code startDay}, {@code startDayOfWeek}, + * {@code endDay}, and {@code endDayOfWeek}. The values of these * fields in the required section are approximate values suited to the rule - * mode DOW_IN_MONTH_MODE, which is the only mode recognized by + * mode {@code DOW_IN_MONTH_MODE}, which is the only mode recognized by * JDK 1.1. */ + @java.io.Serial private void writeObject(ObjectOutputStream stream) throws IOException { @@ -1666,6 +1721,7 @@ private void writeObject(ObjectOutputStream stream) * We handle both JDK 1.1 * binary formats and full formats with a packed byte array. */ + @java.io.Serial private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { @@ -1691,9 +1747,13 @@ private void readObject(ObjectInputStream stream) // store the actual rules (which have not be made compatible with 1.1) // in the optional area. Read them in here and parse them. int length = stream.readInt(); - byte[] rules = new byte[length]; - stream.readFully(rules); - unpackRules(rules); + if (length <= MAX_RULE_NUM) { + byte[] rules = new byte[length]; + stream.readFully(rules); + unpackRules(rules); + } else { + throw new InvalidObjectException("Too many rules: " + length); + } } if (serialVersionOnStream >= 2) { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedMap.java index 7f98152253..77553bcc57 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ -93,7 +93,7 @@ * SortedMap<String, V> sub = m.subMap(low+"\0", high);

      * *

      This interface is a member of the - * + * * Java Collections Framework. * * @param the type of keys maintained by this map diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedSet.java index 3ea932949a..c3ef264a2a 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/SortedSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ -34,38 +34,38 @@ * to take advantage of the ordering. (This interface is the set * analogue of {@link SortedMap}.) * - *

      All elements inserted into a sorted set must implement the Comparable + *

      All elements inserted into a sorted set must implement the {@code Comparable} * interface (or be accepted by the specified comparator). Furthermore, all - * such elements must be mutually comparable: e1.compareTo(e2) - * (or comparator.compare(e1, e2)) must not throw a - * ClassCastException for any elements e1 and e2 in + * such elements must be mutually comparable: {@code e1.compareTo(e2)} + * (or {@code comparator.compare(e1, e2)}) must not throw a + * {@code ClassCastException} for any elements {@code e1} and {@code e2} in * the sorted set. Attempts to violate this restriction will cause the * offending method or constructor invocation to throw a - * ClassCastException. + * {@code ClassCastException}. * *

      Note that the ordering maintained by a sorted set (whether or not an * explicit comparator is provided) must be consistent with equals if - * the sorted set is to correctly implement the Set interface. (See - * the Comparable interface or Comparator interface for a + * the sorted set is to correctly implement the {@code Set} interface. (See + * the {@code Comparable} interface or {@code Comparator} interface for a * precise definition of consistent with equals.) This is so because - * the Set interface is defined in terms of the equals + * the {@code Set} interface is defined in terms of the {@code equals} * operation, but a sorted set performs all element comparisons using its - * compareTo (or compare) method, so two elements that are + * {@code compareTo} (or {@code compare}) method, so two elements that are * deemed equal by this method are, from the standpoint of the sorted set, * equal. The behavior of a sorted set is well-defined even if its * ordering is inconsistent with equals; it just fails to obey the general - * contract of the Set interface. + * contract of the {@code Set} interface. * *

      All general-purpose sorted set implementation classes should * provide four "standard" constructors: 1) A void (no arguments) * constructor, which creates an empty sorted set sorted according to * the natural ordering of its elements. 2) A constructor with a - * single argument of type Comparator, which creates an empty + * single argument of type {@code Comparator}, which creates an empty * sorted set sorted according to the specified comparator. 3) A - * constructor with a single argument of type Collection, + * constructor with a single argument of type {@code Collection}, * which creates a new sorted set with the same elements as its * argument, sorted according to the natural ordering of the elements. - * 4) A constructor with a single argument of type SortedSet, + * 4) A constructor with a single argument of type {@code SortedSet}, * which creates a new sorted set with the same elements and the same * ordering as the input sorted set. There is no way to enforce this * recommendation, as interfaces cannot contain constructors. @@ -75,21 +75,21 @@ * endpoint but not their high endpoint (where applicable). * If you need a closed range (which includes both endpoints), and * the element type allows for calculation of the successor of a given - * value, merely request the subrange from lowEndpoint to - * successor(highEndpoint). For example, suppose that s + * value, merely request the subrange from {@code lowEndpoint} to + * {@code successor(highEndpoint)}. For example, suppose that {@code s} * is a sorted set of strings. The following idiom obtains a view - * containing all of the strings in s from low to - * high, inclusive:

      + * containing all of the strings in {@code s} from {@code low} to
      + * {@code high}, inclusive:
        *   SortedSet<String> sub = s.subSet(low, high+"\0");
      * * A similar technique can be used to generate an open range (which * contains neither endpoint). The following idiom obtains a view - * containing all of the Strings in s from low to - * high, exclusive:
      + * containing all of the Strings in {@code s} from {@code low} to
      + * {@code high}, exclusive:
        *   SortedSet<String> sub = s.subSet(low+"\0", high);
      * *

      This interface is a member of the - * + * * Java Collections Framework. * * @param the type of elements maintained by this set @@ -108,98 +108,98 @@ public interface SortedSet extends Set { /** * Returns the comparator used to order the elements in this set, - * or null if this set uses the {@linkplain Comparable + * or {@code null} if this set uses the {@linkplain Comparable * natural ordering} of its elements. * * @return the comparator used to order the elements in this set, - * or null if this set uses the natural ordering + * or {@code null} if this set uses the natural ordering * of its elements */ Comparator comparator(); /** * Returns a view of the portion of this set whose elements range - * from fromElement, inclusive, to toElement, - * exclusive. (If fromElement and toElement are + * from {@code fromElement}, inclusive, to {@code toElement}, + * exclusive. (If {@code fromElement} and {@code toElement} are * equal, the returned set is empty.) The returned set is backed * by this set, so changes in the returned set are reflected in * this set, and vice-versa. The returned set supports all * optional set operations that this set supports. * - *

      The returned set will throw an IllegalArgumentException + *

      The returned set will throw an {@code IllegalArgumentException} * on an attempt to insert an element outside its range. * * @param fromElement low endpoint (inclusive) of the returned set * @param toElement high endpoint (exclusive) of the returned set * @return a view of the portion of this set whose elements range from - * fromElement, inclusive, to toElement, exclusive - * @throws ClassCastException if fromElement and - * toElement cannot be compared to one another using this + * {@code fromElement}, inclusive, to {@code toElement}, exclusive + * @throws ClassCastException if {@code fromElement} and + * {@code toElement} cannot be compared to one another using this * set's comparator (or, if the set has no comparator, using * natural ordering). Implementations may, but are not required - * to, throw this exception if fromElement or - * toElement cannot be compared to elements currently in + * to, throw this exception if {@code fromElement} or + * {@code toElement} cannot be compared to elements currently in * the set. - * @throws NullPointerException if fromElement or - * toElement is null and this set does not permit null + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set does not permit null * elements - * @throws IllegalArgumentException if fromElement is - * greater than toElement; or if this set itself - * has a restricted range, and fromElement or - * toElement lies outside the bounds of the range + * @throws IllegalArgumentException if {@code fromElement} is + * greater than {@code toElement}; or if this set itself + * has a restricted range, and {@code fromElement} or + * {@code toElement} lies outside the bounds of the range */ SortedSet subSet(E fromElement, E toElement); /** * Returns a view of the portion of this set whose elements are - * strictly less than toElement. The returned set is + * strictly less than {@code toElement}. The returned set is * backed by this set, so changes in the returned set are * reflected in this set, and vice-versa. The returned set * supports all optional set operations that this set supports. * - *

      The returned set will throw an IllegalArgumentException + *

      The returned set will throw an {@code IllegalArgumentException} * on an attempt to insert an element outside its range. * * @param toElement high endpoint (exclusive) of the returned set * @return a view of the portion of this set whose elements are strictly - * less than toElement - * @throws ClassCastException if toElement is not compatible + * less than {@code toElement} + * @throws ClassCastException if {@code toElement} is not compatible * with this set's comparator (or, if the set has no comparator, - * if toElement does not implement {@link Comparable}). + * if {@code toElement} does not implement {@link Comparable}). * Implementations may, but are not required to, throw this - * exception if toElement cannot be compared to elements + * exception if {@code toElement} cannot be compared to elements * currently in the set. - * @throws NullPointerException if toElement is null and + * @throws NullPointerException if {@code toElement} is null and * this set does not permit null elements * @throws IllegalArgumentException if this set itself has a - * restricted range, and toElement lies outside the + * restricted range, and {@code toElement} lies outside the * bounds of the range */ SortedSet headSet(E toElement); /** * Returns a view of the portion of this set whose elements are - * greater than or equal to fromElement. The returned + * greater than or equal to {@code fromElement}. The returned * set is backed by this set, so changes in the returned set are * reflected in this set, and vice-versa. The returned set * supports all optional set operations that this set supports. * - *

      The returned set will throw an IllegalArgumentException + *

      The returned set will throw an {@code IllegalArgumentException} * on an attempt to insert an element outside its range. * * @param fromElement low endpoint (inclusive) of the returned set * @return a view of the portion of this set whose elements are greater - * than or equal to fromElement - * @throws ClassCastException if fromElement is not compatible + * than or equal to {@code fromElement} + * @throws ClassCastException if {@code fromElement} is not compatible * with this set's comparator (or, if the set has no comparator, - * if fromElement does not implement {@link Comparable}). + * if {@code fromElement} does not implement {@link Comparable}). * Implementations may, but are not required to, throw this - * exception if fromElement cannot be compared to elements + * exception if {@code fromElement} cannot be compared to elements * currently in the set. - * @throws NullPointerException if fromElement is null + * @throws NullPointerException if {@code fromElement} is null * and this set does not permit null elements * @throws IllegalArgumentException if this set itself has a - * restricted range, and fromElement lies outside the + * restricted range, and {@code fromElement} lies outside the * bounds of the range */ SortedSet tailSet(E fromElement); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterator.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterator.java index 995fcfdca5..a53c5cad99 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterator.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterator.java @@ -62,7 +62,7 @@ * New characteristics may be defined in the future, so implementors should not * assign meanings to unlisted values. * - *

      A Spliterator that does not report {@code IMMUTABLE} or + *

      A Spliterator that does not report {@code IMMUTABLE} or * {@code CONCURRENT} is expected to have a documented policy concerning: * when the spliterator binds to the element source; and detection of * structural interference of the element source detected after binding. A @@ -84,7 +84,7 @@ * via the {@link #estimateSize} method. Ideally, as reflected in characteristic * {@link #SIZED}, this value corresponds exactly to the number of elements * that would be encountered in a successful traversal. However, even when not - * exactly known, an estimated value value may still be useful to operations + * exactly known, an estimated value may still be useful to operations * being performed on the source, such as helping to determine whether it is * preferable to split further or traverse the remaining elements sequentially. * @@ -553,6 +553,12 @@ default Comparator getComparator() { * sub-split size is known and additions or removals to the source are not * reflected when traversing. * + *

      A top-level Spliterator should not report both {@code CONCURRENT} and + * {@code IMMUTABLE}, since they are mutually exclusive. Such a Spliterator + * is inconsistent and no guarantees can be made about any computation using + * that Spliterator. Sub-spliterators may report {@code IMMUTABLE} if + * additions or removals to the source are not reflected when traversing. + * * @apiNote Most concurrent collections maintain a consistency policy * guaranteeing accuracy with respect to elements present at the point of * Spliterator construction, but possibly not reflecting subsequent diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterators.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterators.java index 79c0ef3efd..3b5fe86053 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterators.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Spliterators.java @@ -132,7 +132,7 @@ public static Spliterator.OfDouble emptyDoubleSpliterator() { * @param array The array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @see Arrays#spliterator(Object[]) @@ -164,7 +164,7 @@ public static Spliterator spliterator(Object[] array, * @param toIndex One past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, @@ -196,7 +196,7 @@ public static Spliterator spliterator(Object[] array, int fromIndex, int * @param array The array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @see Arrays#spliterator(int[]) @@ -226,7 +226,7 @@ public static Spliterator.OfInt spliterator(int[] array, * @param toIndex One past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, @@ -258,7 +258,7 @@ public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIn * @param array The array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @see Arrays#spliterator(long[]) @@ -282,7 +282,7 @@ public static Spliterator.OfLong spliterator(long[] array, * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional * characteristics for the spliterator to report. (For example, if it is * known the array will not be further modified, specify {@code IMMUTABLE}; - * if the array data is considered to have an an encounter order, specify + * if the array data is considered to have an encounter order, specify * {@code ORDERED}). The method {@link Arrays#spliterator(long[], int, int)} can * often be used instead, which returns a spliterator that reports * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}. @@ -292,7 +292,7 @@ public static Spliterator.OfLong spliterator(long[] array, * @param toIndex One past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, @@ -324,7 +324,7 @@ public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int to * @param array The array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @see Arrays#spliterator(double[]) @@ -348,7 +348,7 @@ public static Spliterator.OfDouble spliterator(double[] array, * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional * characteristics for the spliterator to report. (For example, if it is * known the array will not be further modified, specify {@code IMMUTABLE}; - * if the array data is considered to have an an encounter order, specify + * if the array data is considered to have an encounter order, specify * {@code ORDERED}). The method {@link Arrays#spliterator(long[], int, int)} can * often be used instead, which returns a spliterator that reports * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}. @@ -358,7 +358,7 @@ public static Spliterator.OfDouble spliterator(double[] array, * @param toIndex One past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported * @return A spliterator for an array * @throws NullPointerException if the given array is {@code null} * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, @@ -833,7 +833,7 @@ public double nextDouble() { // Implementations - private static abstract class EmptySpliterator, C> { + private abstract static class EmptySpliterator, C> { EmptySpliterator() { } @@ -907,7 +907,7 @@ static final class ArraySpliterator implements Spliterator { * @param array the array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public ArraySpliterator(Object[] array, int additionalCharacteristics) { this(array, 0, array.length, additionalCharacteristics); @@ -920,7 +920,7 @@ public ArraySpliterator(Object[] array, int additionalCharacteristics) { * @param fence one past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public ArraySpliterator(Object[] array, int origin, int fence, int additionalCharacteristics) { this.array = array; @@ -992,7 +992,7 @@ static final class IntArraySpliterator implements Spliterator.OfInt { * @param array the array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public IntArraySpliterator(int[] array, int additionalCharacteristics) { this(array, 0, array.length, additionalCharacteristics); @@ -1005,7 +1005,7 @@ public IntArraySpliterator(int[] array, int additionalCharacteristics) { * @param fence one past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) { this.array = array; @@ -1075,7 +1075,7 @@ static final class LongArraySpliterator implements Spliterator.OfLong { * @param array the array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public LongArraySpliterator(long[] array, int additionalCharacteristics) { this(array, 0, array.length, additionalCharacteristics); @@ -1088,7 +1088,7 @@ public LongArraySpliterator(long[] array, int additionalCharacteristics) { * @param fence one past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public LongArraySpliterator(long[] array, int origin, int fence, int additionalCharacteristics) { this.array = array; @@ -1158,7 +1158,7 @@ static final class DoubleArraySpliterator implements Spliterator.OfDouble { * @param array the array, assumed to be unmodified during use * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public DoubleArraySpliterator(double[] array, int additionalCharacteristics) { this(array, 0, array.length, additionalCharacteristics); @@ -1171,7 +1171,7 @@ public DoubleArraySpliterator(double[] array, int additionalCharacteristics) { * @param fence one past the greatest index to cover * @param additionalCharacteristics Additional spliterator characteristics * of this spliterator's source or elements beyond {@code SIZED} and - * {@code SUBSIZED} which are are always reported + * {@code SUBSIZED} which are always reported */ public DoubleArraySpliterator(double[] array, int origin, int fence, int additionalCharacteristics) { this.array = array; @@ -1235,8 +1235,8 @@ public Comparator getComparator() { *

      An extending class need only * implement {@link #tryAdvance(java.util.function.Consumer) tryAdvance}. * The extending class should override - * {@link #forEachRemaining(java.util.function.Consumer) forEach} if it can - * provide a more performant implementation. + * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining} + * if it can provide a more performant implementation. * * @apiNote * This class is a useful aid for creating a spliterator when it is not @@ -1253,7 +1253,7 @@ public Comparator getComparator() { * @see #spliterator(Iterator, long, int) * @since 1.8 */ - public static abstract class AbstractSpliterator implements Spliterator { + public abstract static class AbstractSpliterator implements Spliterator { static final int BATCH_UNIT = 1 << 10; // batch array size increment static final int MAX_BATCH = 1 << 25; // max batch array size; private final int characteristics; @@ -1356,10 +1356,10 @@ public int characteristics() { * permit limited parallelism. * *

      To implement a spliterator an extending class need only - * implement {@link #tryAdvance(java.util.function.IntConsumer)} + * implement {@link #tryAdvance(java.util.function.IntConsumer) * tryAdvance}. The extending class should override - * {@link #forEachRemaining(java.util.function.IntConsumer)} forEach} if it - * can provide a more performant implementation. + * {@link #forEachRemaining(java.util.function.IntConsumer) forEachRemaining} + * if it can provide a more performant implementation. * * @apiNote * This class is a useful aid for creating a spliterator when it is not @@ -1376,7 +1376,7 @@ public int characteristics() { * @see #spliterator(java.util.PrimitiveIterator.OfInt, long, int) * @since 1.8 */ - public static abstract class AbstractIntSpliterator implements Spliterator.OfInt { + public abstract static class AbstractIntSpliterator implements Spliterator.OfInt { static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH; static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT; private final int characteristics; @@ -1466,10 +1466,10 @@ public int characteristics() { * to permit limited parallelism. * *

      To implement a spliterator an extending class need only - * implement {@link #tryAdvance(java.util.function.LongConsumer)} + * implement {@link #tryAdvance(java.util.function.LongConsumer) * tryAdvance}. The extending class should override - * {@link #forEachRemaining(java.util.function.LongConsumer)} forEach} if it - * can provide a more performant implementation. + * {@link #forEachRemaining(java.util.function.LongConsumer) forEachRemaining} + * if it can provide a more performant implementation. * * @apiNote * This class is a useful aid for creating a spliterator when it is not @@ -1486,7 +1486,7 @@ public int characteristics() { * @see #spliterator(java.util.PrimitiveIterator.OfLong, long, int) * @since 1.8 */ - public static abstract class AbstractLongSpliterator implements Spliterator.OfLong { + public abstract static class AbstractLongSpliterator implements Spliterator.OfLong { static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH; static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT; private final int characteristics; @@ -1576,10 +1576,10 @@ public int characteristics() { * {@code trySplit} to permit limited parallelism. * *

      To implement a spliterator an extending class need only - * implement {@link #tryAdvance(java.util.function.DoubleConsumer)} + * implement {@link #tryAdvance(java.util.function.DoubleConsumer) * tryAdvance}. The extending class should override - * {@link #forEachRemaining(java.util.function.DoubleConsumer)} forEach} if - * it can provide a more performant implementation. + * {@link #forEachRemaining(java.util.function.DoubleConsumer) forEachRemaining} + * if it can provide a more performant implementation. * * @apiNote * This class is a useful aid for creating a spliterator when it is not @@ -1596,7 +1596,7 @@ public int characteristics() { * @see #spliterator(java.util.PrimitiveIterator.OfDouble, long, int) * @since 1.8 */ - public static abstract class AbstractDoubleSpliterator implements Spliterator.OfDouble { + public abstract static class AbstractDoubleSpliterator implements Spliterator.OfDouble { static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH; static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT; private final int characteristics; @@ -1698,7 +1698,7 @@ static class IteratorSpliterator implements Spliterator { private int batch; // batch size for splits /** - * Creates a spliterator using the given given + * Creates a spliterator using the given * collection's {@link java.util.Collection#iterator()) for traversal, * and reporting its {@link java.util.Collection#size()) as its initial * size. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Stack.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Stack.java index ebea11e5a6..2573276372 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Stack.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Stack.java @@ -26,12 +26,12 @@ package java.util; /** - * The Stack class represents a last-in-first-out - * (LIFO) stack of objects. It extends class Vector with five + * The {@code Stack} class represents a last-in-first-out + * (LIFO) stack of objects. It extends class {@code Vector} with five * operations that allow a vector to be treated as a stack. The usual - * push and pop operations are provided, as well as a - * method to peek at the top item on the stack, a method to test - * for whether the stack is empty, and a method to search + * {@code push} and {@code pop} operations are provided, as well as a + * method to {@code peek} at the top item on the stack, a method to test + * for whether the stack is {@code empty}, and a method to {@code search} * the stack for an item and discover how far it is from the top. *

      * When a stack is first created, it contains no items. @@ -43,7 +43,7 @@ * Deque stack = new ArrayDeque();}

      * * @author Jonathan Payne - * @since JDK1.0 + * @since 1.0 */ public class Stack extends Vector { @@ -60,7 +60,7 @@ public Stack() { * addElement(item)
      * * @param item the item to be pushed onto this stack. - * @return the item argument. + * @return the {@code item} argument. * @see java.util.Vector#addElement */ public E push(E item) { @@ -74,7 +74,7 @@ public E push(E item) { * object as the value of this function. * * @return The object at the top of this stack (the last item - * of the Vector object). + * of the {@code Vector} object). * @throws EmptyStackException if this stack is empty. */ public synchronized E pop() { @@ -92,7 +92,7 @@ public synchronized E pop() { * from the stack. * * @return the object at the top of this stack (the last item - * of the Vector object). + * of the {@code Vector} object). * @throws EmptyStackException if this stack is empty. */ public synchronized E peek() { @@ -106,8 +106,8 @@ public synchronized E peek() { /** * Tests if this stack is empty. * - * @return true if and only if this stack contains - * no items; false otherwise. + * @return {@code true} if and only if this stack contains + * no items; {@code false} otherwise. */ public boolean empty() { return size() == 0; @@ -115,16 +115,16 @@ public boolean empty() { /** * Returns the 1-based position where an object is on this stack. - * If the object o occurs as an item in this stack, this + * If the object {@code o} occurs as an item in this stack, this * method returns the distance from the top of the stack of the * occurrence nearest the top of the stack; the topmost item on the - * stack is considered to be at distance 1. The equals - * method is used to compare o to the + * stack is considered to be at distance {@code 1}. The {@code equals} + * method is used to compare {@code o} to the * items in this stack. * * @param o the desired object. * @return the 1-based position from the top of the stack where - * the object is located; the return value -1 + * the object is located; the return value {@code -1} * indicates that the object is not on the stack. */ public synchronized int search(Object o) { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringJoiner.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringJoiner.java index b6ba84c5df..c72d5a213b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringJoiner.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringJoiner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -67,19 +67,19 @@ public final class StringJoiner { private final String delimiter; private final String suffix; - /* - * StringBuilder value -- at any time, the characters constructed from the - * prefix, the added element separated by the delimiter, but without the - * suffix, so that we can more easily add elements without having to jigger - * the suffix each time. - */ - private StringBuilder value; + /** Contains all the string components added so far. */ + private String[] elts; + + /** The number of string components added so far. */ + private int size; - /* - * By default, the string consisting of prefix+suffix, returned by - * toString(), or properties of value, when no elements have yet been added, - * i.e. when it is empty. This may be overridden by the user to be some - * other value including the empty String. + /** Total length in chars so far, excluding prefix and suffix. */ + private int len; + + /** + * When overriden by the user to be non-null via {@link setEmptyValue}, the + * string returned by toString() when no elements have yet been added. + * When null, prefix + suffix is used as the empty value. */ private String emptyValue; @@ -125,7 +125,6 @@ public StringJoiner(CharSequence delimiter, this.prefix = prefix.toString(); this.delimiter = delimiter.toString(); this.suffix = suffix.toString(); - this.emptyValue = this.prefix + this.suffix; } /** @@ -148,29 +147,44 @@ public StringJoiner setEmptyValue(CharSequence emptyValue) { return this; } + private static int getChars(String s, char[] chars, int start) { + int len = s.length(); + s.getChars(0, len, chars, start); + return len; + } + /** * Returns the current value, consisting of the {@code prefix}, the values * added so far separated by the {@code delimiter}, and the {@code suffix}, * unless no elements have been added in which case, the - * {@code prefix + suffix} or the {@code emptyValue} characters are returned + * {@code prefix + suffix} or the {@code emptyValue} characters are returned. * * @return the string representation of this {@code StringJoiner} */ @Override public String toString() { - if (value == null) { + final String[] elts = this.elts; + if (elts == null && emptyValue != null) { return emptyValue; - } else { - if (suffix.equals("")) { - return value.toString(); - } else { - int initialLength = value.length(); - String result = value.append(suffix).toString(); - // reset value to pre-append initialLength - value.setLength(initialLength); - return result; + } + final int size = this.size; + final int addLen = prefix.length() + suffix.length(); + if (addLen == 0) { + compactElts(); + return size == 0 ? "" : elts[0]; + } + final String delimiter = this.delimiter; + final char[] chars = new char[len + addLen]; + int k = getChars(prefix, chars, 0); + if (size > 0) { + k += getChars(elts[0], chars, k); + for (int i = 1; i < size; i++) { + k += getChars(delimiter, chars, k); + k += getChars(elts[i], chars, k); } } + k += getChars(suffix, chars, k); + return new String(chars); } /** @@ -182,7 +196,16 @@ public String toString() { * @return a reference to this {@code StringJoiner} */ public StringJoiner add(CharSequence newElement) { - prepareBuilder().append(newElement); + final String elt = String.valueOf(newElement); + if (elts == null) { + elts = new String[8]; + } else { + if (size == elts.length) + elts = Arrays.copyOf(elts, 2 * size); + len += delimiter.length(); + } + len += elt.length(); + elts[size++] = elt; return this; } @@ -207,24 +230,25 @@ public StringJoiner add(CharSequence newElement) { */ public StringJoiner merge(StringJoiner other) { Objects.requireNonNull(other); - if (other.value != null) { - final int length = other.value.length(); - // lock the length so that we can seize the data to be appended - // before initiate copying to avoid interference, especially when - // merge 'this' - StringBuilder builder = prepareBuilder(); - builder.append(other.value, other.prefix.length(), length); + if (other.elts == null) { + return this; } - return this; + other.compactElts(); + return add(other.elts[0]); } - private StringBuilder prepareBuilder() { - if (value != null) { - value.append(delimiter); - } else { - value = new StringBuilder().append(prefix); + private void compactElts() { + if (size > 1) { + final char[] chars = new char[len]; + int i = 1, k = getChars(elts[0], chars, 0); + do { + k += getChars(delimiter, chars, k); + k += getChars(elts[i], chars, k); + elts[i] = null; + } while (++i < size); + size = 1; + elts[0] = new String(chars); } - return value; } /** @@ -238,10 +262,7 @@ private StringBuilder prepareBuilder() { * @return the length of the current value of {@code StringJoiner} */ public int length() { - // Remember that we never actually append the suffix unless we return - // the full (present) value or some sub-string or length of it, so that - // we can add on more if we need to. - return (value != null ? value.length() + suffix.length() : - emptyValue.length()); + return (size == 0 && emptyValue != null) ? emptyValue.length() : + len + prefix.length() + suffix.length(); } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringTokenizer.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringTokenizer.java index 1540c1a28e..5d55ae01e3 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringTokenizer.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/StringTokenizer.java @@ -30,32 +30,32 @@ /** * The string tokenizer class allows an application to break a * string into tokens. The tokenization method is much simpler than - * the one used by the StreamTokenizer class. The - * StringTokenizer methods do not distinguish among + * the one used by the {@code StreamTokenizer} class. The + * {@code StringTokenizer} methods do not distinguish among * identifiers, numbers, and quoted strings, nor do they recognize * and skip comments. *

      * The set of delimiters (the characters that separate tokens) may * be specified either at creation time or on a per-token basis. *

      - * An instance of StringTokenizer behaves in one of two + * An instance of {@code StringTokenizer} behaves in one of two * ways, depending on whether it was created with the - * returnDelims flag having the value true - * or false: + * {@code returnDelims} flag having the value {@code true} + * or {@code false}: *

        - *
      • If the flag is false, delimiter characters serve to + *
      • If the flag is {@code false}, delimiter characters serve to * separate tokens. A token is a maximal sequence of consecutive * characters that are not delimiters. - *
      • If the flag is true, delimiter characters are themselves + *
      • If the flag is {@code true}, delimiter characters are themselves * considered to be tokens. A token is thus either one delimiter * character, or a maximal sequence of consecutive characters that are * not delimiters. *

      - * A StringTokenizer object internally maintains a current + * A {@code StringTokenizer} object internally maintains a current * position within the string to be tokenized. Some operations advance this * current position past the characters processed.

      * A token is returned by taking a substring of the string that was used to - * create the StringTokenizer object. + * create the {@code StringTokenizer} object. *

      * The following is one example of the use of the tokenizer. The code: *

      @@ -74,12 +74,12 @@
        * 
      * *

      - * StringTokenizer is a legacy class that is retained for + * {@code StringTokenizer} is a legacy class that is retained for * compatibility reasons although its use is discouraged in new code. It is - * recommended that anyone seeking this functionality use the split - * method of String or the java.util.regex package instead. + * recommended that anyone seeking this functionality use the {@code split} + * method of {@code String} or the java.util.regex package instead. *

      - * The following example illustrates how the String.split + * The following example illustrates how the {@code String.split} * method can be used to break up a string into its basic tokens: *

        *     String[] result = "this is a test".split("\\s");
      @@ -97,7 +97,7 @@
        *
        * @author  unascribed
        * @see     java.io.StreamTokenizer
      - * @since   JDK1.0
      + * @since   1.0
        */
       public
       class StringTokenizer implements Enumeration {
      @@ -171,25 +171,25 @@ private void setMaxDelimCodePoint() {
       
           /**
            * Constructs a string tokenizer for the specified string. All
      -     * characters in the delim argument are the delimiters
      +     * characters in the {@code delim} argument are the delimiters
            * for separating tokens.
            * 

      - * If the returnDelims flag is true, then + * If the {@code returnDelims} flag is {@code true}, then * the delimiter characters are also returned as tokens. Each * delimiter is returned as a string of length one. If the flag is - * false, the delimiter characters are skipped and only + * {@code false}, the delimiter characters are skipped and only * serve as separators between tokens. *

      - * Note that if delim is null, this constructor does + * Note that if {@code delim} is {@code null}, this constructor does * not throw an exception. However, trying to invoke other methods on the - * resulting StringTokenizer may result in a - * NullPointerException. + * resulting {@code StringTokenizer} may result in a + * {@code NullPointerException}. * * @param str a string to be parsed. * @param delim the delimiters. * @param returnDelims flag indicating whether to return the delimiters * as tokens. - * @exception NullPointerException if str is null + * @exception NullPointerException if str is {@code null} */ public StringTokenizer(String str, String delim, boolean returnDelims) { currentPosition = 0; @@ -204,18 +204,18 @@ public StringTokenizer(String str, String delim, boolean returnDelims) { /** * Constructs a string tokenizer for the specified string. The - * characters in the delim argument are the delimiters + * characters in the {@code delim} argument are the delimiters * for separating tokens. Delimiter characters themselves will not * be treated as tokens. *

      - * Note that if delim is null, this constructor does + * Note that if {@code delim} is {@code null}, this constructor does * not throw an exception. However, trying to invoke other methods on the - * resulting StringTokenizer may result in a - * NullPointerException. + * resulting {@code StringTokenizer} may result in a + * {@code NullPointerException}. * * @param str a string to be parsed. * @param delim the delimiters. - * @exception NullPointerException if str is null + * @exception NullPointerException if str is {@code null} */ public StringTokenizer(String str, String delim) { this(str, delim, false); @@ -230,7 +230,7 @@ public StringTokenizer(String str, String delim) { * not be treated as tokens. * * @param str a string to be parsed. - * @exception NullPointerException if str is null + * @exception NullPointerException if str is {@code null} */ public StringTokenizer(String str) { this(str, " \t\n\r\f", false); @@ -297,8 +297,8 @@ private int scanToken(int startPos) { } private boolean isDelimiter(int codePoint) { - for (int i = 0; i < delimiterCodePoints.length; i++) { - if (delimiterCodePoints[i] == codePoint) { + for (int delimiterCodePoint : delimiterCodePoints) { + if (delimiterCodePoint == codePoint) { return true; } } @@ -307,11 +307,11 @@ private boolean isDelimiter(int codePoint) { /** * Tests if there are more tokens available from this tokenizer's string. - * If this method returns true, then a subsequent call to - * nextToken with no argument will successfully return a token. + * If this method returns {@code true}, then a subsequent call to + * {@code nextToken} with no argument will successfully return a token. * - * @return true if and only if there is at least one token - * in the string after the current position; false + * @return {@code true} if and only if there is at least one token + * in the string after the current position; {@code false} * otherwise. */ public boolean hasMoreTokens() { @@ -355,8 +355,8 @@ public String nextToken() { /** * Returns the next token in this string tokenizer's string. First, * the set of characters considered to be delimiters by this - * StringTokenizer object is changed to be the characters in - * the string delim. Then the next token in the string + * {@code StringTokenizer} object is changed to be the characters in + * the string {@code delim}. Then the next token in the string * after the current position is returned. The current position is * advanced beyond the recognized token. The new delimiter set * remains the default after this call. @@ -365,7 +365,7 @@ public String nextToken() { * @return the next token, after switching to the new delimiter set. * @exception NoSuchElementException if there are no more tokens in this * tokenizer's string. - * @exception NullPointerException if delim is null + * @exception NullPointerException if delim is {@code null} */ public String nextToken(String delim) { delimiters = delim; @@ -378,12 +378,12 @@ public String nextToken(String delim) { } /** - * Returns the same value as the hasMoreTokens + * Returns the same value as the {@code hasMoreTokens} * method. It exists so that this class can implement the - * Enumeration interface. + * {@code Enumeration} interface. * - * @return true if there are more tokens; - * false otherwise. + * @return {@code true} if there are more tokens; + * {@code false} otherwise. * @see java.util.Enumeration * @see java.util.StringTokenizer#hasMoreTokens() */ @@ -392,10 +392,10 @@ public boolean hasMoreElements() { } /** - * Returns the same value as the nextToken method, - * except that its declared return value is Object rather than - * String. It exists so that this class can implement the - * Enumeration interface. + * Returns the same value as the {@code nextToken} method, + * except that its declared return value is {@code Object} rather than + * {@code String}. It exists so that this class can implement the + * {@code Enumeration} interface. * * @return the next token in the string. * @exception NoSuchElementException if there are no more tokens in this @@ -409,7 +409,7 @@ public Object nextElement() { /** * Calculates the number of times that this tokenizer's - * nextToken method can be called before it generates an + * {@code nextToken} method can be called before it generates an * exception. The current position is not advanced. * * @return the number of tokens remaining in the string using the current diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimSort.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimSort.java index ea0d58f5a8..7cce1cc450 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimSort.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimSort.java @@ -339,7 +339,7 @@ private static void binarySort(T[] a, int lo, int hi, int start, * @param a the array in which a run is to be counted and possibly reversed * @param lo index of the first element in the run * @param hi index after the last element that may be contained in the run. - It is required that {@code lo < hi}. + * It is required that {@code lo < hi}. * @param c the comparator to used for the sort * @return the length of the run beginning at the specified position in * the specified array @@ -429,19 +429,23 @@ private void pushRun(int runBase, int runLen) { * This method is called each time a new run is pushed onto the stack, * so the invariants are guaranteed to hold for i < stackSize upon * entry to the method. + * + * Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer, + * Richard Bubel and Reiner Hahnle, this is fixed with respect to + * the analysis in "On the Worst-Case Complexity of TimSort" by + * Nicolas Auger, Vincent Jug, Cyril Nicaud, and Carine Pivoteau. */ private void mergeCollapse() { while (stackSize > 1) { int n = stackSize - 2; - if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) { + if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] || + n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) { if (runLen[n - 1] < runLen[n + 1]) n--; - mergeAt(n); - } else if (runLen[n] <= runLen[n + 1]) { - mergeAt(n); - } else { + } else if (n < 0 || runLen[n] > runLen[n + 1]) { break; // Invariant is established } + mergeAt(n); } } @@ -916,12 +920,7 @@ private void mergeHi(int base1, int len1, int base2, int len2) { private T[] ensureCapacity(int minCapacity) { if (tmpLen < minCapacity) { // Compute smallest power of 2 > minCapacity - int newSize = minCapacity; - newSize |= newSize >> 1; - newSize |= newSize >> 2; - newSize |= newSize >> 4; - newSize |= newSize >> 8; - newSize |= newSize >> 16; + int newSize = -1 >>> Integer.numberOfLeadingZeros(minCapacity); newSize++; if (newSize < 0) // Not bloody likely! diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimeZone.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimeZone.java index bb4f0970d2..9a4c38d7ed 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimeZone.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimeZone.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, 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 @@ -39,6 +39,17 @@ package java.util; +/* J2ObjC removed +import android.icu.text.TimeZoneNames; +import com.android.icu.util.ExtendedTimeZone; +import com.android.i18n.timezone.ZoneInfoData; +import com.android.i18n.timezone.ZoneInfoDb; +import libcore.util.ZoneInfo; +import java.time.ZoneId; +import java.util.function.Supplier; +import dalvik.system.RuntimeHooks; +*/ + import com.google.j2objc.util.NativeTimeZone; import java.io.IOException; @@ -48,46 +59,45 @@ import libcore.icu.TimeZoneNames; import libcore.io.IoUtils; - /** - * TimeZone represents a time zone offset, and also figures out daylight + * {@code TimeZone} represents a time zone offset, and also figures out daylight * savings. * *

      - * Typically, you get a TimeZone using getDefault - * which creates a TimeZone based on the time zone where the program - * is running. For example, for a program running in Japan, getDefault - * creates a TimeZone object based on Japanese Standard Time. + * Typically, you get a {@code TimeZone} using {@code getDefault} + * which creates a {@code TimeZone} based on the time zone where the program + * is running. For example, for a program running in Japan, {@code getDefault} + * creates a {@code TimeZone} object based on Japanese Standard Time. * *

      - * You can also get a TimeZone using getTimeZone + * You can also get a {@code TimeZone} using {@code getTimeZone} * along with a time zone ID. For instance, the time zone ID for the * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a - * U.S. Pacific Time TimeZone object with: + * U.S. Pacific Time {@code TimeZone} object with: *

        * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
        * 
      - * You can use the getAvailableIDs method to iterate through + * You can use the {@code getAvailableIDs} method to iterate through * all the supported time zone IDs. You can then choose a - * supported ID to get a TimeZone. + * supported ID to get a {@code TimeZone}. * If the time zone you want is not represented by one of the * supported IDs, then a custom time zone ID can be specified to * produce a TimeZone. The syntax of a custom time zone ID is: * *
      - * CustomID:
      - *         GMT Sign Hours : Minutes
      - *         GMT Sign Hours Minutes
      - *         GMT Sign Hours
      + * CustomID:
      + *         {@code GMT} Sign Hours {@code :} Minutes
      + *         {@code GMT} Sign Hours Minutes
      + *         {@code GMT} Sign Hours
        * Sign: one of
      - *         + -
      + *         {@code + -}
        * Hours:
        *         Digit
        *         Digit Digit
        * Minutes:
        *         Digit Digit
        * Digit: one of
      - *         0 1 2 3 4 5 6 7 8 9
      + *         {@code 0 1 2 3 4 5 6 7 8 9}
        * 
      * * Hours must be between 0 to 23 and Minutes must be @@ -97,26 +107,26 @@ * The format is locale independent and digits must be taken from the * Basic Latin block of the Unicode standard. No daylight saving time * transition schedule can be specified with a custom time zone ID. If - * the specified string doesn't match the syntax, "GMT" + * the specified string doesn't match the syntax, {@code "GMT"} * is used. *

      - * When creating a TimeZone, the specified custom time + * When creating a {@code TimeZone}, the specified custom time * zone ID is normalized in the following syntax: *

      - * NormalizedCustomID:
      - *         GMT Sign TwoDigitHours : Minutes
      + * NormalizedCustomID:
      + *         {@code GMT} Sign TwoDigitHours {@code :} Minutes
        * Sign: one of
      - *         + -
      + *         {@code + -}
        * TwoDigitHours:
        *         Digit Digit
        * Minutes:
        *         Digit Digit
        * Digit: one of
      - *         0 1 2 3 4 5 6 7 8 9
      + *         {@code 0 1 2 3 4 5 6 7 8 9}
        * 
      * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00". * - *

      Three-letter time zone IDs

      + *

      Three-letter time zone IDs

      * * For compatibility with JDK 1.1.x, some other three-letter time zone IDs * (such as "PST", "CTT", "AST") are also supported. However, their @@ -130,9 +140,9 @@ * @see GregorianCalendar * @see SimpleTimeZone * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu - * @since JDK1.1 + * @since 1.1 */ -abstract public class TimeZone implements Serializable, Cloneable { +public abstract class TimeZone implements Serializable, Cloneable { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) @@ -141,7 +151,7 @@ public TimeZone() { } /** - * A style specifier for getDisplayName() indicating + * A style specifier for {@code getDisplayName()} indicating * a short name, such as "PST." * @see #LONG * @since 1.2 @@ -149,7 +159,7 @@ public TimeZone() { public static final int SHORT = 0; /** - * A style specifier for getDisplayName() indicating + * A style specifier for {@code getDisplayName()} indicating * a long name, such as "Pacific Standard Time." * @see #SHORT * @since 1.2 @@ -163,6 +173,7 @@ private static class NoImagePreloadHolder { } // Proclaim serialization compatibility with JDK 1.1 + @java.io.Serial static final long serialVersionUID = 3581463369166924961L; // Android-changed: common timezone instances. @@ -183,7 +194,7 @@ static class UTCHolder { * daylight savings. This is the offset to add to UTC to get local time. *

      * This method returns a historically correct offset if an - * underlying TimeZone implementation subclass + * underlying {@code TimeZone} implementation subclass * supports historical Daylight Saving Time schedule and GMT * offset changes. * @@ -261,7 +272,7 @@ int getOffsets(long date, int[] offsets) { * Sets the base time zone offset to GMT. * This is the offset to add to UTC to get local time. *

      - * If an underlying TimeZone implementation subclass + * If an underlying {@code TimeZone} implementation subclass * supports historical GMT offset changes, the specified GMT * offset is set as the latest GMT offset and the difference from * the known latest GMT offset value is used to adjust all @@ -269,7 +280,7 @@ int getOffsets(long date, int[] offsets) { * * @param offsetMillis the given base time zone offset to GMT. */ - abstract public void setRawOffset(int offsetMillis); + public abstract void setRawOffset(int offsetMillis); /** * Returns the amount of time in milliseconds to add to UTC to get @@ -277,7 +288,7 @@ int getOffsets(long date, int[] offsets) { * affected by daylight saving time, it is called raw * offset. *

      - * If an underlying TimeZone implementation subclass + * If an underlying {@code TimeZone} implementation subclass * supports historical GMT offset changes, the method returns the * raw offset value of the current date. In Honolulu, for example, * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and @@ -343,7 +354,7 @@ public final String getDisplayName() { * * @param locale the locale in which to supply the display name. * @return the human-readable name of this time zone in the given locale. - * @exception NullPointerException if {@code locale} is {@code null}. + * @throws NullPointerException if {@code locale} is {@code null}. * @since 1.2 * @see #getDisplayName(boolean, int, Locale) */ @@ -368,7 +379,7 @@ public final String getDisplayName(Locale locale) { * {@code false} specifying a Standard Time name * @param style either {@link #LONG} or {@link #SHORT} * @return the human-readable name of this time zone in the default locale. - * @exception IllegalArgumentException if {@code style} is invalid. + * @throws IllegalArgumentException if {@code style} is invalid. * @since 1.2 * @see #getDisplayName(boolean, int, Locale) * @see Locale#getDefault(Locale.Category) @@ -562,17 +573,17 @@ public boolean observesDaylightTime() { * @return {@code true} if the given date is in Daylight Saving Time, * {@code false}, otherwise. */ - abstract public boolean inDaylightTime(Date date); + public abstract boolean inDaylightTime(Date date); /** - * Gets the TimeZone for the given ID. + * Gets the {@code TimeZone} for the given ID. * * @param id the ID for a TimeZone, either an abbreviation * such as "PST", a full name such as "America/Los_Angeles", or a custom * ID such as "GMT-8:00". Note that the support of abbreviations is * for JDK 1.1.x compatibility only and full names should be used. * - * @return the specified TimeZone, or the GMT zone if the given ID + * @return the specified {@code TimeZone}, or the GMT zone if the given ID * cannot be understood. */ // Android-changed: param s/ID/id; use ZoneInfoDb instead of ZoneInfo class. @@ -826,15 +837,15 @@ public synchronized static void setDefault(TimeZone timeZone) defaultTimeZone = timeZone != null ? (TimeZone) timeZone.clone() : null; /* // Android-changed: notify ICU4J of changed default TimeZone. - android.icu.util.TimeZone.setICUDefault(null); - */ + ExtendedTimeZone.clearDefaultTimeZone(); + */ } /** * Returns true if this zone has the same rule and offset as another zone. * That is, if this zone differs only in ID, if at all. Returns false * if the other zone is null. - * @param other the TimeZone object to be compared with + * @param other the {@code TimeZone} object to be compared with * @return true if the other zone is not null and is the same as this one, * with the possible exception of the ID * @since 1.2 @@ -845,16 +856,14 @@ public boolean hasSameRules(TimeZone other) { } /** - * Creates a copy of this TimeZone. + * Creates a copy of this {@code TimeZone}. * - * @return a clone of this TimeZone + * @return a clone of this {@code TimeZone} */ public Object clone() { try { - TimeZone other = (TimeZone) super.clone(); - other.ID = ID; - return other; + return super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(e); } @@ -868,10 +877,10 @@ public Object clone() // =======================privates=============================== /** - * The string identifier of this TimeZone. This is a - * programmatic identifier used internally to look up TimeZone + * The string identifier of this {@code TimeZone}. This is a + * programmatic identifier used internally to look up {@code TimeZone} * objects from the system table and also to map them to their localized - * display names. ID values are unique in the system + * display names. {@code ID} values are unique in the system * table but may not be for dynamically created zones. * @serial */ diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Timer.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Timer.java index c76011178d..0bf2b16327 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Timer.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Timer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -34,7 +34,7 @@ * background thread. Tasks may be scheduled for one-time execution, or for * repeated execution at regular intervals. * - *

      Corresponding to each Timer object is a single background + *

      Corresponding to each {@code Timer} object is a single background * thread that is used to execute all of the timer's tasks, sequentially. * Timer tasks should complete quickly. If a timer task takes excessive time * to complete, it "hogs" the timer's task execution thread. This can, in @@ -42,26 +42,26 @@ * execute in rapid succession when (and if) the offending task finally * completes. * - *

      After the last live reference to a Timer object goes away + *

      After the last live reference to a {@code Timer} object goes away * and all outstanding tasks have completed execution, the timer's task * execution thread terminates gracefully (and becomes subject to garbage * collection). However, this can take arbitrarily long to occur. By * default, the task execution thread does not run as a daemon thread, * so it is capable of keeping an application from terminating. If a caller * wants to terminate a timer's task execution thread rapidly, the caller - * should invoke the timer's cancel method. + * should invoke the timer's {@code cancel} method. * *

      If the timer's task execution thread terminates unexpectedly, for - * example, because its stop method is invoked, any further + * example, because its {@code stop} method is invoked, any further * attempt to schedule a task on the timer will result in an - * IllegalStateException, as if the timer's cancel + * {@code IllegalStateException}, as if the timer's {@code cancel} * method had been invoked. * *

      This class is thread-safe: multiple threads can share a single - * Timer object without the need for external synchronization. + * {@code Timer} object without the need for external synchronization. * *

      This class does not offer real-time guarantees: it schedules - * tasks using the Object.wait(long) method. + * tasks using the {@code Object.wait(long)} method. * *

      Java 5.0 introduced the {@code java.util.concurrent} package and * one of the concurrency utilities therein is the {@link @@ -95,11 +95,21 @@ public class Timer { * and the timer thread consumes, executing timer tasks as appropriate, * and removing them from the queue when they're obsolete. */ + // Android-added: @ReachabilitySensitive + // Otherwise the finalizer may cancel the Timer in the middle of a + // sched() call. + /* J2ObjC removed + @ReachabilitySensitive + */ private final TaskQueue queue = new TaskQueue(); /** * The timer thread. */ + // Android-added: @ReachabilitySensitive + /* J2ObjC removed + @ReachabilitySensitive + */ private final TimerThread thread = new TimerThread(queue); /** @@ -110,6 +120,7 @@ public class Timer { * finalizer forgetting to call it. */ private final Object threadReaper = new Object() { + @SuppressWarnings("deprecation") protected void finalize() throws Throwable { synchronized(queue) { thread.newTasksMayBeScheduled = false; @@ -121,7 +132,7 @@ protected void finalize() throws Throwable { /** * This ID is used to generate thread names. */ - private final static AtomicInteger nextSerialNumber = new AtomicInteger(0); + private static final AtomicInteger nextSerialNumber = new AtomicInteger(0); private static int serialNumber() { return nextSerialNumber.getAndIncrement(); } @@ -183,8 +194,8 @@ public Timer(String name, boolean isDaemon) { * * @param task task to be scheduled. * @param delay delay in milliseconds before task is to be executed. - * @throws IllegalArgumentException if delay is negative, or - * delay + System.currentTimeMillis() is negative. + * @throws IllegalArgumentException if {@code delay} is negative, or + * {@code delay + System.currentTimeMillis()} is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. * @throws NullPointerException if {@code task} is null @@ -201,7 +212,7 @@ public void schedule(TimerTask task, long delay) { * * @param task task to be scheduled. * @param time time at which task is to be executed. - * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalArgumentException if {@code time.getTime()} is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. * @throws NullPointerException if {@code task} or {@code time} is null @@ -221,7 +232,7 @@ public void schedule(TimerTask task, Date time) { * background activity), subsequent executions will be delayed as well. * In the long run, the frequency of execution will generally be slightly * lower than the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). + * clock underlying {@code Object.wait(long)} is accurate). * *

      Fixed-delay execution is appropriate for recurring activities * that require "smoothness." In other words, it is appropriate for @@ -261,7 +272,7 @@ public void schedule(TimerTask task, long delay, long period) { * background activity), subsequent executions will be delayed as well. * In the long run, the frequency of execution will generally be slightly * lower than the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). As a + * clock underlying {@code Object.wait(long)} is accurate). As a * consequence of the above, if the scheduled first time is in the past, * it is scheduled for immediate execution. * @@ -300,7 +311,7 @@ public void schedule(TimerTask task, Date firstTime, long period) { * activity), two or more executions will occur in rapid succession to * "catch up." In the long run, the frequency of execution will be * exactly the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). + * clock underlying {@code Object.wait(long)} is accurate). * *

      Fixed-rate execution is appropriate for recurring activities that * are sensitive to absolute time, such as ringing a chime every @@ -341,7 +352,7 @@ public void scheduleAtFixedRate(TimerTask task, long delay, long period) { * activity), two or more executions will occur in rapid succession to * "catch up." In the long run, the frequency of execution will be * exactly the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). As a + * clock underlying {@code Object.wait(long)} is accurate). As a * consequence of the above, if the scheduled first time is in the past, * then any "missed" executions will be scheduled for immediate "catch up" * execution. @@ -380,7 +391,7 @@ public void scheduleAtFixedRate(TimerTask task, Date firstTime, * in Date.getTime() format. This method checks timer state, task state, * and initial execution time, but not period. * - * @throws IllegalArgumentException if time is negative. + * @throws IllegalArgumentException if {@code time} is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. * @throws NullPointerException if {@code task} is null @@ -449,7 +460,7 @@ public void cancel() { * is the number of tasks in the queue and c is the number of cancelled * tasks. * - *

      Note that it is permissible to call this method from within a + *

      Note that it is permissible to call this method from within * a task scheduled on this timer. * * @return the number of tasks removed from the queue. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimerTask.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimerTask.java index 5750486d16..6703cc0604 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimerTask.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TimerTask.java @@ -26,10 +26,14 @@ package java.util; /** - * A task that can be scheduled for one-time or repeated execution by a Timer. + * A task that can be scheduled for one-time or repeated execution by a + * {@link Timer}. + * + *

      A timer task is not reusable. Once a task has been scheduled + * for execution on a {@code Timer} or cancelled, subsequent attempts to + * schedule it for execution will throw {@code IllegalStateException}. * * @author Josh Bloch - * @see Timer * @since 1.3 */ @@ -98,7 +102,7 @@ protected TimerTask() { * will never run again. (If the task is running when this call occurs, * the task will run to completion, but will never run again.) * - *

      Note that calling this method from within the run method of + *

      Note that calling this method from within the {@code run} method of * a repeating timer task absolutely guarantees that the timer task will * not run again. * @@ -110,7 +114,7 @@ protected TimerTask() { * Returns false if the task was scheduled for one-time execution * and has already run, or if the task was never scheduled, or if * the task was already cancelled. (Loosely speaking, this method - * returns true if it prevents one or more scheduled + * returns {@code true} if it prevents one or more scheduled * executions from taking place.) */ public boolean cancel() { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TooManyListenersException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TooManyListenersException.java index 134dea8e19..9635a5cfe5 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TooManyListenersException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TooManyListenersException.java @@ -44,7 +44,7 @@ * @see java.util.EventListener * * @author Laurence P. G. Cable - * @since JDK1.1 + * @since 1.1 */ public class TooManyListenersException extends Exception { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeMap.java index 247f9f5f5e..5f7a0cb111 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeMap.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -100,7 +100,7 @@ * associated map using {@code put}.) * *

      This class is a member of the - * + * * Java Collections Framework. * * @param the type of keys maintained by this map @@ -206,8 +206,7 @@ public TreeMap(SortedMap m) { comparator = m.comparator(); try { buildFromSorted(m.size(), m.entrySet().iterator(), null, null); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { + } catch (java.io.IOException | ClassNotFoundException cannotHappen) { } } @@ -326,8 +325,7 @@ public void putAll(Map map) { try { buildFromSorted(mapSize, map.entrySet().iterator(), null, null); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { + } catch (java.io.IOException | ClassNotFoundException cannotHappen) { } return; } @@ -652,8 +650,7 @@ public Object clone() { // Initialize clone with our mappings try { clone.buildFromSorted(size, entrySet().iterator(), null, null); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { + } catch (java.io.IOException | ClassNotFoundException cannotHappen) { } return clone; @@ -874,7 +871,7 @@ public Collection values() { * Returns a {@link Set} view of the mappings contained in this map. * *

      The set's iterator returns the entries in ascending key order. The - * sets's spliterator is + * set's spliterator is * late-binding, * fail-fast, and additionally reports {@link Spliterator#SORTED} and * {@link Spliterator#ORDERED} with an encounter order that is ascending key @@ -984,6 +981,27 @@ public SortedMap tailMap(K fromKey) { return tailMap(fromKey, true); } + @Override + public boolean replace(K key, V oldValue, V newValue) { + TreeMapEntry p = getEntry(key); + if (p!=null && Objects.equals(oldValue, p.value)) { + p.value = newValue; + return true; + } + return false; + } + + @Override + public V replace(K key, V value) { + TreeMapEntry p = getEntry(key); + if (p!=null) { + V oldValue = p.value; + p.value = value; + return oldValue; + } + return null; + } + @Override public void forEach(BiConsumer action) { Objects.requireNonNull(action); @@ -1041,7 +1059,7 @@ public void clear() { } public Spliterator spliterator() { - return new ValueSpliterator(TreeMap.this, null, null, 0, -1, 0); + return new ValueSpliterator<>(TreeMap.this, null, null, 0, -1, 0); } /*-[ @@ -1093,7 +1111,7 @@ public void clear() { } public Spliterator> spliterator() { - return new EntrySpliterator(TreeMap.this, null, null, 0, -1, 0); + return new EntrySpliterator<>(TreeMap.this, null, null, 0, -1, 0); } /*-[ @@ -2499,8 +2517,7 @@ private void writeObject(java.io.ObjectOutputStream s) s.writeInt(size); // Write out keys and values (alternating) - for (Iterator> i = entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); + for (Map.Entry e : entrySet()) { s.writeObject(e.getKey()); s.writeObject(e.getValue()); } @@ -2531,8 +2548,7 @@ void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal) void addAllForTreeSet(SortedSet set, V defaultVal) { try { buildFromSorted(set.size(), set.iterator(), null, defaultVal); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { + } catch (java.io.IOException | ClassNotFoundException cannotHappen) { } } @@ -2657,19 +2673,17 @@ private final TreeMapEntry buildFromSorted(int level, int lo, int hi, } /** - * Find the level down to which to assign all nodes BLACK. This is the - * last `full' level of the complete binary tree produced by - * buildTree. The remaining nodes are colored RED. (This makes a `nice' - * set of color assignments wrt future insertions.) This level number is + * Finds the level down to which to assign all nodes BLACK. This is the + * last `full' level of the complete binary tree produced by buildTree. + * The remaining nodes are colored RED. (This makes a `nice' set of + * color assignments wrt future insertions.) This level number is * computed by finding the number of splits needed to reach the zeroeth - * node. (The answer is ~lg(N), but in any case must be computed by same - * quick O(lg(N)) loop.) + * node. + * + * @param size the (non-negative) number of keys in the tree to be built */ - private static int computeRedLevel(int sz) { - int level = 0; - for (int m = sz - 1; m >= 0; m = m / 2 - 1) - level++; - return level; + private static int computeRedLevel(int size) { + return 31 - Integer.numberOfLeadingZeros(size + 1); } /** @@ -2703,11 +2717,11 @@ static Spliterator keySpliteratorFor(NavigableMap m) { } final Spliterator keySpliterator() { - return new KeySpliterator(this, null, null, 0, -1, 0); + return new KeySpliterator<>(this, null, null, 0, -1, 0); } final Spliterator descendingKeySpliterator() { - return new DescendingKeySpliterator(this, null, null, 0, -2, 0); + return new DescendingKeySpliterator<>(this, null, null, 0, -2, 0); } /** @@ -2719,7 +2733,7 @@ final Spliterator descendingKeySpliterator() { * child, also serving as origin for the split-off spliterator. * Left-hands are symmetric. Descending versions place the origin * at the end and invert ascending split rules. This base class - * is non-commital about directionality, or whether the top-level + * is non-committal about directionality, or whether the top-level * spliterator covers the whole tree. This means that the actual * split mechanics are located in subclasses. Some of the subclass * trySplit methods are identical (except for return types), but diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeSet.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeSet.java index 8f323e1a72..f278256672 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeSet.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/TreeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ -74,7 +74,7 @@ * should be used only to detect bugs. * *

      This class is a member of the - * + * * Java Collections Framework. * * @param the type of elements maintained by this set @@ -121,7 +121,7 @@ public class TreeSet extends AbstractSet * {@code ClassCastException}. */ public TreeSet() { - this(new TreeMap()); + this(new TreeMap<>()); } /** @@ -220,7 +220,7 @@ public boolean isEmpty() { * Returns {@code true} if this set contains the specified element. * More formally, returns {@code true} if and only if this set * contains an element {@code e} such that - * (o==null ? e==null : o.equals(e)). + * {@code Objects.equals(o, e)}. * * @param o object to be checked for containment in this set * @return {@code true} if this set contains the specified element @@ -238,7 +238,7 @@ public boolean contains(Object o) { * Adds the specified element to this set if it is not already present. * More formally, adds the specified element {@code e} to this set if * the set contains no element {@code e2} such that - * (e==null ? e2==null : e.equals(e2)). + * {@code Objects.equals(e, e2)}. * If this set already contains the element, the call leaves the set * unchanged and returns {@code false}. * @@ -258,7 +258,7 @@ public boolean add(E e) { /** * Removes the specified element from this set if it is present. * More formally, removes an element {@code e} such that - * (o==null ? e==null : o.equals(e)), + * {@code Objects.equals(o, e)}, * if this set contains such an element. Returns {@code true} if * this set contained the element (or equivalently, if this set * changed as a result of the call). (This set will not contain the diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UUID.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UUID.java index b4ea41ff06..c4f82ff6cd 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UUID.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UUID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -27,6 +27,10 @@ import java.security.*; +// Android-removed: not using JavaLangAccess.fastUUID. +// import jdk.internal.misc.JavaLangAccess; +// import jdk.internal.misc.SharedSecrets; + /** * A class that represents an immutable universally unique identifier (UUID). * A UUID represents a 128-bit value. @@ -88,6 +92,9 @@ public final class UUID implements java.io.Serializable, Comparable { */ private final long leastSigBits; + // Android-removed: not using JavaLangAccess.fastUUID. + // private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /* * The random number generator used by this class to create random * based UUIDs. In a holder class to defer initialization until needed. @@ -373,6 +380,8 @@ public long node() { * @return A string representation of this {@code UUID} */ public String toString() { + // Android-changed: using old implementation. + // return jla.fastUUID(leastSigBits, mostSigBits); return (digits(mostSigBits >> 32, 8) + "-" + digits(mostSigBits >> 16, 4) + "-" + digits(mostSigBits, 4) + "-" + diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatConversionException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatConversionException.java index 9ef964dc1c..1278c6e678 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatConversionException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatConversionException.java @@ -28,7 +28,7 @@ /** * Unchecked exception thrown when an unknown conversion is given. * - *

      Unless otherwise specified, passing a null argument to + *

      Unless otherwise specified, passing a {@code null} argument to * any method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java index 764fe6d234..8549566ce2 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java @@ -28,7 +28,7 @@ /** * Unchecked exception thrown when an unknown flag is given. * - *

      Unless otherwise specified, passing a null argument to any + *

      Unless otherwise specified, passing a {@code null} argument to any * method or constructor in this class will cause a {@link * NullPointerException} to be thrown. * diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Vector.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Vector.java index f1844379ad..0b264b7d3b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Vector.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2018, 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 @@ -25,6 +25,9 @@ package java.util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.StreamCorruptedException; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -45,9 +48,9 @@ * capacity of a vector before inserting a large number of * components; this reduces the amount of incremental reallocation. * - *

      + *

      * The iterators returned by this class's {@link #iterator() iterator} and - * {@link #listIterator(int) listIterator} methods are fail-fast: + * {@link #listIterator(int) listIterator} methods are fail-fast: * if the vector is structurally modified at any time after the iterator is * created, in any way except through the iterator's own * {@link ListIterator#remove() remove} or @@ -56,7 +59,9 @@ * concurrent modification, the iterator fails quickly and cleanly, rather * than risking arbitrary, non-deterministic behavior at an undetermined * time in the future. The {@link Enumeration Enumerations} returned by - * the {@link #elements() elements} method are not fail-fast. + * the {@link #elements() elements} method are not fail-fast; if the + * Vector is structurally modified at any time after the enumeration is + * created then the results of enumerating are undefined. * *

      Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the @@ -68,17 +73,19 @@ * *

      As of the Java 2 platform v1.2, this class was retrofitted to * implement the {@link List} interface, making it a member of the - * + * * Java Collections Framework. Unlike the new collection * implementations, {@code Vector} is synchronized. If a thread-safe * implementation is not needed, it is recommended to use {@link * ArrayList} in place of {@code Vector}. * + * @param Type of component elements + * * @author Lee Boynton * @author Jonathan Payne * @see Collection * @see LinkedList - * @since JDK1.0 + * @since 1.0 */ public class Vector extends AbstractList @@ -168,11 +175,13 @@ public Vector() { * @since 1.2 */ public Vector(Collection c) { - elementData = c.toArray(); - elementCount = elementData.length; - // c.toArray might (incorrectly) not return Object[] (see 6260652) - if (elementData.getClass() != Object[].class) - elementData = Arrays.copyOf(elementData, elementCount, Object[].class); + Object[] a = c.toArray(); + elementCount = a.length; + if (c.getClass() == ArrayList.class) { + elementData = a; + } else { + elementData = Arrays.copyOf(a, elementCount, Object[].class); + } } /** @@ -228,42 +237,56 @@ public synchronized void trimToSize() { public synchronized void ensureCapacity(int minCapacity) { if (minCapacity > 0) { modCount++; - ensureCapacityHelper(minCapacity); + if (minCapacity > elementData.length) + grow(minCapacity); } } /** - * This implements the unsynchronized semantics of ensureCapacity. - * Synchronized methods in this class can internally call this - * method for ensuring capacity without incurring the cost of an - * extra synchronization. - * - * @see #ensureCapacity(int) - */ - private void ensureCapacityHelper(int minCapacity) { - // overflow-conscious code - if (minCapacity - elementData.length > 0) - grow(minCapacity); - } - - /** - * The maximum size of array to allocate. + * The maximum size of array to allocate (unless necessary). * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - private void grow(int minCapacity) { + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if minCapacity is less than zero + */ + private Object[] grow(int minCapacity) { + return elementData = Arrays.copyOf(elementData, + newCapacity(minCapacity)); + } + + private Object[] grow() { + return grow(elementCount + 1); + } + + /** + * Returns a capacity at least as large as the given minimum capacity. + * Will not return a capacity greater than MAX_ARRAY_SIZE unless + * the given minimum capacity is greater than MAX_ARRAY_SIZE. + * + * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if minCapacity is less than zero + */ + private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); - if (newCapacity - minCapacity < 0) - newCapacity = minCapacity; - if (newCapacity - MAX_ARRAY_SIZE > 0) - newCapacity = hugeCapacity(minCapacity); - elementData = Arrays.copyOf(elementData, newCapacity); + if (newCapacity - minCapacity <= 0) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return minCapacity; + } + return (newCapacity - MAX_ARRAY_SIZE <= 0) + ? newCapacity + : hugeCapacity(minCapacity); } private static int hugeCapacity(int minCapacity) { @@ -285,13 +308,11 @@ private static int hugeCapacity(int minCapacity) { */ public synchronized void setSize(int newSize) { modCount++; - if (newSize > elementCount) { - ensureCapacityHelper(newSize); - } else { - for (int i = newSize ; i < elementCount ; i++) { - elementData[i] = null; - } - } + if (newSize > elementData.length) + grow(newSize); + final Object[] es = elementData; + for (int to = elementCount, i = newSize; i < to; i++) + es[i] = null; elementCount = newSize; } @@ -330,7 +351,9 @@ public synchronized boolean isEmpty() { * Returns an enumeration of the components of this vector. The * returned {@code Enumeration} object will generate all items in * this vector. The first item generated is the item at index {@code 0}, - * then the item at index {@code 1}, and so on. + * then the item at index {@code 1}, and so on. If the vector is + * structurally modified while enumerating over the elements then the + * results of enumerating are undefined. * * @return an enumeration of the components of this vector * @see Iterator @@ -358,7 +381,7 @@ public E nextElement() { * Returns {@code true} if this vector contains the specified element. * More formally, returns {@code true} if and only if this vector * contains at least one element {@code e} such that - * (o==null ? e==null : o.equals(e)). + * {@code Objects.equals(o, e)}. * * @param o element whose presence in this vector is to be tested * @return {@code true} if this vector contains the specified element @@ -371,7 +394,7 @@ public boolean contains(Object o) { * Returns the index of the first occurrence of the specified element * in this vector, or -1 if this vector does not contain the element. * More formally, returns the lowest index {@code i} such that - * (o==null ? get(i)==null : o.equals(get(i))), + * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. * * @param o element to search for @@ -387,7 +410,7 @@ public int indexOf(Object o) { * this vector, searching forwards from {@code index}, or returns -1 if * the element is not found. * More formally, returns the lowest index {@code i} such that - * (i >= index && (o==null ? get(i)==null : o.equals(get(i)))), + * {@code (i >= index && Objects.equals(o, get(i)))}, * or -1 if there is no such index. * * @param o element to search for @@ -415,7 +438,7 @@ public synchronized int indexOf(Object o, int index) { * Returns the index of the last occurrence of the specified element * in this vector, or -1 if this vector does not contain the element. * More formally, returns the highest index {@code i} such that - * (o==null ? get(i)==null : o.equals(get(i))), + * {@code Objects.equals(o, get(i))}, * or -1 if there is no such index. * * @param o element to search for @@ -431,7 +454,7 @@ public synchronized int lastIndexOf(Object o) { * this vector, searching backwards from {@code index}, or returns -1 if * the element is not found. * More formally, returns the highest index {@code i} such that - * (i <= index && (o==null ? get(i)==null : o.equals(get(i)))), + * {@code (i <= index && Objects.equals(o, get(i)))}, * or -1 if there is no such index. * * @param o element to search for @@ -495,7 +518,7 @@ public synchronized E firstElement() { * Returns the last component of the vector. * * @return the last component of the vector, i.e., the component at index - * size() - 1. + * {@code size() - 1} * @throws NoSuchElementException if this vector is empty */ public synchronized E lastElement() { @@ -553,7 +576,6 @@ public synchronized void setElementAt(E obj, int index) { * ({@code index < 0 || index >= size()}) */ public synchronized void removeElementAt(int index) { - modCount++; if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); @@ -565,6 +587,7 @@ else if (index < 0) { if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } + modCount++; elementCount--; elementData[elementCount] = null; /* to let gc do its work */ } @@ -593,15 +616,20 @@ else if (index < 0) { * ({@code index < 0 || index > size()}) */ public synchronized void insertElementAt(E obj, int index) { - modCount++; if (index > elementCount) { throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount); } - ensureCapacityHelper(elementCount + 1); - System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); + modCount++; + final int s = elementCount; + Object[] elementData = this.elementData; + if (s == elementData.length) + elementData = grow(); + System.arraycopy(elementData, index, + elementData, index + 1, + s - index); elementData[index] = obj; - elementCount++; + elementCount = s + 1; } /** @@ -617,8 +645,7 @@ public synchronized void insertElementAt(E obj, int index) { */ public synchronized void addElement(E obj) { modCount++; - ensureCapacityHelper(elementCount + 1); - elementData[elementCount++] = obj; + add(obj, elementData, elementCount); } /** @@ -653,12 +680,10 @@ public synchronized boolean removeElement(Object obj) { * method (which is part of the {@link List} interface). */ public synchronized void removeAllElements() { + final Object[] es = elementData; + for (int to = elementCount, i = elementCount = 0; i < to; i++) + es[i] = null; modCount++; - // Let gc do its work - for (int i = 0; i < elementCount; i++) - elementData[i] = null; - - elementCount = 0; } /** @@ -671,7 +696,7 @@ public synchronized void removeAllElements() { public synchronized Object clone() { try { @SuppressWarnings("unchecked") - Vector v = (Vector) super.clone(); + Vector v = (Vector) super.clone(); v.elementData = Arrays.copyOf(elementData, elementCount); v.modCount = 0; return v; @@ -705,12 +730,15 @@ public synchronized Object[] toArray() { * of the Vector only if the caller knows that the Vector * does not contain any null elements.) * + * @param type of array elements. The same type as {@code } or a + * supertype of {@code }. * @param a the array into which the elements of the Vector are to * be stored, if it is big enough; otherwise, a new array of the * same runtime type is allocated for this purpose. * @return an array containing the elements of the Vector - * @throws ArrayStoreException if the runtime type of a is not a supertype - * of the runtime type of every element in this Vector + * @throws ArrayStoreException if the runtime type of a, {@code }, is not + * a supertype of the runtime type, {@code }, of every element in this + * Vector * @throws NullPointerException if the given array is null * @since 1.2 */ @@ -734,6 +762,11 @@ E elementData(int index) { return (E) elementData[index]; } + @SuppressWarnings("unchecked") + static E elementAt(Object[] es, int index) { + return (E) es[index]; + } + /** * Returns the element at the specified position in this Vector. * @@ -770,6 +803,18 @@ public synchronized E set(int index, E element) { return oldValue; } + /** + * This helper method split out from add(E) to keep method + * bytecode size under 35 (the -XX:MaxInlineSize default value), + * which helps when add(E) is called in a C1-compiled loop. + */ + private void add(E e, Object[] elementData, int s) { + if (s == elementData.length) + elementData = grow(); + elementData[s] = e; + elementCount = s + 1; + } + /** * Appends the specified element to the end of this Vector. * @@ -779,8 +824,7 @@ public synchronized E set(int index, E element) { */ public synchronized boolean add(E e) { modCount++; - ensureCapacityHelper(elementCount + 1); - elementData[elementCount++] = e; + add(e, elementData, elementCount); return true; } @@ -788,7 +832,7 @@ public synchronized boolean add(E e) { * Removes the first occurrence of the specified element in this Vector * If the Vector does not contain the element, it is unchanged. More * formally, removes the element with the lowest index i such that - * {@code (o==null ? get(i)==null : o.equals(get(i)))} (if such + * {@code Objects.equals(o, get(i))} (if such * an element exists). * * @param o element to be removed from this Vector, if present @@ -819,10 +863,10 @@ public void add(int index, E element) { * Shifts any subsequent elements to the left (subtracts one from their * indices). Returns the element that was removed from the Vector. * - * @throws ArrayIndexOutOfBoundsException if the index is out of range - * ({@code index < 0 || index >= size()}) * @param index the index of the element to be removed * @return element that was removed + * @throws ArrayIndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) * @since 1.2 */ public synchronized E remove(int index) { @@ -879,14 +923,21 @@ public synchronized boolean containsAll(Collection c) { * @throws NullPointerException if the specified collection is null * @since 1.2 */ - public synchronized boolean addAll(Collection c) { - modCount++; + public boolean addAll(Collection c) { Object[] a = c.toArray(); + modCount++; int numNew = a.length; - ensureCapacityHelper(elementCount + numNew); - System.arraycopy(a, 0, elementData, elementCount, numNew); - elementCount += numNew; - return numNew != 0; + if (numNew == 0) + return false; + synchronized (this) { + Object[] elementData = this.elementData; + final int s = elementCount; + if (numNew > elementData.length - s) + elementData = grow(s + numNew); + System.arraycopy(a, 0, elementData, s, numNew); + elementCount = s + numNew; + return true; + } } /** @@ -906,8 +957,9 @@ public synchronized boolean addAll(Collection c) { * or if the specified collection is null * @since 1.2 */ - public synchronized boolean removeAll(Collection c) { - return super.removeAll(c); + public boolean removeAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> c.contains(e)); } /** @@ -929,8 +981,65 @@ public synchronized boolean removeAll(Collection c) { * or if the specified collection is null * @since 1.2 */ - public synchronized boolean retainAll(Collection c) { - return super.retainAll(c); + public boolean retainAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> !c.contains(e)); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + @Override + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return bulkRemove(filter); + } + + // A tiny bit set implementation + + private static long[] nBits(int n) { + return new long[((n - 1) >> 6) + 1]; + } + private static void setBit(long[] bits, int i) { + bits[i >> 6] |= 1L << i; + } + private static boolean isClear(long[] bits, int i) { + return (bits[i >> 6] & (1L << i)) == 0; + } + + private synchronized boolean bulkRemove(Predicate filter) { + int expectedModCount = modCount; + final Object[] es = elementData; + final int end = elementCount; + int i; + // Optimize for initial run of survivors + for (i = 0; i < end && !filter.test(elementAt(es, i)); i++) + ; + // Tolerate predicates that reentrantly access the collection for + // read (but writers still get CME), so traverse once to find + // elements to delete, a second pass to physically expunge. + if (i < end) { + final int beg = i; + final long[] deathRow = nBits(end - beg); + deathRow[0] = 1L; // set bit 0 + for (i = beg + 1; i < end; i++) + if (filter.test(elementAt(es, i))) + setBit(deathRow, i - beg); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + modCount++; + int w = beg; + for (i = beg; i < end; i++) + if (isClear(deathRow, i - beg)) + es[w++] = es[i]; + for (i = elementCount = w; i < end; i++) + es[i] = null; + return true; + } else { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + return false; + } } /** @@ -951,22 +1060,27 @@ public synchronized boolean retainAll(Collection c) { * @since 1.2 */ public synchronized boolean addAll(int index, Collection c) { - modCount++; if (index < 0 || index > elementCount) throw new ArrayIndexOutOfBoundsException(index); Object[] a = c.toArray(); + modCount++; int numNew = a.length; - ensureCapacityHelper(elementCount + numNew); + if (numNew == 0) + return false; + Object[] elementData = this.elementData; + final int s = elementCount; + if (numNew > elementData.length - s) + elementData = grow(s + numNew); - int numMoved = elementCount - index; + int numMoved = s - index; if (numMoved > 0) - System.arraycopy(elementData, index, elementData, index + numNew, + System.arraycopy(elementData, index, + elementData, index + numNew, numMoved); - System.arraycopy(a, 0, elementData, index, numNew); - elementCount += numNew; - return numNew != 0; + elementCount = s + numNew; + return true; } /** @@ -974,8 +1088,8 @@ public synchronized boolean addAll(int index, Collection c) { * true if and only if the specified Object is also a List, both Lists * have the same size, and all corresponding pairs of elements in the two * Lists are equal. (Two elements {@code e1} and - * {@code e2} are equal if {@code (e1==null ? e2==null : - * e1.equals(e2))}.) In other words, two Lists are defined to be + * {@code e2} are equal if {@code Objects.equals(e1, e2)}.) + * In other words, two Lists are defined to be * equal if they contain the same elements in the same order. * * @param o the Object to be compared for equality with this Vector @@ -1047,22 +1161,56 @@ public synchronized List subList(int fromIndex, int toIndex) { * (If {@code toIndex==fromIndex}, this operation has no effect.) */ protected synchronized void removeRange(int fromIndex, int toIndex) { + // BEGIN Android-added: make check explicit and independent of the way elementData + // array management is done. + if (fromIndex > toIndex) { + throw new IndexOutOfBoundsException( + "From Index: " + fromIndex + " > To Index: " + toIndex); + } + // END Android-added: make check explicit and independent of the way elementData + // array management is done. modCount++; - int numMoved = elementCount - toIndex; - System.arraycopy(elementData, toIndex, elementData, fromIndex, - numMoved); + shiftTailOverGap(elementData, fromIndex, toIndex); + } - // Let gc do its work - int newElementCount = elementCount - (toIndex-fromIndex); - while (elementCount != newElementCount) - elementData[--elementCount] = null; + /** Erases the gap from lo to hi, by sliding down following elements. */ + private void shiftTailOverGap(Object[] es, int lo, int hi) { + System.arraycopy(es, hi, es, lo, elementCount - hi); + for (int to = elementCount, i = (elementCount -= hi - lo); i < to; i++) + es[i] = null; } /** - * Save the state of the {@code Vector} instance to a stream (that - * is, serialize it). + * Loads a {@code Vector} instance from a stream + * (that is, deserializes it). + * This method performs checks to ensure the consistency + * of the fields. + * + * @param in the stream + * @throws java.io.IOException if an I/O error occurs + * @throws ClassNotFoundException if the stream contains data + * of a non-existing class + */ + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + ObjectInputStream.GetField gfields = in.readFields(); + int count = gfields.get("elementCount", 0); + Object[] data = (Object[])gfields.get("elementData", null); + if (count < 0 || data == null || count > data.length) { + throw new StreamCorruptedException("Inconsistent vector internals"); + } + elementCount = count; + elementData = data.clone(); + } + + /** + * Saves the state of the {@code Vector} instance to a stream + * (that is, serializes it). * This method performs synchronization to ensure the consistency * of the serialized data. + * + * @param s the stream + * @throws java.io.IOException if an I/O error occurs */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1180,14 +1328,11 @@ public void forEachRemaining(Consumer action) { if (i >= size) { return; } - @SuppressWarnings("unchecked") - final E[] elementData = (E[]) Vector.this.elementData; - if (i >= elementData.length) { + final Object[] es = elementData; + if (i >= es.length) throw new ConcurrentModificationException(); - } - while (i != size && modCount == expectedModCount) { - action.accept(elementData[i++]); - } + while (i < size && modCount == expectedModCount) + action.accept(elementAt(es, i++)); // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; @@ -1256,77 +1401,34 @@ public void add(E e) { } } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public synchronized void forEach(Consumer action) { Objects.requireNonNull(action); final int expectedModCount = modCount; - @SuppressWarnings("unchecked") - final E[] elementData = (E[]) this.elementData; - final int elementCount = this.elementCount; - for (int i=0; modCount == expectedModCount && i < elementCount; i++) { - action.accept(elementData[i]); - } - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter); - // figure out which elements are to be removed - // any exception thrown from the filter predicate at this stage - // will leave the collection unmodified - int removeCount = 0; + final Object[] es = elementData; final int size = elementCount; - final BitSet removeSet = new BitSet(size); - final int expectedModCount = modCount; - for (int i=0; modCount == expectedModCount && i < size; i++) { - @SuppressWarnings("unchecked") - final E element = (E) elementData[i]; - if (filter.test(element)) { - removeSet.set(i); - removeCount++; - } - } - if (modCount != expectedModCount) { + for (int i = 0; modCount == expectedModCount && i < size; i++) + action.accept(elementAt(es, i)); + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } - - // shift surviving elements left over the spaces left by removed elements - final boolean anyToRemove = removeCount > 0; - if (anyToRemove) { - final int newSize = size - removeCount; - for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { - i = removeSet.nextClearBit(i); - elementData[j] = elementData[i]; - } - for (int k=newSize; k < size; k++) { - elementData[k] = null; // Let gc do its work - } - elementCount = newSize; - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - modCount++; - } - - return anyToRemove; } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") public synchronized void replaceAll(UnaryOperator operator) { Objects.requireNonNull(operator); final int expectedModCount = modCount; + final Object[] es = elementData; final int size = elementCount; - for (int i=0; modCount == expectedModCount && i < size; i++) { - elementData[i] = operator.apply((E) elementData[i]); - } - if (modCount != expectedModCount) { + for (int i = 0; modCount == expectedModCount && i < size; i++) + es[i] = operator.apply(elementAt(es, i)); + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } modCount++; } @@ -1335,9 +1437,8 @@ public synchronized void replaceAll(UnaryOperator operator) { public synchronized void sort(Comparator c) { final int expectedModCount = modCount; Arrays.sort((E[]) elementData, 0, elementCount, c); - if (modCount != expectedModCount) { + if (modCount != expectedModCount) throw new ConcurrentModificationException(); - } modCount++; } @@ -1356,21 +1457,19 @@ public synchronized void sort(Comparator c) { */ @Override public Spliterator spliterator() { - return new VectorSpliterator<>(this, null, 0, -1, 0); + return new VectorSpliterator(null, 0, -1, 0); } /** Similar to ArrayList Spliterator */ - static final class VectorSpliterator implements Spliterator { - private final Vector list; + final class VectorSpliterator implements Spliterator { private Object[] array; private int index; // current index, modified on advance/split private int fence; // -1 until used; then one past last index private int expectedModCount; // initialized when fence set - /** Create new spliterator covering the given range */ - VectorSpliterator(Vector list, Object[] array, int origin, int fence, + /** Creates new spliterator covering the given range. */ + VectorSpliterator(Object[] array, int origin, int fence, int expectedModCount) { - this.list = list; this.array = array; this.index = origin; this.fence = fence; @@ -1380,10 +1479,10 @@ static final class VectorSpliterator implements Spliterator { private int getFence() { // initialize on first use int hi; if ((hi = fence) < 0) { - synchronized(list) { - array = list.elementData; - expectedModCount = list.modCount; - hi = fence = list.elementCount; + synchronized (Vector.this) { + array = elementData; + expectedModCount = modCount; + hi = fence = elementCount; } } return hi; @@ -1392,19 +1491,17 @@ private int getFence() { // initialize on first use public Spliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new VectorSpliterator(list, array, lo, index = mid, - expectedModCount); + new VectorSpliterator(array, lo, index = mid, expectedModCount); } @SuppressWarnings("unchecked") public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); int i; - if (action == null) - throw new NullPointerException(); if (getFence() > (i = index)) { index = i + 1; action.accept((E)array[i]); - if (list.modCount != expectedModCount) + if (modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } @@ -1413,36 +1510,27 @@ public boolean tryAdvance(Consumer action) { @SuppressWarnings("unchecked") public void forEachRemaining(Consumer action) { - int i, hi; // hoist accesses and checks from loop - Vector lst; Object[] a; - if (action == null) - throw new NullPointerException(); - if ((lst = list) != null) { - if ((hi = fence) < 0) { - synchronized(lst) { - expectedModCount = lst.modCount; - a = array = lst.elementData; - hi = fence = lst.elementCount; - } - } - else - a = array; - if (a != null && (i = index) >= 0 && (index = hi) <= a.length) { - while (i < hi) - action.accept((E) a[i++]); - if (lst.modCount == expectedModCount) - return; - } - } - throw new ConcurrentModificationException(); + Objects.requireNonNull(action); + final int hi = getFence(); + final Object[] a = array; + int i; + for (i = index, index = hi; i < hi; i++) + action.accept((E) a[i]); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); } public long estimateSize() { - return (long) (getFence() - index); + return getFence() - index; } public int characteristics() { return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; } } + + void checkInvariants() { + // assert elementCount >= 0; + // assert elementCount == elementData.length || elementData[elementCount] == null; + } } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/WeakHashMap.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/WeakHashMap.java index cc9ace50e3..3059c75e84 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/WeakHashMap.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/WeakHashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ -39,79 +39,79 @@ ]-*/ /** - * Hash table based implementation of the Map interface, with + * Hash table based implementation of the {@code Map} interface, with * weak keys. - * An entry in a WeakHashMap will automatically be removed when + * An entry in a {@code WeakHashMap} will automatically be removed when * its key is no longer in ordinary use. More precisely, the presence of a * mapping for a given key will not prevent the key from being discarded by the * garbage collector, that is, made finalizable, finalized, and then reclaimed. * When a key has been discarded its entry is effectively removed from the map, - * so this class behaves somewhat differently from other Map + * so this class behaves somewhat differently from other {@code Map} * implementations. * *

      Both null values and the null key are supported. This class has - * performance characteristics similar to those of the HashMap + * performance characteristics similar to those of the {@code HashMap} * class, and has the same efficiency parameters of initial capacity * and load factor. * *

      Like most collection classes, this class is not synchronized. - * A synchronized WeakHashMap may be constructed using the + * A synchronized {@code WeakHashMap} may be constructed using the * {@link Collections#synchronizedMap Collections.synchronizedMap} * method. * *

      This class is intended primarily for use with key objects whose - * equals methods test for object identity using the - * == operator. Once such a key is discarded it can never be + * {@code equals} methods test for object identity using the + * {@code ==} operator. Once such a key is discarded it can never be * recreated, so it is impossible to do a lookup of that key in a - * WeakHashMap at some later time and be surprised that its entry + * {@code WeakHashMap} at some later time and be surprised that its entry * has been removed. This class will work perfectly well with key objects - * whose equals methods are not based upon object identity, such - * as String instances. With such recreatable key objects, - * however, the automatic removal of WeakHashMap entries whose + * whose {@code equals} methods are not based upon object identity, such + * as {@code String} instances. With such recreatable key objects, + * however, the automatic removal of {@code WeakHashMap} entries whose * keys have been discarded may prove to be confusing. * - *

      The behavior of the WeakHashMap class depends in part upon + *

      The behavior of the {@code WeakHashMap} class depends in part upon * the actions of the garbage collector, so several familiar (though not - * required) Map invariants do not hold for this class. Because + * required) {@code Map} invariants do not hold for this class. Because * the garbage collector may discard keys at any time, a - * WeakHashMap may behave as though an unknown thread is silently + * {@code WeakHashMap} may behave as though an unknown thread is silently * removing entries. In particular, even if you synchronize on a - * WeakHashMap instance and invoke none of its mutator methods, it - * is possible for the size method to return smaller values over - * time, for the isEmpty method to return false and - * then true, for the containsKey method to return - * true and later false for a given key, for the - * get method to return a value for a given key but later return - * null, for the put method to return - * null and the remove method to return - * false for a key that previously appeared to be in the map, and + * {@code WeakHashMap} instance and invoke none of its mutator methods, it + * is possible for the {@code size} method to return smaller values over + * time, for the {@code isEmpty} method to return {@code false} and + * then {@code true}, for the {@code containsKey} method to return + * {@code true} and later {@code false} for a given key, for the + * {@code get} method to return a value for a given key but later return + * {@code null}, for the {@code put} method to return + * {@code null} and the {@code remove} method to return + * {@code false} for a key that previously appeared to be in the map, and * for successive examinations of the key set, the value collection, and * the entry set to yield successively smaller numbers of elements. * - *

      Each key object in a WeakHashMap is stored indirectly as + *

      Each key object in a {@code WeakHashMap} is stored indirectly as * the referent of a weak reference. Therefore a key will automatically be * removed only after the weak references to it, both inside and outside of the * map, have been cleared by the garbage collector. * *

      Implementation note: The value objects in a - * WeakHashMap are held by ordinary strong references. Thus care + * {@code WeakHashMap} are held by ordinary strong references. Thus care * should be taken to ensure that value objects do not strongly refer to their * own keys, either directly or indirectly, since that will prevent the keys * from being discarded. Note that a value object may refer indirectly to its - * key via the WeakHashMap itself; that is, a value object may + * key via the {@code WeakHashMap} itself; that is, a value object may * strongly refer to some other key object whose associated value object, in * turn, strongly refers to the key of the first value object. If the values * in the map do not rely on the map holding strong references to them, one way * to deal with this is to wrap values themselves within - * WeakReferences before - * inserting, as in: m.put(key, new WeakReference(value)), - * and then unwrapping upon each get. + * {@code WeakReferences} before + * inserting, as in: {@code m.put(key, new WeakReference(value))}, + * and then unwrapping upon each {@code get}. * - *

      The iterators returned by the iterator method of the collections + *

      The iterators returned by the {@code iterator} method of the collections * returned by all of this class's "collection view methods" are * fail-fast: if the map is structurally modified at any time after the * iterator is created, in any way except through the iterator's own - * remove method, the iterator will throw a {@link + * {@code remove} method, the iterator will throw a {@link * ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than risking * arbitrary, non-deterministic behavior at an undetermined time in the future. @@ -119,13 +119,13 @@ *

      Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. * *

      This class is a member of the - * + * * Java Collections Framework. * * @param the type of keys maintained by this map @@ -201,11 +201,11 @@ private Entry[] newTable(int n) { } /** - * Constructs a new, empty WeakHashMap with the given initial + * Constructs a new, empty {@code WeakHashMap} with the given initial * capacity and the given load factor. * - * @param initialCapacity The initial capacity of the WeakHashMap - * @param loadFactor The load factor of the WeakHashMap + * @param initialCapacity The initial capacity of the {@code WeakHashMap} + * @param loadFactor The load factor of the {@code WeakHashMap} * @throws IllegalArgumentException if the initial capacity is negative, * or if the load factor is nonpositive. */ @@ -228,10 +228,10 @@ public WeakHashMap(int initialCapacity, float loadFactor) { } /** - * Constructs a new, empty WeakHashMap with the given initial + * Constructs a new, empty {@code WeakHashMap} with the given initial * capacity and the default load factor (0.75). * - * @param initialCapacity The initial capacity of the WeakHashMap + * @param initialCapacity The initial capacity of the {@code WeakHashMap} * @throws IllegalArgumentException if the initial capacity is negative */ public WeakHashMap(int initialCapacity) { @@ -239,7 +239,7 @@ public WeakHashMap(int initialCapacity) { } /** - * Constructs a new, empty WeakHashMap with the default initial + * Constructs a new, empty {@code WeakHashMap} with the default initial * capacity (16) and load factor (0.75). */ public WeakHashMap() { @@ -247,8 +247,8 @@ public WeakHashMap() { } /** - * Constructs a new WeakHashMap with the same mappings as the - * specified map. The WeakHashMap is created with the default + * Constructs a new {@code WeakHashMap} with the same mappings as the + * specified map. The {@code WeakHashMap} is created with the default * load factor (0.75) and an initial capacity sufficient to hold the * mappings in the specified map. * @@ -370,7 +370,7 @@ public int size() { } /** - * Returns true if this map contains no key-value mappings. + * Returns {@code true} if this map contains no key-value mappings. * This result is a snapshot, and may not reflect unprocessed * entries that will be removed before next attempted access * because they are no longer referenced. @@ -384,8 +384,9 @@ public boolean isEmpty() { * or {@code null} if this map contains no mapping for the key. * *

      More formally, if this map contains a mapping from a key - * {@code k} to a value {@code v} such that {@code (key==null ? k==null : - * key.equals(k))}, then this method returns {@code v}; otherwise + * {@code k} to a value {@code v} such that + * {@code Objects.equals(key, k)}, + * then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * *

      A return value of {@code null} does not necessarily @@ -411,12 +412,12 @@ public V get(Object key) { } /** - * Returns true if this map contains a mapping for the + * Returns {@code true} if this map contains a mapping for the * specified key. * * @param key The key whose presence in this map is to be tested - * @return true if there is a mapping for key; - * false otherwise + * @return {@code true} if there is a mapping for {@code key}; + * {@code false} otherwise */ public boolean containsKey(Object key) { return getEntry(key) != null; @@ -444,10 +445,10 @@ Entry getEntry(Object key) { * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) */ public V put(K key, V value) { Object k = maskNull(key); @@ -573,23 +574,23 @@ public void putAll(Map m) { /** * Removes the mapping for a key from this weak hash map if it is present. - * More formally, if this map contains a mapping from key k to - * value v such that (key==null ? k==null : + * More formally, if this map contains a mapping from key {@code k} to + * value {@code v} such that (key==null ? k==null : * key.equals(k)), that mapping is removed. (The map can contain * at most one such mapping.) * *

      Returns the value to which this map previously associated the key, - * or null if the map contained no mapping for the key. A - * return value of null does not necessarily indicate + * or {@code null} if the map contained no mapping for the key. A + * return value of {@code null} does not necessarily indicate * that the map contained no mapping for the key; it's also possible - * that the map explicitly mapped the key to null. + * that the map explicitly mapped the key to {@code null}. * *

      The map will not contain a mapping for the specified key once the * call returns. * * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or - * null if there was no mapping for key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} */ public V remove(Object key) { Object k = maskNull(key); @@ -669,11 +670,11 @@ public void clear() { } /** - * Returns true if this map maps one or more keys to the + * Returns {@code true} if this map maps one or more keys to the * specified value. * * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the + * @return {@code true} if this map maps one or more keys to the * specified value */ public boolean containsValue(Object value) { @@ -860,12 +861,12 @@ public Map.Entry next() { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation), the results of + * the iterator's own {@code remove} operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the - * Iterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or addAll + * {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} * operations. */ public Set keySet() { @@ -916,13 +917,13 @@ public Spliterator spliterator() { * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress - * (except through the iterator's own remove operation), + * (except through the iterator's own {@code remove} operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear operations. It does not - * support the add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. */ public Collection values() { Collection vs = values; @@ -933,7 +934,6 @@ public Collection values() { return vs; } - @WeakOuter private class Values extends AbstractCollection { public Iterator iterator() { return new ValueIterator(); @@ -963,14 +963,14 @@ public Spliterator spliterator() { * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through - * the iterator's own remove operation, or through the - * setValue operation on a map entry returned by the + * the iterator's own {@code remove} operation, or through the + * {@code setValue} operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll and - * clear operations. It does not support the - * add or addAll operations. + * mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and + * {@code clear} operations. It does not support the + * {@code add} or {@code addAll} operations. */ public Set> entrySet() { Set> es = entrySet; @@ -1119,8 +1119,8 @@ static final class KeySpliterator public KeySpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new KeySpliterator(map, lo, index = mid, est >>>= 1, - expectedModCount); + new KeySpliterator<>(map, lo, index = mid, est >>>= 1, + expectedModCount); } public void forEachRemaining(Consumer action) { @@ -1199,8 +1199,8 @@ static final class ValueSpliterator public ValueSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new ValueSpliterator(map, lo, index = mid, est >>>= 1, - expectedModCount); + new ValueSpliterator<>(map, lo, index = mid, est >>>= 1, + expectedModCount); } public void forEachRemaining(Consumer action) { @@ -1276,8 +1276,8 @@ static final class EntrySpliterator public EntrySpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new EntrySpliterator(map, lo, index = mid, est >>>= 1, - expectedModCount); + new EntrySpliterator<>(map, lo, index = mid, est >>>= 1, + expectedModCount); } @@ -1308,7 +1308,7 @@ public void forEachRemaining(Consumer> action) { @SuppressWarnings("unchecked") K k = (K) WeakHashMap.unmaskNull(x); action.accept - (new AbstractMap.SimpleImmutableEntry(k, v)); + (new AbstractMap.SimpleImmutableEntry<>(k, v)); } } } while (p != null || i < hi); @@ -1334,7 +1334,7 @@ public boolean tryAdvance(Consumer> action) { @SuppressWarnings("unchecked") K k = (K) WeakHashMap.unmaskNull(x); action.accept - (new AbstractMap.SimpleImmutableEntry(k, v)); + (new AbstractMap.SimpleImmutableEntry<>(k, v)); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/AbstractPipeline.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/AbstractPipeline.java index 8c1ee4d7c5..d4e9dc9a4f 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/AbstractPipeline.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/AbstractPipeline.java @@ -69,8 +69,9 @@ * @param type of output elements * @param type of the subclass implementing {@code BaseStream} * @since 1.8 - * @hide Visibility for CTS only (OpenJDK 8 streams tests). + * @hide Made public for CTS tests only (OpenJDK 8 streams tests). */ +// Android-changed: Made public for CTS tests only. public abstract class AbstractPipeline> extends PipelineHelper implements BaseStream { private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed"; @@ -245,6 +246,7 @@ final R evaluate(TerminalOp terminalOp) { * @return a flat array-backed Node that holds the collected output elements */ @SuppressWarnings("unchecked") + // Android-changed: Made public for CTS tests only. public final Node evaluateToArrayNode(IntFunction generator) { if (linkedOrConsumed) throw new IllegalStateException(MSG_STREAM_LINKED); @@ -383,6 +385,7 @@ public final boolean isParallel() { * intermediate operations * @see StreamOpFlag */ + // Android-changed: Made public for CTS tests only. public final int getStreamFlags() { return StreamOpFlag.toStreamFlags(combinedFlags); } @@ -504,6 +507,7 @@ final void copyIntoWithCancel(Sink wrappedSink, Spliterator s } @Override + // Android-changed: Made public for CTS tests only. public final int getStreamAndOpFlags() { return combinedFlags; } @@ -514,6 +518,7 @@ final boolean isOrdered() { @Override @SuppressWarnings("unchecked") + // Android-changed: Made public for CTS tests only. public final Sink wrapSink(Sink sink) { Objects.requireNonNull(sink); @@ -536,6 +541,7 @@ final Spliterator wrapSpliterator(Spliterator sourceSplitera @Override @SuppressWarnings("unchecked") + // Android-changed: Made public for CTS tests only. public final Node evaluate(Spliterator spliterator, boolean flatten, IntFunction generator) { @@ -561,6 +567,7 @@ public final Node evaluate(Spliterator spliterator, * * @return the output shape */ + // Android-changed: Made public for CTS tests only. public abstract StreamShape getOutputShape(); /** @@ -573,6 +580,7 @@ public final Node evaluate(Spliterator spliterator, * @param generator the array generator * @return a Node holding the output of the pipeline */ + // Android-changed: Made public for CTS tests only. public abstract Node evaluateToNode(PipelineHelper helper, Spliterator spliterator, boolean flattenTree, @@ -587,6 +595,7 @@ public abstract Node evaluateToNode(PipelineHelper helper, * @param supplier the supplier of a spliterator * @return a wrapping spliterator compatible with this shape */ + // Android-changed: Made public for CTS tests only. public abstract Spliterator wrap(PipelineHelper ph, Supplier> supplier, boolean isParallel); @@ -596,6 +605,7 @@ public abstract Spliterator wrap(PipelineHelper ph, * spliterator when a method is invoked on the lazy spliterator. * @param supplier the supplier of a spliterator */ + // Android-changed: Made public for CTS tests only. public abstract Spliterator lazySpliterator(Supplier> supplier); /** @@ -606,6 +616,7 @@ public abstract Spliterator wrap(PipelineHelper ph, * @param spliterator the spliterator to pull elements from * @param sink the sink to push elements to */ + // Android-changed: Made public for CTS tests only. public abstract void forEachWithCancel(Spliterator spliterator, Sink sink); /** @@ -624,6 +635,7 @@ public abstract Spliterator wrap(PipelineHelper ph, * @return a node builder */ @Override + // Android-changed: Made public for CTS tests only. public abstract Node.Builder makeNodeBuilder(long exactSizeIfKnown, IntFunction generator); @@ -638,6 +650,7 @@ public abstract Node.Builder makeNodeBuilder(long exactSizeIfKnown, * * @return {@code true} if this operation is stateful */ + // Android-changed: Made public for CTS tests only. public abstract boolean opIsStateful(); /** @@ -659,6 +672,7 @@ public abstract Node.Builder makeNodeBuilder(long exactSizeIfKnown, * each element, and passes the results (if any) to the provided * {@code Sink}. */ + // Android-changed: Made public for CTS tests only. public abstract Sink opWrapSink(int flags, Sink sink); /** @@ -676,6 +690,7 @@ public abstract Node.Builder makeNodeBuilder(long exactSizeIfKnown, * @param generator the array generator * @return a {@code Node} describing the result of the evaluation */ + // Android-changed: Made public for CTS tests only. public Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator) { @@ -703,6 +718,7 @@ public Node opEvaluateParallel(PipelineHelper helper, * @return a {@code Spliterator} describing the result of the evaluation */ @SuppressWarnings("unchecked") + // Android-changed: Made public for CTS tests only. public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { return opEvaluateParallel(helper, spliterator, i -> (E_OUT[]) new Object[i]).spliterator(); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/BaseStream.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/BaseStream.java index b0be0000ad..0328b25caf 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/BaseStream.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/BaseStream.java @@ -25,6 +25,8 @@ package java.util.stream; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collection; import java.util.Iterator; import java.util.Spliterator; @@ -51,7 +53,7 @@ * parallelism, which governs the behavior of all stream types. * * @param the type of the stream elements - * @param the type of of the stream implementing {@code BaseStream} + * @param the type of the stream implementing {@code BaseStream} * @since 1.8 * @see Stream * @see IntStream @@ -77,6 +79,14 @@ public interface BaseStream> *

      This is a terminal * operation. * + *

      + * The returned spliterator should report the set of characteristics derived + * from the stream pipeline (namely the characteristics derived from the + * stream source spliterator and the intermediate operations). + * Implementations may report a sub-set of those characteristics. For + * example, it may be too expensive to compute the entire set for some or + * all possible stream pipelines. + * * @return the element spliterator for this stream */ Spliterator spliterator(); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Collectors.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Collectors.java index a338ec236c..26d98bf6d4 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Collectors.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Collectors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -27,7 +27,6 @@ import java.util.AbstractMap; import java.util.AbstractSet; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -66,36 +65,37 @@ * common mutable reduction tasks: * *

      {@code
      - *     // Accumulate names into a List
      - *     List list = people.stream().map(Person::getName).collect(Collectors.toList());
      + * // Accumulate names into a List
      + * List list = people.stream()
      + *   .map(Person::getName)
      + *   .collect(Collectors.toList());
        *
      - *     // Accumulate names into a TreeSet
      - *     Set set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
      + * // Accumulate names into a TreeSet
      + * Set set = people.stream()
      + *   .map(Person::getName)
      + *   .collect(Collectors.toCollection(TreeSet::new));
        *
      - *     // Convert elements to strings and concatenate them, separated by commas
      - *     String joined = things.stream()
      - *                           .map(Object::toString)
      - *                           .collect(Collectors.joining(", "));
      + * // Convert elements to strings and concatenate them, separated by commas
      + * String joined = things.stream()
      + *   .map(Object::toString)
      + *   .collect(Collectors.joining(", "));
        *
      - *     // Compute sum of salaries of employee
      - *     int total = employees.stream()
      - *                          .collect(Collectors.summingInt(Employee::getSalary)));
      + * // Compute sum of salaries of employee
      + * int total = employees.stream()
      + *   .collect(Collectors.summingInt(Employee::getSalary));
        *
      - *     // Group employees by department
      - *     Map> byDept
      - *         = employees.stream()
      - *                    .collect(Collectors.groupingBy(Employee::getDepartment));
      + * // Group employees by department
      + * Map> byDept = employees.stream()
      + *   .collect(Collectors.groupingBy(Employee::getDepartment));
        *
      - *     // Compute sum of salaries by department
      - *     Map totalByDept
      - *         = employees.stream()
      - *                    .collect(Collectors.groupingBy(Employee::getDepartment,
      - *                                                   Collectors.summingInt(Employee::getSalary)));
      + * // Compute sum of salaries by department
      + * Map totalByDept = employees.stream()
      + *   .collect(Collectors.groupingBy(Employee::getDepartment,
      + *                                  Collectors.summingInt(Employee::getSalary)));
        *
      - *     // Partition students into passing and failing
      - *     Map> passingFailing =
      - *         students.stream()
      - *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
      + * // Partition students into passing and failing
      + * Map> passingFailing = students.stream()
      + *   .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
        *
        * }
      * @@ -116,21 +116,69 @@ public final class Collectors { = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED, Collector.Characteristics.IDENTITY_FINISH)); static final Set CH_NOID = Collections.emptySet(); + static final Set CH_UNORDERED_NOID + = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED)); private Collectors() { } /** - * Returns a merge function, suitable for use in - * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or - * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always - * throws {@code IllegalStateException}. This can be used to enforce the - * assumption that the elements being collected are distinct. - * - * @param the type of input arguments to the merge function - * @return a merge function which always throw {@code IllegalStateException} + * Construct an {@code IllegalStateException} with appropriate message. + * + * @param k the duplicate key + * @param u 1st value to be accumulated/merged + * @param v 2nd value to be accumulated/merged + */ + private static IllegalStateException duplicateKeyException( + Object k, Object u, Object v) { + return new IllegalStateException(String.format( + "Duplicate key %s (attempted merging values %s and %s)", + k, u, v)); + } + + /** + * {@code BinaryOperator} that merges the contents of its right + * argument into its left argument, throwing {@code IllegalStateException} + * if duplicate keys are encountered. + * + * @param type of the map keys + * @param type of the map values + * @param type of the map + * @return a merge function for two maps + */ + private static > + BinaryOperator uniqKeysMapMerger() { + return (m1, m2) -> { + for (Map.Entry e : m2.entrySet()) { + K k = e.getKey(); + V v = Objects.requireNonNull(e.getValue()); + V u = m1.putIfAbsent(k, v); + if (u != null) throw duplicateKeyException(k, u, v); + } + return m1; + }; + } + + /** + * {@code BiConsumer} that accumulates (key, value) pairs + * extracted from elements into the map, throwing {@code IllegalStateException} + * if duplicate keys are encountered. + * + * @param keyMapper a function that maps an element into a key + * @param valueMapper a function that maps an element into a value + * @param type of elements + * @param type of map keys + * @param type of map values + * @return an accumulating consumer */ - private static BinaryOperator throwingMerger() { - return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; + private static + BiConsumer, T> uniqKeysMapAccumulator(Function keyMapper, + Function valueMapper) { + return (map, element) -> { + K k = keyMapper.apply(element); + V v = Objects.requireNonNull(valueMapper.apply(element)); + V u = map.putIfAbsent(k, v); + if (u != null) throw duplicateKeyException(k, u, v); + }; } @SuppressWarnings("unchecked") @@ -203,8 +251,8 @@ public Set characteristics() { * * @param the type of the input elements * @param the type of the resulting {@code Collection} - * @param collectionFactory a {@code Supplier} which returns a new, empty - * {@code Collection} of the appropriate type + * @param collectionFactory a supplier providing a new empty {@code Collection} + * into which the results will be inserted * @return a {@code Collector} which collects all the input elements into a * {@code Collection}, in encounter order */ @@ -232,6 +280,26 @@ public Set characteristics() { CH_ID); } + /** + * Returns a {@code Collector} that accumulates the input elements into an + * unmodifiable List in encounter + * order. The returned Collector disallows null values and will throw + * {@code NullPointerException} if it is presented with a null value. + * + * @param the type of the input elements + * @return a {@code Collector} that accumulates the input elements into an + * unmodifiable List in encounter order + * @since 10 + */ + @SuppressWarnings("unchecked") + public static + Collector> toUnmodifiableList() { + return new CollectorImpl<>((Supplier>) ArrayList::new, List::add, + (left, right) -> { left.addAll(right); return left; }, + list -> (List)List.of(list.toArray()), + CH_NOID); + } + /** * Returns a {@code Collector} that accumulates the input elements into a * new {@code Set}. There are no guarantees on the type, mutability, @@ -249,10 +317,46 @@ public Set characteristics() { public static Collector> toSet() { return new CollectorImpl<>((Supplier>) HashSet::new, Set::add, - (left, right) -> { left.addAll(right); return left; }, + (left, right) -> { + if (left.size() < right.size()) { + right.addAll(left); return right; + } else { + left.addAll(right); return left; + } + }, CH_UNORDERED_ID); } + /** + * Returns a {@code Collector} that accumulates the input elements into an + * unmodifiable Set. The returned + * Collector disallows null values and will throw {@code NullPointerException} + * if it is presented with a null value. If the input contains duplicate elements, + * an arbitrary element of the duplicates is preserved. + * + *

      This is an {@link Collector.Characteristics#UNORDERED unordered} + * Collector. + * + * @param the type of the input elements + * @return a {@code Collector} that accumulates the input elements into an + * unmodifiable Set + * @since 10 + */ + @SuppressWarnings("unchecked") + public static + Collector> toUnmodifiableSet() { + return new CollectorImpl<>((Supplier>) HashSet::new, Set::add, + (left, right) -> { + if (left.size() < right.size()) { + right.addAll(left); return right; + } else { + left.addAll(right); return left; + } + }, + set -> (Set)Set.of(set.toArray()), + CH_UNORDERED_NOID); + } + /** * Returns a {@code Collector} that concatenates the input elements into a * {@code String}, in encounter order. @@ -333,9 +437,11 @@ BinaryOperator mapMerger(BinaryOperator mergeFunction) { * {@code partitioningBy}. For example, given a stream of * {@code Person}, to accumulate the set of last names in each city: *

      {@code
      -     *     Map> lastNamesByCity
      -     *         = people.stream().collect(groupingBy(Person::getCity,
      -     *                                              mapping(Person::getLastName, toSet())));
      +     * Map> lastNamesByCity
      +     *   = people.stream().collect(
      +     *     groupingBy(Person::getCity,
      +     *                mapping(Person::getLastName,
      +     *                        toSet())));
            * }
      * * @param the type of the input elements @@ -357,13 +463,113 @@ BinaryOperator mapMerger(BinaryOperator mergeFunction) { downstream.characteristics()); } + /** + * Adapts a {@code Collector} accepting elements of type {@code U} to one + * accepting elements of type {@code T} by applying a flat mapping function + * to each input element before accumulation. The flat mapping function + * maps an input element to a {@link Stream stream} covering zero or more + * output elements that are then accumulated downstream. Each mapped stream + * is {@link java.util.stream.BaseStream#close() closed} after its contents + * have been placed downstream. (If a mapped stream is {@code null} + * an empty stream is used, instead.) + * + * @apiNote + * The {@code flatMapping()} collectors are most useful when used in a + * multi-level reduction, such as downstream of a {@code groupingBy} or + * {@code partitioningBy}. For example, given a stream of + * {@code Order}, to accumulate the set of line items for each customer: + *
      {@code
      +     * Map> itemsByCustomerName
      +     *   = orders.stream().collect(
      +     *     groupingBy(Order::getCustomerName,
      +     *                flatMapping(order -> order.getLineItems().stream(),
      +     *                            toSet())));
      +     * }
      + * + * @param the type of the input elements + * @param type of elements accepted by downstream collector + * @param intermediate accumulation type of the downstream collector + * @param result type of collector + * @param mapper a function to be applied to the input elements, which + * returns a stream of results + * @param downstream a collector which will receive the elements of the + * stream returned by mapper + * @return a collector which applies the mapping function to the input + * elements and provides the flat mapped results to the downstream collector + * @since 9 + */ + public static + Collector flatMapping(Function> mapper, + Collector downstream) { + BiConsumer downstreamAccumulator = downstream.accumulator(); + return new CollectorImpl<>(downstream.supplier(), + (r, t) -> { + try (Stream result = mapper.apply(t)) { + if (result != null) + result.sequential().forEach(u -> downstreamAccumulator.accept(r, u)); + } + }, + downstream.combiner(), downstream.finisher(), + downstream.characteristics()); + } + + /** + * Adapts a {@code Collector} to one accepting elements of the same type + * {@code T} by applying the predicate to each input element and only + * accumulating if the predicate returns {@code true}. + * + * @apiNote + * The {@code filtering()} collectors are most useful when used in a + * multi-level reduction, such as downstream of a {@code groupingBy} or + * {@code partitioningBy}. For example, given a stream of + * {@code Employee}, to accumulate the employees in each department that have a + * salary above a certain threshold: + *
      {@code
      +     * Map> wellPaidEmployeesByDepartment
      +     *   = employees.stream().collect(
      +     *     groupingBy(Employee::getDepartment,
      +     *                filtering(e -> e.getSalary() > 2000,
      +     *                          toSet())));
      +     * }
      + * A filtering collector differs from a stream's {@code filter()} operation. + * In this example, suppose there are no employees whose salary is above the + * threshold in some department. Using a filtering collector as shown above + * would result in a mapping from that department to an empty {@code Set}. + * If a stream {@code filter()} operation were done instead, there would be + * no mapping for that department at all. + * + * @param the type of the input elements + * @param
      intermediate accumulation type of the downstream collector + * @param result type of collector + * @param predicate a predicate to be applied to the input elements + * @param downstream a collector which will accept values that match the + * predicate + * @return a collector which applies the predicate to the input elements + * and provides matching elements to the downstream collector + * @since 9 + */ + public static + Collector filtering(Predicate predicate, + Collector downstream) { + BiConsumer downstreamAccumulator = downstream.accumulator(); + return new CollectorImpl<>(downstream.supplier(), + (r, t) -> { + if (predicate.test(t)) { + downstreamAccumulator.accept(r, t); + } + }, + downstream.combiner(), downstream.finisher(), + downstream.characteristics()); + } + /** * Adapts a {@code Collector} to perform an additional finishing * transformation. For example, one could adapt the {@link #toList()} * collector to always produce an immutable list with: *
      {@code
      -     *     List people
      -     *         = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
      +     * List list = people.stream().collect(
      +     *   collectingAndThen(toList(),
      +     *                     Collections::unmodifiableList));
            * }
      * * @param the type of the input elements @@ -410,7 +616,7 @@ public static Collector collectingAndThen(Collector dow */ public static Collector counting() { - return reducing(0L, e -> 1L, Long::sum); + return summingLong(e -> 1L); } /** @@ -515,8 +721,9 @@ public static Collector collectingAndThen(Collector dow */ return new CollectorImpl<>( () -> new double[3], - (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); - a[2] += mapper.applyAsDouble(t);}, + (a, t) -> { double val = mapper.applyAsDouble(t); + sumWithCompensation(a, val); + a[2] += val;}, (a, b) -> { sumWithCompensation(a, b[0]); a[2] += b[2]; return sumWithCompensation(a, b[1]); }, @@ -565,8 +772,9 @@ static double computeFinalSum(double[] summands) { * the result is 0. * * @param the type of the input elements - * @param mapper a function extracting the property to be summed - * @return a {@code Collector} that produces the sum of a derived property + * @param mapper a function extracting the property to be averaged + * @return a {@code Collector} that produces the arithmetic mean of a + * derived property */ public static Collector averagingInt(ToIntFunction mapper) { @@ -583,8 +791,9 @@ static double computeFinalSum(double[] summands) { * the result is 0. * * @param the type of the input elements - * @param mapper a function extracting the property to be summed - * @return a {@code Collector} that produces the sum of a derived property + * @param mapper a function extracting the property to be averaged + * @return a {@code Collector} that produces the arithmetic mean of a + * derived property */ public static Collector averagingLong(ToLongFunction mapper) { @@ -614,8 +823,9 @@ static double computeFinalSum(double[] summands) { * 253, leading to additional numerical errors. * * @param the type of the input elements - * @param mapper a function extracting the property to be summed - * @return a {@code Collector} that produces the sum of a derived property + * @param mapper a function extracting the property to be averaged + * @return a {@code Collector} that produces the arithmetic mean of a + * derived property */ public static Collector averagingDouble(ToDoubleFunction mapper) { @@ -627,7 +837,7 @@ static double computeFinalSum(double[] summands) { */ return new CollectorImpl<>( () -> new double[4], - (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);}, + (a, t) -> { double val = mapper.applyAsDouble(t); sumWithCompensation(a, val); a[2]++; a[3]+= val;}, (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID); @@ -682,9 +892,11 @@ private static Supplier boxSupplier(T identity) { *

      For example, given a stream of {@code Person}, to calculate tallest * person in each city: *

      {@code
      -     *     Comparator byHeight = Comparator.comparing(Person::getHeight);
      -     *     Map tallestByCity
      -     *         = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight))));
      +     * Comparator byHeight = Comparator.comparing(Person::getHeight);
      +     * Map> tallestByCity
      +     *   = people.stream().collect(
      +     *     groupingBy(Person::getCity,
      +     *                reducing(BinaryOperator.maxBy(byHeight))));
            * }
      * * @param element type for the input and output of the reduction @@ -735,10 +947,13 @@ public void accept(T t) { *

      For example, given a stream of {@code Person}, to calculate the longest * last name of residents in each city: *

      {@code
      -     *     Comparator byLength = Comparator.comparing(String::length);
      -     *     Map longestLastNameByCity
      -     *         = people.stream().collect(groupingBy(Person::getCity,
      -     *                                              reducing(Person::getLastName, BinaryOperator.maxBy(byLength))));
      +     * Comparator byLength = Comparator.comparing(String::length);
      +     * Map longestLastNameByCity
      +     *   = people.stream().collect(
      +     *     groupingBy(Person::getCity,
      +     *                reducing("",
      +     *                         Person::getLastName,
      +     *                         BinaryOperator.maxBy(byLength))));
            * }
      * * @param the type of the input elements @@ -822,9 +1037,11 @@ public void accept(T t) { * *

      For example, to compute the set of last names of people in each city: *

      {@code
      -     *     Map> namesByCity
      -     *         = people.stream().collect(groupingBy(Person::getCity,
      -     *                                              mapping(Person::getLastName, toSet())));
      +     * Map> namesByCity
      +     *   = people.stream().collect(
      +     *     groupingBy(Person::getCity,
      +     *                mapping(Person::getLastName,
      +     *                        toSet())));
            * }
      * * @implNote @@ -869,9 +1086,12 @@ public void accept(T t) { *

      For example, to compute the set of last names of people in each city, * where the city names are sorted: *

      {@code
      -     *     Map> namesByCity
      -     *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
      -     *                                              mapping(Person::getLastName, toSet())));
      +     * Map> namesByCity
      +     *   = people.stream().collect(
      +     *     groupingBy(Person::getCity,
      +     *                TreeMap::new,
      +     *                mapping(Person::getLastName,
      +     *                        toSet())));
            * }
      * * @implNote @@ -889,8 +1109,8 @@ public void accept(T t) { * @param the type of the resulting {@code Map} * @param classifier a classifier function mapping input elements to keys * @param downstream a {@code Collector} implementing the downstream reduction - * @param mapFactory a function which, when called, produces a new empty - * {@code Map} of the desired type + * @param mapFactory a supplier providing a new empty {@code Map} + * into which the results will be inserted * @return a {@code Collector} implementing the cascaded group-by operation * * @see #groupingBy(Function, Collector) @@ -944,7 +1164,7 @@ public void accept(T t) { * function. * *

      There are no guarantees on the type, mutability, or serializability - * of the {@code Map} or {@code List} objects returned, or of the + * of the {@code ConcurrentMap} or {@code List} objects returned, or of the * thread-safety of the {@code List} objects returned. * @implSpec * This produces a result similar to: @@ -980,14 +1200,19 @@ public void accept(T t) { *

      The classification function maps elements to some key type {@code K}. * The downstream collector operates on elements of type {@code T} and * produces a result of type {@code D}. The resulting collector produces a - * {@code Map}. + * {@code ConcurrentMap}. + * + *

      There are no guarantees on the type, mutability, or serializability + * of the {@code ConcurrentMap} returned. * *

      For example, to compute the set of last names of people in each city, * where the city names are sorted: *

      {@code
      -     *     ConcurrentMap> namesByCity
      -     *         = people.stream().collect(groupingByConcurrent(Person::getCity,
      -     *                                                        mapping(Person::getLastName, toSet())));
      +     * ConcurrentMap> namesByCity
      +     *   = people.stream().collect(
      +     *     groupingByConcurrent(Person::getCity,
      +     *                          mapping(Person::getLastName,
      +     *                                  toSet())));
            * }
      * * @param the type of the input elements @@ -1022,17 +1247,19 @@ public void accept(T t) { *

      The classification function maps elements to some key type {@code K}. * The downstream collector operates on elements of type {@code T} and * produces a result of type {@code D}. The resulting collector produces a - * {@code Map}. + * {@code ConcurrentMap}. * *

      For example, to compute the set of last names of people in each city, * where the city names are sorted: *

      {@code
      -     *     ConcurrentMap> namesByCity
      -     *         = people.stream().collect(groupingBy(Person::getCity, ConcurrentSkipListMap::new,
      -     *                                              mapping(Person::getLastName, toSet())));
      +     * ConcurrentMap> namesByCity
      +     *   = people.stream().collect(
      +     *     groupingByConcurrent(Person::getCity,
      +     *                          ConcurrentSkipListMap::new,
      +     *                          mapping(Person::getLastName,
      +     *                                  toSet())));
            * }
      * - * * @param the type of the input elements * @param the type of the keys * @param
      the intermediate accumulation type of the downstream collector @@ -1040,8 +1267,8 @@ public void accept(T t) { * @param the type of the resulting {@code ConcurrentMap} * @param classifier a classifier function mapping input elements to keys * @param downstream a {@code Collector} implementing the downstream reduction - * @param mapFactory a function which, when called, produces a new empty - * {@code ConcurrentMap} of the desired type + * @param mapFactory a supplier providing a new empty {@code ConcurrentMap} + * into which the results will be inserted * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation * * @see #groupingByConcurrent(Function) @@ -1096,8 +1323,15 @@ public void accept(T t) { * to a {@code Predicate}, and organizes them into a * {@code Map>}. * + * The returned {@code Map} always contains mappings for both + * {@code false} and {@code true} keys. * There are no guarantees on the type, mutability, - * serializability, or thread-safety of the {@code Map} returned. + * serializability, or thread-safety of the {@code Map} or {@code List} + * returned. + * + * @apiNote + * If a partition has no elements, its value in the result Map will be + * an empty List. * * @param the type of the input elements * @param predicate a predicate used for classifying input elements @@ -1117,9 +1351,17 @@ public void accept(T t) { * {@code Map} whose values are the result of the downstream * reduction. * - *

      There are no guarantees on the type, mutability, + *

      + * The returned {@code Map} always contains mappings for both + * {@code false} and {@code true} keys. + * There are no guarantees on the type, mutability, * serializability, or thread-safety of the {@code Map} returned. * + * @apiNote + * If a partition has no elements, its value in the result Map will be + * obtained by calling the downstream collector's supplier function and then + * applying the finisher function. + * * @param the type of the input elements * @param the intermediate accumulation type of the downstream collector * @param the result type of the downstream reduction @@ -1160,12 +1402,15 @@ public void accept(T t) { * {@code Map} whose keys and values are the result of applying the provided * mapping functions to the input elements. * - *

      If the mapped keys contains duplicates (according to + *

      If the mapped keys contain duplicates (according to * {@link Object#equals(Object)}), an {@code IllegalStateException} is * thrown when the collection operation is performed. If the mapped keys - * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)} + * might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)} * instead. * + *

      There are no guarantees on the type, mutability, serializability, + * or thread-safety of the {@code Map} returned. + * * @apiNote * It is common for either the key or the value to be the input elements. * In this case, the utility method @@ -1173,16 +1418,18 @@ public void accept(T t) { * For example, the following produces a {@code Map} mapping * students to their grade point average: *

      {@code
      -     *     Map studentToGPA
      -     *         students.stream().collect(toMap(Functions.identity(),
      -     *                                         student -> computeGPA(student)));
      +     * Map studentToGPA
      +     *   = students.stream().collect(
      +     *     toMap(Function.identity(),
      +     *           student -> computeGPA(student)));
            * }
      * And the following produces a {@code Map} mapping a unique identifier to * students: *
      {@code
      -     *     Map studentIdToStudent
      -     *         students.stream().collect(toMap(Student::getId,
      -     *                                         Functions.identity());
      +     * Map studentIdToStudent
      +     *   = students.stream().collect(
      +     *     toMap(Student::getId,
      +     *           Function.identity()));
            * }
      * * @implNote @@ -1209,7 +1456,49 @@ public void accept(T t) { public static Collector> toMap(Function keyMapper, Function valueMapper) { - return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); + return new CollectorImpl<>(HashMap::new, + uniqKeysMapAccumulator(keyMapper, valueMapper), + uniqKeysMapMerger(), + CH_ID); + } + + /** + * Returns a {@code Collector} that accumulates the input elements into an + *
      unmodifiable Map, + * whose keys and values are the result of applying the provided + * mapping functions to the input elements. + * + *

      If the mapped keys contain duplicates (according to + * {@link Object#equals(Object)}), an {@code IllegalStateException} is + * thrown when the collection operation is performed. If the mapped keys + * might have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)} + * to handle merging of the values. + * + *

      The returned Collector disallows null keys and values. If either mapping function + * returns null, {@code NullPointerException} will be thrown. + * + * @param the type of the input elements + * @param the output type of the key mapping function + * @param the output type of the value mapping function + * @param keyMapper a mapping function to produce keys, must be non-null + * @param valueMapper a mapping function to produce values, must be non-null + * @return a {@code Collector} that accumulates the input elements into an + * unmodifiable Map, whose keys and values + * are the result of applying the provided mapping functions to the input elements + * @throws NullPointerException if either keyMapper or valueMapper is null + * + * @see #toUnmodifiableMap(Function, Function, BinaryOperator) + * @since 10 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static + Collector> toUnmodifiableMap(Function keyMapper, + Function valueMapper) { + Objects.requireNonNull(keyMapper, "keyMapper"); + Objects.requireNonNull(valueMapper, "valueMapper"); + return collectingAndThen( + toMap(keyMapper, valueMapper), + map -> (Map)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0]))); } /** @@ -1218,10 +1507,13 @@ public void accept(T t) { * mapping functions to the input elements. * *

      If the mapped - * keys contains duplicates (according to {@link Object#equals(Object)}), + * keys contain duplicates (according to {@link Object#equals(Object)}), * the value mapping function is applied to each equal element, and the * results are merged using the provided merging function. * + *

      There are no guarantees on the type, mutability, serializability, + * or thread-safety of the {@code Map} returned. + * * @apiNote * There are multiple ways to deal with collisions between multiple elements * mapping to the same key. The other forms of {@code toMap} simply use @@ -1229,13 +1521,14 @@ public void accept(T t) { * more flexible merge policies. For example, if you have a stream * of {@code Person}, and you want to produce a "phone book" mapping name to * address, but it is possible that two persons have the same name, you can - * do as follows to gracefully deals with these collisions, and produce a + * do as follows to gracefully deal with these collisions, and produce a * {@code Map} mapping names to a concatenated list of addresses: *

      {@code
      -     *     Map phoneBook
      -     *         people.stream().collect(toMap(Person::getName,
      -     *                                       Person::getAddress,
      -     *                                       (s, a) -> s + ", " + a));
      +     * Map phoneBook
      +     *   = people.stream().collect(
      +     *     toMap(Person::getName,
      +     *           Person::getAddress,
      +     *           (s, a) -> s + ", " + a));
            * }
      * * @implNote @@ -1271,13 +1564,58 @@ public void accept(T t) { return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); } + + /** + * Returns a {@code Collector} that accumulates the input elements into an + * unmodifiable Map, + * whose keys and values are the result of applying the provided + * mapping functions to the input elements. + * + *

      If the mapped + * keys contain duplicates (according to {@link Object#equals(Object)}), + * the value mapping function is applied to each equal element, and the + * results are merged using the provided merging function. + * + *

      The returned Collector disallows null keys and values. If either mapping function + * returns null, {@code NullPointerException} will be thrown. + * + * @param the type of the input elements + * @param the output type of the key mapping function + * @param the output type of the value mapping function + * @param keyMapper a mapping function to produce keys, must be non-null + * @param valueMapper a mapping function to produce values, must be non-null + * @param mergeFunction a merge function, used to resolve collisions between + * values associated with the same key, as supplied + * to {@link Map#merge(Object, Object, BiFunction)}, + * must be non-null + * @return a {@code Collector} that accumulates the input elements into an + * unmodifiable Map, whose keys and values + * are the result of applying the provided mapping functions to the input elements + * @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null + * + * @see #toUnmodifiableMap(Function, Function) + * @since 10 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static + Collector> toUnmodifiableMap(Function keyMapper, + Function valueMapper, + BinaryOperator mergeFunction) { + Objects.requireNonNull(keyMapper, "keyMapper"); + Objects.requireNonNull(valueMapper, "valueMapper"); + Objects.requireNonNull(mergeFunction, "mergeFunction"); + return collectingAndThen( + toMap(keyMapper, valueMapper, mergeFunction, HashMap::new), + map -> (Map)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0]))); + } + /** * Returns a {@code Collector} that accumulates elements into a * {@code Map} whose keys and values are the result of applying the provided * mapping functions to the input elements. * *

      If the mapped - * keys contains duplicates (according to {@link Object#equals(Object)}), + * keys contain duplicates (according to {@link Object#equals(Object)}), * the value mapping function is applied to each equal element, and the * results are merged using the provided merging function. The {@code Map} * is created by a provided supplier function. @@ -1299,8 +1637,8 @@ public void accept(T t) { * @param mergeFunction a merge function, used to resolve collisions between * values associated with the same key, as supplied * to {@link Map#merge(Object, Object, BiFunction)} - * @param mapSupplier a function which returns a new, empty {@code Map} into - * which the results will be inserted + * @param mapFactory a supplier providing a new empty {@code Map} + * into which the results will be inserted * @return a {@code Collector} which collects elements into a {@code Map} * whose keys are the result of applying a key mapping function to the input * elements, and whose values are the result of applying a value mapping @@ -1313,13 +1651,13 @@ public void accept(T t) { */ public static > Collector toMap(Function keyMapper, - Function valueMapper, - BinaryOperator mergeFunction, - Supplier mapSupplier) { + Function valueMapper, + BinaryOperator mergeFunction, + Supplier mapFactory) { BiConsumer accumulator = (map, element) -> map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction); - return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); + return new CollectorImpl<>(mapFactory, accumulator, mapMerger(mergeFunction), CH_ID); } /** @@ -1327,29 +1665,34 @@ public void accept(T t) { * {@code ConcurrentMap} whose keys and values are the result of applying * the provided mapping functions to the input elements. * - *

      If the mapped keys contains duplicates (according to + *

      If the mapped keys contain duplicates (according to * {@link Object#equals(Object)}), an {@code IllegalStateException} is * thrown when the collection operation is performed. If the mapped keys * may have duplicates, use * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead. * + *

      There are no guarantees on the type, mutability, or serializability + * of the {@code ConcurrentMap} returned. + * * @apiNote * It is common for either the key or the value to be the input elements. * In this case, the utility method * {@link java.util.function.Function#identity()} may be helpful. - * For example, the following produces a {@code Map} mapping + * For example, the following produces a {@code ConcurrentMap} mapping * students to their grade point average: *

      {@code
      -     *     Map studentToGPA
      -     *         students.stream().collect(toMap(Functions.identity(),
      -     *                                         student -> computeGPA(student)));
      +     * ConcurrentMap studentToGPA
      +     *   = students.stream().collect(
      +     *     toConcurrentMap(Function.identity(),
      +     *                     student -> computeGPA(student)));
            * }
      - * And the following produces a {@code Map} mapping a unique identifier to - * students: + * And the following produces a {@code ConcurrentMap} mapping a + * unique identifier to students: *
      {@code
      -     *     Map studentIdToStudent
      -     *         students.stream().collect(toConcurrentMap(Student::getId,
      -     *                                                   Functions.identity());
      +     * ConcurrentMap studentIdToStudent
      +     *   = students.stream().collect(
      +     *     toConcurrentMap(Student::getId,
      +     *                     Function.identity()));
            * }
      * *

      This is a {@link Collector.Characteristics#CONCURRENT concurrent} and @@ -1372,7 +1715,10 @@ public void accept(T t) { public static Collector> toConcurrentMap(Function keyMapper, Function valueMapper) { - return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new); + return new CollectorImpl<>(ConcurrentHashMap::new, + uniqKeysMapAccumulator(keyMapper, valueMapper), + uniqKeysMapMerger(), + CH_CONCURRENT_ID); } /** @@ -1380,10 +1726,13 @@ public void accept(T t) { * {@code ConcurrentMap} whose keys and values are the result of applying * the provided mapping functions to the input elements. * - *

      If the mapped keys contains duplicates (according to {@link Object#equals(Object)}), + *

      If the mapped keys contain duplicates (according to {@link Object#equals(Object)}), * the value mapping function is applied to each equal element, and the * results are merged using the provided merging function. * + *

      There are no guarantees on the type, mutability, or serializability + * of the {@code ConcurrentMap} returned. + * * @apiNote * There are multiple ways to deal with collisions between multiple elements * mapping to the same key. The other forms of {@code toConcurrentMap} simply use @@ -1391,13 +1740,14 @@ public void accept(T t) { * more flexible merge policies. For example, if you have a stream * of {@code Person}, and you want to produce a "phone book" mapping name to * address, but it is possible that two persons have the same name, you can - * do as follows to gracefully deals with these collisions, and produce a - * {@code Map} mapping names to a concatenated list of addresses: + * do as follows to gracefully deal with these collisions, and produce a + * {@code ConcurrentMap} mapping names to a concatenated list of addresses: *

      {@code
      -     *     Map phoneBook
      -     *         people.stream().collect(toConcurrentMap(Person::getName,
      -     *                                                 Person::getAddress,
      -     *                                                 (s, a) -> s + ", " + a));
      +     * ConcurrentMap phoneBook
      +     *   = people.stream().collect(
      +     *     toConcurrentMap(Person::getName,
      +     *                     Person::getAddress,
      +     *                     (s, a) -> s + ", " + a));
            * }
      * *

      This is a {@link Collector.Characteristics#CONCURRENT concurrent} and @@ -1434,7 +1784,7 @@ public void accept(T t) { * {@code ConcurrentMap} whose keys and values are the result of applying * the provided mapping functions to the input elements. * - *

      If the mapped keys contains duplicates (according to {@link Object#equals(Object)}), + *

      If the mapped keys contain duplicates (according to {@link Object#equals(Object)}), * the value mapping function is applied to each equal element, and the * results are merged using the provided merging function. The * {@code ConcurrentMap} is created by a provided supplier function. @@ -1451,8 +1801,8 @@ public void accept(T t) { * @param mergeFunction a merge function, used to resolve collisions between * values associated with the same key, as supplied * to {@link Map#merge(Object, Object, BiFunction)} - * @param mapSupplier a function which returns a new, empty {@code Map} into - * which the results will be inserted + * @param mapFactory a supplier providing a new empty {@code ConcurrentMap} + * into which the results will be inserted * @return a concurrent, unordered {@code Collector} which collects elements into a * {@code ConcurrentMap} whose keys are the result of applying a key mapping * function to the input elements, and whose values are the result of @@ -1467,11 +1817,11 @@ public void accept(T t) { Collector toConcurrentMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction, - Supplier mapSupplier) { + Supplier mapFactory) { BiConsumer accumulator = (map, element) -> map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction); - return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID); + return new CollectorImpl<>(mapFactory, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID); } /** @@ -1550,12 +1900,12 @@ private static final class Partition @Override public Set> entrySet() { - return new AbstractSet>() { + return new AbstractSet<>() { @Override public Iterator> iterator() { Map.Entry falseEntry = new SimpleImmutableEntry<>(false, forFalse); Map.Entry trueEntry = new SimpleImmutableEntry<>(true, forTrue); - return Arrays.asList(falseEntry, trueEntry).iterator(); + return List.of(falseEntry, trueEntry).iterator(); } @Override diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DistinctOps.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DistinctOps.java index 0b7713e4f2..22fbe052e7 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DistinctOps.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DistinctOps.java @@ -65,6 +65,7 @@ Node reduce(PipelineHelper helper, Spliterator spliterator) { } @Override + // Android-changed: Make public, to match the method it's overriding. public Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator) { @@ -100,6 +101,7 @@ else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { } @Override + // Android-changed: Make public, to match the method it's overriding. public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) { // No-op @@ -116,6 +118,7 @@ else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { } @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { Objects.requireNonNull(sink); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoublePipeline.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoublePipeline.java index e5c06c6ce8..38aa5d3f04 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoublePipeline.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoublePipeline.java @@ -52,6 +52,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public abstract class DoublePipeline extends AbstractPipeline implements DoubleStream { @@ -128,11 +129,13 @@ private static Spliterator.OfDouble adapt(Spliterator s) { // Shape-specific methods @Override + // Android-changed: Make public, to match the method it's overriding. public final StreamShape getOutputShape() { return StreamShape.DOUBLE_VALUE; } @Override + // Android-changed: Make public, to match the method it's overriding. public final Node evaluateToNode(PipelineHelper helper, Spliterator spliterator, boolean flattenTree, @@ -141,6 +144,7 @@ public final Node evaluateToNode(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public final Spliterator wrap(PipelineHelper ph, Supplier> supplier, boolean isParallel) { @@ -149,11 +153,13 @@ public final Spliterator wrap(PipelineHelper ph, @Override @SuppressWarnings("unchecked") + // Android-changed: Make public, to match the method it's overriding. public final Spliterator.OfDouble lazySpliterator(Supplier> supplier) { return new StreamSpliterators.DelegatingSpliterator.OfDouble((Supplier) supplier); } @Override + // Android-changed: Make public, to match the method it's overriding. public final void forEachWithCancel(Spliterator spliterator, Sink sink) { Spliterator.OfDouble spl = adapt(spliterator); DoubleConsumer adaptedSink = adapt(sink); @@ -161,6 +167,7 @@ public final void forEachWithCancel(Spliterator spliterator, Sink makeNodeBuilder(long exactSizeIfKnown, IntFunction generator) { return Nodes.doubleBuilder(exactSizeIfKnown); } @@ -191,6 +198,7 @@ public final DoubleStream map(DoubleUnaryOperator mapper) { return new StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -208,6 +216,7 @@ public final Stream mapToObj(DoubleFunction mapper) { return new ReferencePipeline.StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -225,6 +234,7 @@ public final IntStream mapToInt(DoubleToIntFunction mapper) { return new IntPipeline.StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -242,6 +252,7 @@ public final LongStream mapToLong(DoubleToLongFunction mapper) { return new LongPipeline.StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -258,6 +269,7 @@ public final DoubleStream flatMap(DoubleFunction mapper) return new StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -284,6 +296,7 @@ public DoubleStream unordered() { return this; return new StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_ORDERED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return sink; } @@ -296,6 +309,7 @@ public final DoubleStream filter(DoublePredicate predicate) { return new StatelessOp(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -319,6 +333,7 @@ public final DoubleStream peek(DoubleConsumer action) { return new StatelessOp(this, StreamShape.DOUBLE_VALUE, 0) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { @Override @@ -514,8 +529,9 @@ public final double[] toArray() { * Source stage of a DoubleStream * * @param type of elements in the upstream source - * @hide Visibility for CTS only (OpenJDK 8 streams tests). + * @hide Made public for CTS tests only (OpenJDK 8 streams tests). */ + // Android-changed: Made public for CTS tests only. public static class Head extends DoublePipeline { /** * Constructor for the source stage of a DoubleStream. @@ -526,6 +542,7 @@ public static class Head extends DoublePipeline { * in {@link StreamOpFlag} * @param parallel {@code true} if the pipeline is parallel */ + // Android-changed: Made public for CTS tests only. public Head(Supplier> source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); @@ -539,17 +556,20 @@ public Head(Supplier> source, * in {@link StreamOpFlag} * @param parallel {@code true} if the pipeline is parallel */ + // Android-changed: Made public for CTS tests only. public Head(Spliterator source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); } @Override + // Android-changed: Made public for CTS tests only. public final boolean opIsStateful() { throw new UnsupportedOperationException(); } @Override + // Android-changed: Made public for CTS tests only. public final Sink opWrapSink(int flags, Sink sink) { throw new UnsupportedOperationException(); } @@ -585,6 +605,7 @@ public void forEachOrdered(DoubleConsumer consumer) { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatelessOp extends DoublePipeline { /** * Construct a new DoubleStream by appending a stateless intermediate @@ -594,6 +615,7 @@ public abstract static class StatelessOp extends DoublePipeline { * @param inputShape the stream shape for the upstream pipeline stage * @param opFlags operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatelessOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -602,6 +624,7 @@ public StatelessOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return false; } @@ -614,6 +637,7 @@ public final boolean opIsStateful() { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatefulOp extends DoublePipeline { /** * Construct a new DoubleStream by appending a stateful intermediate @@ -623,6 +647,7 @@ public abstract static class StatefulOp extends DoublePipeline { * @param inputShape the stream shape for the upstream pipeline stage * @param opFlags operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatefulOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -631,11 +656,13 @@ public StatefulOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return true; } @Override + // Android-changed: Make public, to match the method it's overriding. public abstract Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoubleStream.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoubleStream.java index 347587ece3..4d5d23d49e 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoubleStream.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/DoubleStream.java @@ -25,6 +25,8 @@ package java.util.stream; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.DoubleSummaryStatistics; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/IntPipeline.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/IntPipeline.java index 0154127fb4..b542b80c29 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/IntPipeline.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/IntPipeline.java @@ -51,6 +51,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public abstract class IntPipeline extends AbstractPipeline implements IntStream { @@ -131,11 +132,13 @@ private static Spliterator.OfInt adapt(Spliterator s) { // Shape-specific methods @Override + // Android-changed: Make public, to match the method it's overriding. public final StreamShape getOutputShape() { return StreamShape.INT_VALUE; } @Override + // Android-changed: Make public, to match the method it's overriding. public final Node evaluateToNode(PipelineHelper helper, Spliterator spliterator, boolean flattenTree, @@ -144,6 +147,7 @@ public final Node evaluateToNode(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public final Spliterator wrap(PipelineHelper ph, Supplier> supplier, boolean isParallel) { @@ -152,11 +156,13 @@ public final Spliterator wrap(PipelineHelper ph, @Override @SuppressWarnings("unchecked") + // Android-changed: Make public, to match the method it's overriding. public final Spliterator.OfInt lazySpliterator(Supplier> supplier) { return new StreamSpliterators.DelegatingSpliterator.OfInt((Supplier) supplier); } @Override + // Android-changed: Make public, to match the method it's overriding. public final void forEachWithCancel(Spliterator spliterator, Sink sink) { Spliterator.OfInt spl = adapt(spliterator); IntConsumer adaptedSink = adapt(sink); @@ -164,6 +170,7 @@ public final void forEachWithCancel(Spliterator spliterator, Sink makeNodeBuilder(long exactSizeIfKnown, IntFunction generator) { return Nodes.intBuilder(exactSizeIfKnown); @@ -205,6 +212,7 @@ public final DoubleStream asDoubleStream() { return new DoublePipeline.StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -227,6 +235,7 @@ public final IntStream map(IntUnaryOperator mapper) { return new StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -244,6 +253,7 @@ public final Stream mapToObj(IntFunction mapper) { return new ReferencePipeline.StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -261,6 +271,7 @@ public final LongStream mapToLong(IntToLongFunction mapper) { return new LongPipeline.StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -278,6 +289,7 @@ public final DoubleStream mapToDouble(IntToDoubleFunction mapper) { return new DoublePipeline.StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -294,6 +306,7 @@ public final IntStream flatMap(IntFunction mapper) { return new StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -320,6 +333,7 @@ public IntStream unordered() { return this; return new StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_ORDERED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return sink; } @@ -332,6 +346,7 @@ public final IntStream filter(IntPredicate predicate) { return new StatelessOp(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -355,6 +370,7 @@ public final IntStream peek(IntConsumer action) { return new StatelessOp(this, StreamShape.INT_VALUE, 0) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { @Override @@ -513,6 +529,7 @@ public final int[] toArray() { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public static class Head extends IntPipeline { /** * Constructor for the source stage of an IntStream. @@ -523,6 +540,7 @@ public static class Head extends IntPipeline { * in {@link StreamOpFlag} * @param parallel {@code true} if the pipeline is parallel */ + // Android-changed: Made public for CTS tests only. public Head(Supplier> source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); @@ -536,17 +554,20 @@ public Head(Supplier> source, * in {@link StreamOpFlag} * @param parallel {@code true} if the pipeline is parallel */ + // Android-changed: Made public for CTS tests only. public Head(Spliterator source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { throw new UnsupportedOperationException(); } @Override + // Android-changed: Make public, to match the method it's overriding. public final Sink opWrapSink(int flags, Sink sink) { throw new UnsupportedOperationException(); } @@ -581,6 +602,7 @@ public void forEachOrdered(IntConsumer action) { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatelessOp extends IntPipeline { /** * Construct a new IntStream by appending a stateless intermediate @@ -589,6 +611,7 @@ public abstract static class StatelessOp extends IntPipeline { * @param inputShape The stream shape for the upstream pipeline stage * @param opFlags Operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatelessOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -597,6 +620,7 @@ public StatelessOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return false; } @@ -609,6 +633,7 @@ public final boolean opIsStateful() { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatefulOp extends IntPipeline { /** * Construct a new IntStream by appending a stateful intermediate @@ -617,6 +642,7 @@ public abstract static class StatefulOp extends IntPipeline { * @param inputShape The stream shape for the upstream pipeline stage * @param opFlags Operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatefulOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -625,11 +651,13 @@ public StatefulOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return true; } @Override + // Android-changed: Make public, to match the method it's overriding. public abstract Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongPipeline.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongPipeline.java index 4819da2de7..5d737f1b5e 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongPipeline.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongPipeline.java @@ -52,6 +52,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public abstract class LongPipeline extends AbstractPipeline implements LongStream { @@ -129,11 +130,13 @@ private static Spliterator.OfLong adapt(Spliterator s) { // Shape-specific methods @Override + // Android-changed: Make public, to match the method it's overriding. public final StreamShape getOutputShape() { return StreamShape.LONG_VALUE; } @Override + // Android-changed: Make public, to match the method it's overriding. public final Node evaluateToNode(PipelineHelper helper, Spliterator spliterator, boolean flattenTree, @@ -142,6 +145,7 @@ public final Node evaluateToNode(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public final Spliterator wrap(PipelineHelper ph, Supplier> supplier, boolean isParallel) { @@ -150,11 +154,13 @@ public final Spliterator wrap(PipelineHelper ph, @Override @SuppressWarnings("unchecked") + // Android-changed: Make public, to match the method it's overriding. public final Spliterator.OfLong lazySpliterator(Supplier> supplier) { return new StreamSpliterators.DelegatingSpliterator.OfLong((Supplier) supplier); } @Override + // Android-changed: Make public, to match the method it's overriding. public final void forEachWithCancel(Spliterator spliterator, Sink sink) { Spliterator.OfLong spl = adapt(spliterator); LongConsumer adaptedSink = adapt(sink); @@ -162,6 +168,7 @@ public final void forEachWithCancel(Spliterator spliterator, Sink si } @Override + // Android-changed: Make public, to match the method it's overriding. public final Node.Builder makeNodeBuilder(long exactSizeIfKnown, IntFunction generator) { return Nodes.longBuilder(exactSizeIfKnown); } @@ -186,6 +193,7 @@ public final DoubleStream asDoubleStream() { return new DoublePipeline.StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -208,6 +216,7 @@ public final LongStream map(LongUnaryOperator mapper) { return new StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -225,6 +234,7 @@ public final Stream mapToObj(LongFunction mapper) { return new ReferencePipeline.StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -242,6 +252,7 @@ public final IntStream mapToInt(LongToIntFunction mapper) { return new IntPipeline.StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -259,6 +270,7 @@ public final DoubleStream mapToDouble(LongToDoubleFunction mapper) { return new DoublePipeline.StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -275,6 +287,7 @@ public final LongStream flatMap(LongFunction mapper) { return new StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -301,6 +314,7 @@ public LongStream unordered() { return this; return new StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_ORDERED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return sink; } @@ -313,6 +327,7 @@ public final LongStream filter(LongPredicate predicate) { return new StatelessOp(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -336,6 +351,7 @@ public final LongStream peek(LongConsumer action) { return new StatelessOp(this, StreamShape.LONG_VALUE, 0) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { @Override @@ -494,8 +510,9 @@ public final long[] toArray() { * * @param type of elements in the upstream source * @since 1.8 - * @hide Visibility for CTS only (OpenJDK 8 streams tests). + * @hide Made public for CTS tests only (OpenJDK 8 streams tests). */ + // Android-changed: Made public for CTS tests only. public static class Head extends LongPipeline { /** * Constructor for the source stage of a LongStream. @@ -506,6 +523,7 @@ public static class Head extends LongPipeline { * in {@link StreamOpFlag} * @param parallel {@code true} if the pipeline is parallel */ + // Android-changed: Made public for CTS tests only. public Head(Supplier> source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); @@ -519,17 +537,20 @@ public Head(Supplier> source, * in {@link StreamOpFlag} * @param parallel {@code true} if the pipeline is parallel */ + // Android-changed: Made public for CTS tests only. public Head(Spliterator source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { throw new UnsupportedOperationException(); } @Override + // Android-changed: Make public, to match the method it's overriding. public final Sink opWrapSink(int flags, Sink sink) { throw new UnsupportedOperationException(); } @@ -561,6 +582,7 @@ public void forEachOrdered(LongConsumer action) { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatelessOp extends LongPipeline { /** * Construct a new LongStream by appending a stateless intermediate @@ -569,6 +591,7 @@ public abstract static class StatelessOp extends LongPipeline { * @param inputShape The stream shape for the upstream pipeline stage * @param opFlags Operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatelessOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -577,6 +600,7 @@ public StatelessOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return false; } @@ -589,6 +613,7 @@ public final boolean opIsStateful() { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatefulOp extends LongPipeline { /** * Construct a new LongStream by appending a stateful intermediate @@ -598,6 +623,7 @@ public abstract static class StatefulOp extends LongPipeline { * @param opFlags Operation flags for the new stage * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public StatefulOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -606,11 +632,13 @@ public StatefulOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return true; } @Override + // Android-changed: Make public, to match the method it's overriding. public abstract Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongStream.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongStream.java index 84189efb4e..a2d429e5a1 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongStream.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/LongStream.java @@ -24,8 +24,9 @@ */ package java.util.stream; -import java.math.BigInteger; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.LongSummaryStatistics; @@ -791,11 +792,7 @@ public static LongStream range(long startInclusive, final long endExclusive) { // Split the range in two and concatenate // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE) then // the lower range, [Long.MIN_VALUE, 0) will be further split in two - // Android-changed: no divideUnsigned support yet, use BigInteger instead. - long m = startInclusive + - BigInteger.valueOf(endExclusive).subtract(BigInteger.valueOf(startInclusive)) - .divide(BigInteger.valueOf(2)).longValue() + 1; - + long m = startInclusive + Long.divideUnsigned(endExclusive - startInclusive, 2) + 1; return concat(range(startInclusive, m), range(m, endExclusive)); } else { return StreamSupport.longStream( @@ -829,11 +826,7 @@ public static LongStream rangeClosed(long startInclusive, final long endInclusiv // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then // the lower range, [Long.MIN_VALUE, 0), and upper range, // [0, Long.MAX_VALUE], will both be further split in two - // Android-changed: no divideUnsigned support yet, use BigInteger instead. - long m = startInclusive + - BigInteger.valueOf(endInclusive).subtract(BigInteger.valueOf(startInclusive)) - .divide(BigInteger.valueOf(2)).longValue() + 1; - + long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1; return concat(range(startInclusive, m), rangeClosed(m, endInclusive)); } else { return StreamSupport.longStream( diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/MatchOps.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/MatchOps.java index cc809e4ace..dbaab0ab6b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/MatchOps.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/MatchOps.java @@ -249,7 +249,7 @@ public Boolean evaluateParallel(PipelineHelper helper, * * @param The output type of the stream pipeline */ - private static abstract class BooleanTerminalSink implements Sink { + private abstract static class BooleanTerminalSink implements Sink { boolean stop; boolean value; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Node.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Node.java index e6aa538ca5..db9c10da72 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Node.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Node.java @@ -58,6 +58,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public interface Node { /** diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/PipelineHelper.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/PipelineHelper.java index 06a4f92fd3..832d68aeca 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/PipelineHelper.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/PipelineHelper.java @@ -53,6 +53,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public abstract class PipelineHelper { /** @@ -70,6 +71,7 @@ public abstract class PipelineHelper { * @return the combined stream and operation flags * @see StreamOpFlag */ + // Android-changed: Made public for CTS tests only. public abstract int getStreamAndOpFlags(); /** @@ -151,6 +153,7 @@ public abstract class PipelineHelper { * @return a {@code Sink} that implements the pipeline stages and sends * results to the provided {@code Sink} */ + // Android-changed: Made public for CTS tests only. public abstract Sink wrapSink(Sink sink); /** @@ -198,6 +201,7 @@ abstract Node.Builder makeNodeBuilder(long exactSizeIfKnown, * @param generator a factory function for array instances * @return the {@code Node} containing all output elements */ + // Android-changed: Made public for CTS tests only. public abstract Node evaluate(Spliterator spliterator, boolean flatten, IntFunction generator); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/ReferencePipeline.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/ReferencePipeline.java index ddec43ef3d..84ec8c5fa8 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/ReferencePipeline.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/ReferencePipeline.java @@ -55,6 +55,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public abstract class ReferencePipeline extends AbstractPipeline> implements Stream { @@ -98,11 +99,13 @@ public abstract class ReferencePipeline // Shape-specific methods @Override + // Android-changed: Make public, to match the method it's overriding. public final StreamShape getOutputShape() { return StreamShape.REFERENCE; } @Override + // Android-changed: Make public, to match the method it's overriding. public final Node evaluateToNode(PipelineHelper helper, Spliterator spliterator, boolean flattenTree, @@ -111,6 +114,7 @@ public final Node evaluateToNode(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public final Spliterator wrap(PipelineHelper ph, Supplier> supplier, boolean isParallel) { @@ -118,16 +122,19 @@ public final Spliterator wrap(PipelineHelper ph, } @Override + // Android-changed: Make public, to match the method it's overriding. public final Spliterator lazySpliterator(Supplier> supplier) { return new StreamSpliterators.DelegatingSpliterator<>(supplier); } @Override + // Android-changed: Make public, to match the method it's overriding. public final void forEachWithCancel(Spliterator spliterator, Sink sink) { do { } while (!sink.cancellationRequested() && spliterator.tryAdvance(sink)); } @Override + // Android-changed: Make public, to match the method it's overriding. public final Node.Builder makeNodeBuilder(long exactSizeIfKnown, IntFunction generator) { return Nodes.builder(exactSizeIfKnown, generator); } @@ -151,6 +158,7 @@ public Stream unordered() { return this; return new StatelessOp(this, StreamShape.REFERENCE, StreamOpFlag.NOT_ORDERED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return sink; } @@ -163,6 +171,7 @@ public final Stream filter(Predicate predicate) { return new StatelessOp(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { @Override @@ -204,6 +213,7 @@ public final IntStream mapToInt(ToIntFunction mapper) { return new IntPipeline.StatelessOp(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { @Override @@ -221,6 +231,7 @@ public final LongStream mapToLong(ToLongFunction mapper) { return new LongPipeline.StatelessOp(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { @Override @@ -238,6 +249,7 @@ public final DoubleStream mapToDouble(ToDoubleFunction mapper) { return new DoublePipeline.StatelessOp(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { @Override @@ -283,6 +295,7 @@ public final IntStream flatMapToInt(Function return new IntPipeline.StatelessOp(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { IntConsumer downstreamAsInt = downstream::accept; @@ -311,6 +324,7 @@ public final DoubleStream flatMapToDouble(Function(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { DoubleConsumer downstreamAsDouble = downstream::accept; @@ -339,6 +353,7 @@ public final LongStream flatMapToLong(Function(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { LongConsumer downstreamAsLong = downstream::accept; @@ -366,6 +381,7 @@ public final Stream peek(Consumer action) { return new StatelessOp(this, StreamShape.REFERENCE, 0) { @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { @Override @@ -436,7 +452,7 @@ public final A[] toArray(IntFunction generator) { // super type of U an ArrayStoreException will be thrown. @SuppressWarnings("rawtypes") IntFunction rawGenerator = (IntFunction) generator; - // TODO(b/29399275): Eclipse compiler requires explicit (Node) cast below. + // Android-changed: Eclipse compiler requires explicit (Node) cast (b/29399275). return (A[]) Nodes.flatten((Node) evaluateToArrayNode(rawGenerator), rawGenerator) .asArray(rawGenerator); } @@ -539,6 +555,7 @@ public final long count() { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public static class Head extends ReferencePipeline { /** * Constructor for the source stage of a Stream. @@ -548,6 +565,7 @@ public static class Head extends ReferencePipeline { * @param sourceFlags the source flags for the stream source, described * in {@link StreamOpFlag} */ + // Android-changed: Made public for CTS tests only. public Head(Supplier> source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); @@ -560,17 +578,20 @@ public Head(Supplier> source, * @param sourceFlags the source flags for the stream source, described * in {@link StreamOpFlag} */ + // Android-changed: Made public for CTS tests only. public Head(Spliterator source, int sourceFlags, boolean parallel) { super(source, sourceFlags, parallel); } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { throw new UnsupportedOperationException(); } @Override + // Android-changed: Make public, to match the method it's overriding. public final Sink opWrapSink(int flags, Sink sink) { throw new UnsupportedOperationException(); } @@ -606,6 +627,7 @@ public void forEachOrdered(Consumer action) { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatelessOp extends ReferencePipeline { /** @@ -616,6 +638,7 @@ public abstract static class StatelessOp * @param inputShape The stream shape for the upstream pipeline stage * @param opFlags Operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatelessOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -624,6 +647,7 @@ public StatelessOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return false; } @@ -637,6 +661,7 @@ public final boolean opIsStateful() { * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public abstract static class StatefulOp extends ReferencePipeline { /** @@ -646,6 +671,7 @@ public abstract static class StatefulOp * @param inputShape The stream shape for the upstream pipeline stage * @param opFlags Operation flags for the new stage */ + // Android-changed: Made public for CTS tests only. public StatefulOp(AbstractPipeline upstream, StreamShape inputShape, int opFlags) { @@ -654,11 +680,13 @@ public StatefulOp(AbstractPipeline upstream, } @Override + // Android-changed: Make public, to match the method it's overriding. public final boolean opIsStateful() { return true; } @Override + // Android-changed: Make public, to match the method it's overriding. public abstract Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator); diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Sink.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Sink.java index 7b9a51dd13..f7f25996a7 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Sink.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Sink.java @@ -115,6 +115,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public interface Sink extends Consumer { /** * Resets the sink state to receive a fresh data set. This must be called @@ -242,7 +243,7 @@ default void accept(Double i) { * implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedReference implements Sink { + abstract static class ChainedReference implements Sink { protected final Sink downstream; public ChainedReference(Sink downstream) { @@ -274,7 +275,7 @@ public boolean cancellationRequested() { * The implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedInt implements Sink.OfInt { + abstract static class ChainedInt implements Sink.OfInt { protected final Sink downstream; public ChainedInt(Sink downstream) { @@ -306,7 +307,7 @@ public boolean cancellationRequested() { * The implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedLong implements Sink.OfLong { + abstract static class ChainedLong implements Sink.OfLong { protected final Sink downstream; public ChainedLong(Sink downstream) { @@ -338,7 +339,7 @@ public boolean cancellationRequested() { * The implementation of the {@code accept()} method must call the correct * {@code accept()} method on the downstream {@code Sink}. */ - static abstract class ChainedDouble implements Sink.OfDouble { + abstract static class ChainedDouble implements Sink.OfDouble { protected final Sink downstream; public ChainedDouble(Sink downstream) { diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SliceOps.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SliceOps.java index 3042197e39..6a6f85e58b 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SliceOps.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SliceOps.java @@ -130,6 +130,7 @@ Spliterator unorderedSkipLimitSpliterator(Spliterator s, } @Override + // Android-changed: Make public, to match the method it's overriding. public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { long size = helper.exactOutputSizeIfKnown(spliterator); if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { @@ -157,6 +158,7 @@ public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Sp } @Override + // Android-changed: Make public, to match the method it's overriding. public Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator) { @@ -186,6 +188,7 @@ public Node opEvaluateParallel(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { long n = skip; @@ -246,6 +249,7 @@ Spliterator.OfInt unorderedSkipLimitSpliterator( } @Override + // Android-changed: Make public, to match the method it's overriding. public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { long size = helper.exactOutputSizeIfKnown(spliterator); @@ -266,6 +270,7 @@ public Spliterator opEvaluateParallelLazy(PipelineHelper Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator) { @@ -295,6 +300,7 @@ public Node opEvaluateParallel(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedInt(sink) { long n = skip; @@ -355,6 +361,7 @@ Spliterator.OfLong unorderedSkipLimitSpliterator( } @Override + // Android-changed: Make public, to match the method it's overriding. public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { long size = helper.exactOutputSizeIfKnown(spliterator); @@ -375,6 +382,7 @@ public Spliterator opEvaluateParallelLazy(PipelineHelper help } @Override + // Android-changed: Make public, to match the method it's overriding. public Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator) { @@ -404,6 +412,7 @@ public Node opEvaluateParallel(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedLong(sink) { long n = skip; @@ -464,6 +473,7 @@ Spliterator.OfDouble unorderedSkipLimitSpliterator( } @Override + // Android-changed: Make public, to match the method it's overriding. public Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { long size = helper.exactOutputSizeIfKnown(spliterator); @@ -484,6 +494,7 @@ public Spliterator opEvaluateParallelLazy(PipelineHelper } @Override + // Android-changed: Make public, to match the method it's overriding. public Node opEvaluateParallel(PipelineHelper helper, Spliterator spliterator, IntFunction generator) { @@ -513,6 +524,7 @@ public Node opEvaluateParallel(PipelineHelper helper, } @Override + // Android-changed: Make public, to match the method it's overriding. public Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedDouble(sink) { long n = skip; diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SpinedBuffer.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SpinedBuffer.java index fb24ec2d7a..9b8c832bea 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SpinedBuffer.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/SpinedBuffer.java @@ -54,6 +54,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public class SpinedBuffer extends AbstractSpinedBuffer implements Consumer, Iterable { @@ -94,6 +95,7 @@ public class SpinedBuffer * is negative */ @SuppressWarnings("unchecked") + // Android-changed: Made public for CTS tests only. public SpinedBuffer(int initialCapacity) { super(initialCapacity); curChunk = (E[]) new Object[1 << initialChunkPower]; @@ -103,6 +105,7 @@ public SpinedBuffer(int initialCapacity) { * Constructs an empty list with an initial capacity of sixteen. */ @SuppressWarnings("unchecked") + // Android-changed: Made public for CTS tests only. public SpinedBuffer() { super(); curChunk = (E[]) new Object[1 << initialChunkPower]; @@ -415,9 +418,8 @@ else if (splSpineIndex == lastSpineIndex) { * @param the wrapper type for this primitive type * @param the array type for this primitive type * @param the Consumer type for this primitive type - * @hide Visible for CTS testing only (OpenJDK8 tests). */ - public abstract static class OfPrimitive + abstract static class OfPrimitive extends AbstractSpinedBuffer implements Iterable { /* @@ -723,10 +725,13 @@ else if (splSpineIndex == lastSpineIndex) { * An ordered collection of {@code int} values. * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public static class OfInt extends SpinedBuffer.OfPrimitive implements IntConsumer { + // Android-changed: Made public for CTS tests only. public OfInt() { } + // Android-changed: Made public for CTS tests only. public OfInt(int initialCapacity) { super(initialCapacity); } @@ -837,10 +842,13 @@ public String toString() { * An ordered collection of {@code long} values. * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public static class OfLong extends SpinedBuffer.OfPrimitive implements LongConsumer { + // Android-changed: Made public for CTS tests only. public OfLong() { } + // Android-changed: Made public for CTS tests only. public OfLong(int initialCapacity) { super(initialCapacity); } @@ -952,11 +960,14 @@ public String toString() { * An ordered collection of {@code double} values. * @hide Visible for CTS testing only (OpenJDK8 tests). */ + // Android-changed: Made public for CTS tests only. public static class OfDouble extends SpinedBuffer.OfPrimitive implements DoubleConsumer { + // Android-changed: Made public for CTS tests only. public OfDouble() { } + // Android-changed: Made public for CTS tests only. public OfDouble(int initialCapacity) { super(initialCapacity); } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Stream.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Stream.java index d4cb9ffc06..c35fc05682 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Stream.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/Stream.java @@ -25,6 +25,8 @@ package java.util.stream; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; @@ -126,7 +128,8 @@ * *

      Streams have a {@link #close()} method and implement {@link AutoCloseable}, * but nearly all stream instances do not actually need to be closed after use. - * Generally, only streams whose source is an IO channel will require closing. Most streams + * Generally, only streams whose source is an IO channel (such as those returned + * by {@link Files#lines(Path, Charset)}) will require closing. Most streams * are backed by collections, arrays, or generating functions, which require no * special resource management. (If a stream does require closing, it can be * declared as a resource in a {@code try}-with-resources statement.) diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamOpFlag.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamOpFlag.java index 3477a33e97..38d7db01a6 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamOpFlag.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamOpFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -41,7 +41,7 @@ * contexts: * *

      - * + *
      * * * @@ -115,7 +115,7 @@ * characteristics that stream has; when describing a stream operation, one need * describe whether the operation preserves, injects, or clears that * characteristic. Accordingly, two bits are used for each flag, so as to allow - * representing not only the presence of of a characteristic, but how an + * representing not only the presence of a characteristic, but how an * operation modifies that characteristic. There are two common forms in which * flag bits are combined into an {@code int} bit set. Stream flags * are a unioned bit set constructed by ORing the enum characteristic values of @@ -202,6 +202,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public enum StreamOpFlag { /* @@ -458,6 +459,7 @@ private StreamOpFlag(int position, MaskBuilder maskBuilder) { * * @return the bitmap for setting this characteristic */ + // Android-changed: Made public for CTS tests only. public int set() { return set; } @@ -467,6 +469,7 @@ public int set() { * * @return the bitmap for clearing this characteristic */ + // Android-changed: Made public for CTS tests only. public int clear() { return clear; } @@ -476,6 +479,7 @@ public int clear() { * * @return true if a stream-based flag, otherwise false. */ + // Android-changed: Made public for CTS tests only. public boolean isStreamFlag() { return maskTable.get(Type.STREAM) > 0; } @@ -488,6 +492,7 @@ public boolean isStreamFlag() { * operation flags * @return true if this flag is known, otherwise false. */ + // Android-changed: Made public for CTS tests only. public boolean isKnown(int flags) { return (flags & preserve) == set; } @@ -499,6 +504,7 @@ public boolean isKnown(int flags) { * @param flags the operation flags or combined stream and operations flags. * @return true if this flag is preserved, otherwise false. */ + // Android-changed: Made public for CTS tests only. public boolean isCleared(int flags) { return (flags & preserve) == clear; } @@ -509,6 +515,7 @@ public boolean isCleared(int flags) { * @param flags the combined stream and operations flags. * @return true if this flag is preserved, otherwise false. */ + // Android-changed: Made public for CTS tests only. public boolean isPreserved(int flags) { return (flags & preserve) == preserve; } @@ -519,6 +526,7 @@ public boolean isPreserved(int flags) { * @param t the flag type. * @return true if this flag can be set for the flag type, otherwise false. */ + // Android-changed: Made public for CTS tests only. public boolean canSet(Type t) { return (maskTable.get(t) & SET_BITS) > 0; } @@ -526,26 +534,31 @@ public boolean canSet(Type t) { /** * The bit mask for spliterator characteristics */ + // Android-changed: Made public for CTS tests only. public static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR); /** * The bit mask for source stream flags. */ + // Android-changed: Made public for CTS tests only. public static final int STREAM_MASK = createMask(Type.STREAM); /** * The bit mask for intermediate operation flags. */ + // Android-changed: Made public for CTS tests only. public static final int OP_MASK = createMask(Type.OP); /** * The bit mask for terminal operation flags. */ + // Android-changed: Made public for CTS tests only. public static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP); /** * The bit mask for upstream terminal operation flags. */ + // Android-changed: Made public for CTS tests only. public static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP); private static int createMask(Type t) { @@ -583,51 +596,61 @@ private static int createFlagMask() { * The initial value to be combined with the stream flags of the first * stream in the pipeline. */ + // Android-changed: Made public for CTS tests only. public static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT; /** * The bit value to set or inject {@link #DISTINCT}. */ + // Android-changed: Made public for CTS tests only. public static final int IS_DISTINCT = DISTINCT.set; /** * The bit value to clear {@link #DISTINCT}. */ + // Android-changed: Made public for CTS tests only. public static final int NOT_DISTINCT = DISTINCT.clear; /** * The bit value to set or inject {@link #SORTED}. */ + // Android-changed: Made public for CTS tests only. public static final int IS_SORTED = SORTED.set; /** * The bit value to clear {@link #SORTED}. */ + // Android-changed: Made public for CTS tests only. public static final int NOT_SORTED = SORTED.clear; /** * The bit value to set or inject {@link #ORDERED}. */ + // Android-changed: Made public for CTS tests only. public static final int IS_ORDERED = ORDERED.set; /** * The bit value to clear {@link #ORDERED}. */ + // Android-changed: Made public for CTS tests only. public static final int NOT_ORDERED = ORDERED.clear; /** * The bit value to set {@link #SIZED}. */ + // Android-changed: Made public for CTS tests only. public static final int IS_SIZED = SIZED.set; /** * The bit value to clear {@link #SIZED}. */ + // Android-changed: Made public for CTS tests only. public static final int NOT_SIZED = SIZED.clear; /** * The bit value to inject {@link #SHORT_CIRCUIT}. */ + // Android-changed: Made public for CTS tests only. public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set; private static int getMask(int flags) { @@ -684,6 +707,7 @@ private static int getMask(int flags) { * The value {#link INITIAL_OPS_VALUE} must be used as the seed value. * @return the updated combined stream and operation flags. */ + // Android-changed: Made public for CTS tests only. public static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) { // 0x01 or 0x10 nibbles are transformed to 0x11 // 0x00 nibbles remain unchanged @@ -701,6 +725,7 @@ public static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) { * @param combOpFlags the combined stream and operation flags. * @return the stream flags. */ + // Android-changed: Made public for CTS tests only. public static int toStreamFlags(int combOpFlags) { // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10 // Shift left 1 to restore set flags and mask off anything other than the set flags @@ -713,6 +738,7 @@ public static int toStreamFlags(int combOpFlags) { * @param streamFlags the stream flags. * @return the spliterator characteristic bit set. */ + // Android-changed: Made public for CTS tests only. public static int toCharacteristics(int streamFlags) { return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK; } @@ -730,6 +756,7 @@ public static int toCharacteristics(int streamFlags) { * bit set. * @return the stream flags. */ + // Android-changed: Made public for CTS tests only. public static int fromCharacteristics(Spliterator spliterator) { int characteristics = spliterator.characteristics(); if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) { @@ -748,6 +775,7 @@ public static int fromCharacteristics(Spliterator spliterator) { * @param characteristics the spliterator characteristic bit set. * @return the stream flags. */ + // Android-changed: Made public for CTS tests only. public static int fromCharacteristics(int characteristics) { return characteristics & SPLITERATOR_CHARACTERISTICS_MASK; } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamShape.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamShape.java index 2c5f83b166..5bcae4a3ea 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamShape.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/StreamShape.java @@ -47,6 +47,7 @@ * @since 1.8 * @hide Visible for CTS testing only (OpenJDK8 tests). */ +// Android-changed: Made public for CTS tests only. public enum StreamShape { /** * The shape specialization corresponding to {@code Stream} and elements diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/package-info.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/package-info.java index 17b070ab3f..016c86dd38 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/package-info.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/stream/package-info.java @@ -82,7 +82,13 @@ * {@link java.util.stream.Stream#of(Object[])}, * {@link java.util.stream.IntStream#range(int, int)} * or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)}; - * + *
    • The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};
    • + *
    • Streams of file paths can be obtained from methods in {@link java.nio.file.Files};
    • + *
    • Streams of random numbers can be obtained from {@link java.util.Random#ints()};
    • + *
    • Numerous other stream-bearing methods in the JDK, including + * {@link java.util.BitSet#stream()}, + * {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)}, + * and {@link java.util.jar.JarFile#stream()}.
    • * * *

      Additional stream sources can be provided by third-party libraries using diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/jdk/internal/util/Preconditions.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/jdk/internal/util/Preconditions.java new file mode 100644 index 0000000000..1e34adbd00 --- /dev/null +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/jdk/internal/util/Preconditions.java @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2016, 2021, 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 jdk.internal.util; + +/* J2ObjC removed +import jdk.internal.vm.annotation.IntrinsicCandidate; +*/ + +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Utility methods to check if state or arguments are correct. + * + */ +public class Preconditions { + + /** + * Maps out-of-bounds values to a runtime exception. + * + * @param checkKind the kind of bounds check, whose name may correspond + * to the name of one of the range check methods, checkIndex, + * checkFromToIndex, checkFromIndexSize + * @param args the out-of-bounds arguments that failed the range check. + * If the checkKind corresponds a the name of a range check method + * then the bounds arguments are those that can be passed in order + * to the method. + * @param oobef the exception formatter that when applied with a checkKind + * and a list out-of-bounds arguments returns a runtime exception. + * If {@code null} then, it is as if an exception formatter was + * supplied that returns {@link IndexOutOfBoundsException} for any + * given arguments. + * @return the runtime exception + */ + private static RuntimeException outOfBounds( + BiFunction, ? extends RuntimeException> oobef, + String checkKind, + Number... args) { + List largs = List.of(args); + RuntimeException e = oobef == null + ? null : oobef.apply(checkKind, largs); + return e == null + ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e; + } + + private static RuntimeException outOfBoundsCheckIndex( + BiFunction, ? extends RuntimeException> oobe, + int index, int length) { + return outOfBounds(oobe, "checkIndex", index, length); + } + + private static RuntimeException outOfBoundsCheckFromToIndex( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int toIndex, int length) { + return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length); + } + + private static RuntimeException outOfBoundsCheckFromIndexSize( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int size, int length) { + return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length); + } + + private static RuntimeException outOfBoundsCheckIndex( + BiFunction, ? extends RuntimeException> oobe, + long index, long length) { + return outOfBounds(oobe, "checkIndex", index, length); + } + + private static RuntimeException outOfBoundsCheckFromToIndex( + BiFunction, ? extends RuntimeException> oobe, + long fromIndex, long toIndex, long length) { + return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length); + } + + private static RuntimeException outOfBoundsCheckFromIndexSize( + BiFunction, ? extends RuntimeException> oobe, + long fromIndex, long size, long length) { + return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length); + } + + /** + * Returns an out-of-bounds exception formatter from an given exception + * factory. The exception formatter is a function that formats an + * out-of-bounds message from its arguments and applies that message to the + * given exception factory to produce and relay an exception. + * + *

      The exception formatter accepts two arguments: a {@code String} + * describing the out-of-bounds range check that failed, referred to as the + * check kind; and a {@code List} containing the + * out-of-bound integral values that failed the check. The list of + * out-of-bound values is not modified. + * + *

      Three check kinds are supported {@code checkIndex}, + * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding + * respectively to the specified application of an exception formatter as an + * argument to the out-of-bounds range check methods + * {@link #checkIndex(int, int, BiFunction) checkIndex}, + * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and + * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. + * Thus a supported check kind corresponds to a method name and the + * out-of-bound integral values correspond to method argument values, in + * order, preceding the exception formatter argument (similar in many + * respects to the form of arguments required for a reflective invocation of + * such a range check method). + * + *

      Formatter arguments conforming to such supported check kinds will + * produce specific exception messages describing failed out-of-bounds + * checks. Otherwise, more generic exception messages will be produced in + * any of the following cases: the check kind is supported but fewer + * or more out-of-bounds values are supplied, the check kind is not + * supported, the check kind is {@code null}, or the list of out-of-bound + * values is {@code null}. + * + * @apiNote + * This method produces an out-of-bounds exception formatter that can be + * passed as an argument to any of the supported out-of-bounds range check + * methods declared by {@code Objects}. For example, a formatter producing + * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a + * {@code static final} field as follows: + *

      {@code
      +     * static final
      +     * BiFunction, ArrayIndexOutOfBoundsException> AIOOBEF =
      +     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
      +     * }
      + * The formatter instance {@code AIOOBEF} may be passed as an argument to an + * out-of-bounds range check method, such as checking if an {@code index} + * is within the bounds of a {@code limit}: + *
      {@code
      +     * checkIndex(index, limit, AIOOBEF);
      +     * }
      + * If the bounds check fails then the range check method will throw an + * {@code ArrayIndexOutOfBoundsException} with an appropriate exception + * message that is a produced from {@code AIOOBEF} as follows: + *
      {@code
      +     * AIOOBEF.apply("checkIndex", List.of(index, limit));
      +     * }
      + * + * @param f the exception factory, that produces an exception from a message + * where the message is produced and formatted by the returned + * exception formatter. If this factory is stateless and side-effect + * free then so is the returned formatter. + * Exceptions thrown by the factory are relayed to the caller + * of the returned formatter. + * @param the type of runtime exception to be returned by the given + * exception factory and relayed by the exception formatter + * @return the out-of-bounds exception formatter + */ + public static + BiFunction, X> outOfBoundsExceptionFormatter(Function f) { + // Use anonymous class to avoid bootstrap issues if this method is + // used early in startup + return new BiFunction, X>() { + @Override + public X apply(String checkKind, List args) { + return f.apply(outOfBoundsMessage(checkKind, args)); + } + }; + } + + private static String outOfBoundsMessage(String checkKind, List args) { + if (checkKind == null && args == null) { + return String.format("Range check failed"); + } else if (checkKind == null) { + return String.format("Range check failed: %s", args); + } else if (args == null) { + return String.format("Range check failed: %s", checkKind); + } + + int argSize = 0; + switch (checkKind) { + case "checkIndex": + argSize = 2; + break; + case "checkFromToIndex": + case "checkFromIndexSize": + argSize = 3; + break; + default: + } + + // Switch to default if fewer or more arguments than required are supplied + switch ((args.size() != argSize) ? "" : checkKind) { + case "checkIndex": + return String.format("Index %s out of bounds for length %s", + args.get(0), args.get(1)); + case "checkFromToIndex": + return String.format("Range [%s, %s) out of bounds for length %s", + args.get(0), args.get(1), args.get(2)); + case "checkFromIndexSize": + return String.format("Range [%s, %The {@code index} is defined to be out of bounds if any of the + * following inequalities is true: + *
        + *
      • {@code index < 0}
      • + *
      • {@code index >= length}
      • + *
      • {@code length < 0}, which is implied from the former inequalities
      • + *
      + * + *

      If the {@code index} is out of bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkIndex}; + * and an unmodifiable list of integers whose values are, in order, the + * out-of-bounds arguments {@code index} and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out of bounds + * @param index the index + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code index} if it is within bounds of the range + * @throws X if the {@code index} is out of bounds and the exception + * formatter is non-{@code null} + * @throws IndexOutOfBoundsException if the {@code index} is out of bounds + * and the exception formatter is {@code null} + * @since 9 + * + * @implNote + * This method is made intrinsic in optimizing compilers to guide them to + * perform unsigned comparisons of the index and length when it is known the + * length is a non-negative value (such as that of an array length or from + * the upper bound of a loop) + */ + /* J2ObjC removed + @IntrinsicCandidate + */ + public static + int checkIndex(int index, int length, + BiFunction, X> oobef) { + if (index < 0 || index >= length) + throw outOfBoundsCheckIndex(oobef, index, length); + return index; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} + * (inclusive) to {@code length} (exclusive). + * + *

      The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

        + *
      • {@code fromIndex < 0}
      • + *
      • {@code fromIndex > toIndex}
      • + *
      • {@code toIndex > length}
      • + *
      • {@code length < 0}, which is implied from the former inequalities
      • + *
      + * + *

      If the sub-range is out of bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromToIndex}; + * and an unmodifiable list of integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out of bounds + * @param fromIndex the lower-bound (inclusive) of the sub-range + * @param toIndex the upper-bound (exclusive) of the sub-range + * @param length the upper-bound (exclusive) the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out of bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out of bounds and + * the exception factory function is {@code null} + * @since 9 + */ + public static + int checkFromToIndex(int fromIndex, int toIndex, int length, + BiFunction, X> oobef) { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) + throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); + return fromIndex; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code fromIndex + size} (exclusive) is within the bounds of range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

      The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

        + *
      • {@code fromIndex < 0}
      • + *
      • {@code size < 0}
      • + *
      • {@code fromIndex + size > length}, taking into account integer overflow
      • + *
      • {@code length < 0}, which is implied from the former inequalities
      • + *
      + * + *

      If the sub-range is out of bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromIndexSize}; + * and an unmodifiable list of integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code size}, and + * {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out of bounds + * @param fromIndex the lower-bound (inclusive) of the sub-interval + * @param size the size of the sub-range + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out of bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out of bounds and + * the exception factory function is {@code null} + * @since 9 + */ + public static + int checkFromIndexSize(int fromIndex, int size, int length, + BiFunction, X> oobef) { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); + return fromIndex; + } + + /** + * Checks if the {@code index} is within the bounds of the range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

      The {@code index} is defined to be out of bounds if any of the + * following inequalities is true: + *

        + *
      • {@code index < 0}
      • + *
      • {@code index >= length}
      • + *
      • {@code length < 0}, which is implied from the former inequalities
      • + *
      + * + *

      If the {@code index} is out of bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkIndex}; + * and an unmodifiable list of longs whose values are, in order, the + * out-of-bounds arguments {@code index} and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out of bounds + * @param index the index + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code index} if it is within bounds of the range + * @throws X if the {@code index} is out of bounds and the exception + * formatter is non-{@code null} + * @throws IndexOutOfBoundsException if the {@code index} is out of bounds + * and the exception formatter is {@code null} + * @since 16 + * + * @implNote + * This method is made intrinsic in optimizing compilers to guide them to + * perform unsigned comparisons of the index and length when it is known the + * length is a non-negative value (such as that of an array length or from + * the upper bound of a loop) + */ + // Android-removed: @IntrinsicCandidate is not present in Android. + //@IntrinsicCandidate + public static + long checkIndex(long index, long length, + BiFunction, X> oobef) { + if (index < 0 || index >= length) + throw outOfBoundsCheckIndex(oobef, index, length); + return index; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} + * (inclusive) to {@code length} (exclusive). + * + *

      The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

        + *
      • {@code fromIndex < 0}
      • + *
      • {@code fromIndex > toIndex}
      • + *
      • {@code toIndex > length}
      • + *
      • {@code length < 0}, which is implied from the former inequalities
      • + *
      + * + *

      If the sub-range is out of bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromToIndex}; + * and an unmodifiable list of longs whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out of bounds + * @param fromIndex the lower-bound (inclusive) of the sub-range + * @param toIndex the upper-bound (exclusive) of the sub-range + * @param length the upper-bound (exclusive) the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out of bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out of bounds and + * the exception factory function is {@code null} + * @since 16 + */ + public static + long checkFromToIndex(long fromIndex, long toIndex, long length, + BiFunction, X> oobef) { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) + throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); + return fromIndex; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code fromIndex + size} (exclusive) is within the bounds of range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

      The sub-range is defined to be out of bounds if any of the following + * inequalities is true: + *

        + *
      • {@code fromIndex < 0}
      • + *
      • {@code size < 0}
      • + *
      • {@code fromIndex + size > length}, taking into account integer overflow
      • + *
      • {@code length < 0}, which is implied from the former inequalities
      • + *
      + * + *

      If the sub-range is out of bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromIndexSize}; + * and an unmodifiable list of longs whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code size}, and + * {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out of bounds + * @param fromIndex the lower-bound (inclusive) of the sub-interval + * @param size the size of the sub-range + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out of bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out of bounds and + * the exception factory function is {@code null} + * @since 16 + */ + public static + long checkFromIndexSize(long fromIndex, long size, long length, + BiFunction, X> oobef) { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); + return fromIndex; + } +} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/JavaObjectInputStreamAccess.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/JavaObjectInputStreamAccess.java new file mode 100644 index 0000000000..09a928a3ab --- /dev/null +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/JavaObjectInputStreamAccess.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, 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 sun.misc; + +import java.io.InvalidClassException; +import java.io.ObjectInputStream; + +/** + * Interface to specify methods for accessing {@code ObjectInputStream}. + */ +@FunctionalInterface +public interface JavaObjectInputStreamAccess { + void checkArray(ObjectInputStream ois, Class arrayType, int arrayLength) + throws InvalidClassException; +} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/SharedSecrets.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/SharedSecrets.java index 226dbf7392..b65382c0dc 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/SharedSecrets.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/SharedSecrets.java @@ -25,6 +25,8 @@ package sun.misc; +import java.io.ObjectInputStream; + /** A repository of "shared secrets", which are a mechanism for calling implementation-private methods in another package without using reflection. A package-private class implements a public @@ -35,9 +37,9 @@ interface and provides the ability to call package-private methods for this purpose, namely the loss of compile-time checking. */ public class SharedSecrets { + private static final Unsafe unsafe = Unsafe.getUnsafe(); // BEGIN Android-removed: Pruned unused access interfaces. /* - private static final Unsafe unsafe = Unsafe.getUnsafe(); private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; private static JavaLangRefAccess javaLangRefAccess; @@ -55,7 +57,11 @@ public class SharedSecrets { private static JavaUtilZipFileAccess javaUtilZipFileAccess; private static JavaAWTAccess javaAWTAccess; private static JavaOISAccess javaOISAccess; + */ + // END Android-removed: Pruned unused access interfaces. private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; + // BEGIN Android-removed: Pruned unused access interfaces. + /* public static JavaUtilJarAccess javaUtilJarAccess() { if (javaUtilJarAccess == null) { @@ -209,6 +215,8 @@ public static JavaAWTAccess getJavaAWTAccess() { } return javaAWTAccess; } + */ + // END Android-removed: Pruned unused access interfaces. public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { if (javaObjectInputStreamAccess == null) { @@ -216,7 +224,9 @@ public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { } return javaObjectInputStreamAccess; } - + + // BEGIN Android-removed: Pruned unused access interfaces. + /* public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) { javaObjectInputStreamAccess = access; } diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/Unsafe.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/Unsafe.java index 50a51283a3..f713252ac5 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/Unsafe.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/sun/misc/Unsafe.java @@ -676,4 +676,26 @@ public final Object getAndSetObject(Object o, long offset, Object newValue) { */ // @HotSpotIntrinsicCandidate public native void fullFence(); + + /** + * Ensures the given class has been initialized. This is often + * needed in conjunction with obtaining the static field base of a + * class. + */ + public void ensureClassInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + // Android-changed: Implementation not yet available natively (b/202380950) + // ensureClassIni9tialized0(c); + try { + Class.forName(c.getName(), true, c.getClassLoader()); + } catch (ClassNotFoundException e) { + // The function doesn't specify that it's throwing ClassNotFoundException, so it needs + // to be caught here. We could rethrow as NoClassDefFoundError, however that is not + // documented for this function and the upstream implementation does not throw an + // exception. + } + } } diff --git a/jre_emul/jre_sources.mk b/jre_emul/jre_sources.mk index ecd402001d..53d980e449 100644 --- a/jre_emul/jre_sources.mk +++ b/jre_emul/jre_sources.mk @@ -631,6 +631,8 @@ JAVA_PRIVATE_SOURCES_CORE = \ java/util/DualPivotQuicksort.java \ java/util/Grego.java \ java/util/JumboEnumSet.java \ + java/util/KeyValueHolder.java \ + java/util/ImmutableCollections.java \ java/util/RegularEnumSet.java \ java/util/logging/Logging.java \ java/util/logging/LoggingProxyImpl.java \ @@ -659,6 +661,7 @@ JAVA_PRIVATE_SOURCES_CORE = \ java/util/stream/StreamSpliterators.java \ java/util/stream/TerminalOp.java \ jdk/internal/module/SystemModulesMap.java \ + jdk/internal/util/Preconditions.java \ libcore/api/CorePlatformApi.java \ libcore/api/Hide.java \ libcore/api/IntraCoreApi.java \ @@ -1183,6 +1186,7 @@ JAVA_PRIVATE_SOURCES_FILE = \ java/nio/file/FileTreeIterator.java \ java/nio/file/FileTreeWalker.java \ sun/misc/JavaIOFileDescriptorAccess.java \ + sun/misc/JavaObjectInputStreamAccess.java \ sun/misc/SharedSecrets.java \ sun/nio/fs/AbstractBasicFileAttributeView.java \ sun/nio/fs/AbstractFileSystemProvider.java \

      Type Characteristics