Merge "OpenJDK 11: Merging in java.nio.channels.Selector and SelectionKey."
diff --git a/api/current.txt b/api/current.txt
index 52291e7..28bd836 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -1577,6 +1577,8 @@
ctor public FileReader(String) throws java.io.FileNotFoundException;
ctor public FileReader(java.io.File) throws java.io.FileNotFoundException;
ctor public FileReader(java.io.FileDescriptor);
+ ctor public FileReader(String, java.nio.charset.Charset) throws java.io.IOException;
+ ctor public FileReader(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
}
public class FileWriter extends java.io.OutputStreamWriter {
@@ -1585,6 +1587,10 @@
ctor public FileWriter(java.io.File) throws java.io.IOException;
ctor public FileWriter(java.io.File, boolean) throws java.io.IOException;
ctor public FileWriter(java.io.FileDescriptor);
+ ctor public FileWriter(String, java.nio.charset.Charset) throws java.io.IOException;
+ ctor public FileWriter(String, java.nio.charset.Charset, boolean) throws java.io.IOException;
+ ctor public FileWriter(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
+ ctor public FileWriter(java.io.File, java.nio.charset.Charset, boolean) throws java.io.IOException;
}
@java.lang.FunctionalInterface public interface FilenameFilter {
@@ -1946,10 +1952,13 @@
ctor public PrintStream(java.io.OutputStream);
ctor public PrintStream(java.io.OutputStream, boolean);
ctor public PrintStream(java.io.OutputStream, boolean, String) throws java.io.UnsupportedEncodingException;
+ ctor public PrintStream(java.io.OutputStream, boolean, java.nio.charset.Charset);
ctor public PrintStream(String) throws java.io.FileNotFoundException;
ctor public PrintStream(String, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+ ctor public PrintStream(String, java.nio.charset.Charset) throws java.io.IOException;
ctor public PrintStream(java.io.File) throws java.io.FileNotFoundException;
ctor public PrintStream(java.io.File, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+ ctor public PrintStream(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
method public java.io.PrintStream append(CharSequence);
method public java.io.PrintStream append(CharSequence, int, int);
method public java.io.PrintStream append(char);
@@ -1990,10 +1999,13 @@
ctor public PrintWriter(@NonNull java.io.Writer, boolean);
ctor public PrintWriter(@NonNull java.io.OutputStream);
ctor public PrintWriter(@NonNull java.io.OutputStream, boolean);
+ ctor public PrintWriter(@NonNull java.io.OutputStream, boolean, @NonNull java.nio.charset.Charset);
ctor public PrintWriter(@NonNull String) throws java.io.FileNotFoundException;
ctor public PrintWriter(@NonNull String, @NonNull String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+ ctor public PrintWriter(@NonNull String, @NonNull java.nio.charset.Charset) throws java.io.IOException;
ctor public PrintWriter(@NonNull java.io.File) throws java.io.FileNotFoundException;
ctor public PrintWriter(@NonNull java.io.File, @NonNull String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+ ctor public PrintWriter(@NonNull java.io.File, @NonNull java.nio.charset.Charset) throws java.io.IOException;
method @NonNull public java.io.PrintWriter append(@Nullable CharSequence);
method @NonNull public java.io.PrintWriter append(@Nullable CharSequence, int, int);
method @NonNull public java.io.PrintWriter append(char);
@@ -2100,6 +2112,7 @@
ctor protected Reader(Object);
method public void mark(int) throws java.io.IOException;
method public boolean markSupported();
+ method public static java.io.Reader nullReader();
method public int read(java.nio.CharBuffer) throws java.io.IOException;
method public int read() throws java.io.IOException;
method public int read(char[]) throws java.io.IOException;
@@ -2107,6 +2120,7 @@
method public boolean ready() throws java.io.IOException;
method public void reset() throws java.io.IOException;
method public long skip(long) throws java.io.IOException;
+ method public long transferTo(java.io.Writer) throws java.io.IOException;
field protected Object lock;
}
@@ -2220,6 +2234,7 @@
method public java.io.Writer append(CharSequence) throws java.io.IOException;
method public java.io.Writer append(CharSequence, int, int) throws java.io.IOException;
method public java.io.Writer append(char) throws java.io.IOException;
+ method public static java.io.Writer nullWriter();
method public void write(int) throws java.io.IOException;
method public void write(char[]) throws java.io.IOException;
method public abstract void write(char[], int, int) throws java.io.IOException;
@@ -4806,9 +4821,9 @@
method public java.math.BigDecimal add(java.math.BigDecimal, java.math.MathContext);
method public byte byteValueExact();
method public int compareTo(java.math.BigDecimal);
- method public java.math.BigDecimal divide(java.math.BigDecimal, int, int);
+ method @Deprecated public java.math.BigDecimal divide(java.math.BigDecimal, int, int);
method public java.math.BigDecimal divide(java.math.BigDecimal, int, java.math.RoundingMode);
- method public java.math.BigDecimal divide(java.math.BigDecimal, int);
+ method @Deprecated public java.math.BigDecimal divide(java.math.BigDecimal, int);
method public java.math.BigDecimal divide(java.math.BigDecimal, java.math.RoundingMode);
method public java.math.BigDecimal divide(java.math.BigDecimal);
method public java.math.BigDecimal divide(java.math.BigDecimal, java.math.MathContext);
@@ -4841,10 +4856,11 @@
method public int scale();
method public java.math.BigDecimal scaleByPowerOfTen(int);
method public java.math.BigDecimal setScale(int, java.math.RoundingMode);
- method public java.math.BigDecimal setScale(int, int);
+ method @Deprecated public java.math.BigDecimal setScale(int, int);
method public java.math.BigDecimal setScale(int);
method public short shortValueExact();
method public int signum();
+ method public java.math.BigDecimal sqrt(java.math.MathContext);
method public java.math.BigDecimal stripTrailingZeros();
method public java.math.BigDecimal subtract(java.math.BigDecimal);
method public java.math.BigDecimal subtract(java.math.BigDecimal, java.math.MathContext);
@@ -4858,20 +4874,22 @@
method public static java.math.BigDecimal valueOf(long);
method public static java.math.BigDecimal valueOf(double);
field public static final java.math.BigDecimal ONE;
- field public static final int ROUND_CEILING = 2; // 0x2
- field public static final int ROUND_DOWN = 1; // 0x1
- field public static final int ROUND_FLOOR = 3; // 0x3
- field public static final int ROUND_HALF_DOWN = 5; // 0x5
- field public static final int ROUND_HALF_EVEN = 6; // 0x6
- field public static final int ROUND_HALF_UP = 4; // 0x4
- field public static final int ROUND_UNNECESSARY = 7; // 0x7
- field public static final int ROUND_UP = 0; // 0x0
+ field @Deprecated public static final int ROUND_CEILING = 2; // 0x2
+ field @Deprecated public static final int ROUND_DOWN = 1; // 0x1
+ field @Deprecated public static final int ROUND_FLOOR = 3; // 0x3
+ field @Deprecated public static final int ROUND_HALF_DOWN = 5; // 0x5
+ field @Deprecated public static final int ROUND_HALF_EVEN = 6; // 0x6
+ field @Deprecated public static final int ROUND_HALF_UP = 4; // 0x4
+ field @Deprecated public static final int ROUND_UNNECESSARY = 7; // 0x7
+ field @Deprecated public static final int ROUND_UP = 0; // 0x0
field public static final java.math.BigDecimal TEN;
field public static final java.math.BigDecimal ZERO;
}
public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> {
+ ctor public BigInteger(byte[], int, int);
ctor public BigInteger(byte[]);
+ ctor public BigInteger(int, byte[], int, int);
ctor public BigInteger(int, byte[]);
ctor public BigInteger(@NonNull String, int);
ctor public BigInteger(@NonNull String);
@@ -4916,6 +4934,8 @@
method @NonNull public java.math.BigInteger shiftRight(int);
method public short shortValueExact();
method public int signum();
+ method @NonNull public java.math.BigInteger sqrt();
+ method @NonNull public java.math.BigInteger[] sqrtAndRemainder();
method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger);
method public boolean testBit(int);
method public byte[] toByteArray();
@@ -4924,6 +4944,7 @@
method @NonNull public java.math.BigInteger xor(@NonNull java.math.BigInteger);
field @NonNull public static final java.math.BigInteger ONE;
field @NonNull public static final java.math.BigInteger TEN;
+ field @NonNull public static final java.math.BigInteger TWO;
field @NonNull public static final java.math.BigInteger ZERO;
}
@@ -6739,6 +6760,7 @@
public abstract class FileStore {
ctor protected FileStore();
method public abstract Object getAttribute(String) throws java.io.IOException;
+ method public long getBlockSize() throws java.io.IOException;
method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(Class<V>);
method public abstract long getTotalSpace() throws java.io.IOException;
method public abstract long getUnallocatedSpace() throws java.io.IOException;
@@ -8510,6 +8532,12 @@
method public final java.security.cert.X509Certificate getTrustedCert();
}
+ public final class URICertStoreParameters implements java.security.cert.CertStoreParameters {
+ ctor public URICertStoreParameters(java.net.URI);
+ method public java.security.cert.URICertStoreParameters clone();
+ method public java.net.URI getURI();
+ }
+
public abstract class X509CRL extends java.security.cert.CRL implements java.security.cert.X509Extension {
ctor protected X509CRL();
method public abstract byte[] getEncoded() throws java.security.cert.CRLException;
@@ -12367,6 +12395,34 @@
method public static int binarySearch(@NonNull Object[], int, int, @NonNull Object);
method public static <T> int binarySearch(@NonNull T[], T, @Nullable java.util.Comparator<? super T>);
method public static <T> int binarySearch(@NonNull T[], int, int, T, @Nullable java.util.Comparator<? super T>);
+ method public static int compare(@Nullable boolean[], @Nullable boolean[]);
+ method public static int compare(@NonNull boolean[], int, int, @NonNull boolean[], int, int);
+ method public static int compare(@Nullable byte[], @Nullable byte[]);
+ method public static int compare(@NonNull byte[], int, int, @NonNull byte[], int, int);
+ method public static int compare(@Nullable short[], @Nullable short[]);
+ method public static int compare(@NonNull short[], int, int, @NonNull short[], int, int);
+ method public static int compare(@Nullable char[], @Nullable char[]);
+ method public static int compare(@NonNull char[], int, int, @NonNull char[], int, int);
+ method public static int compare(@Nullable int[], @Nullable int[]);
+ method public static int compare(@NonNull int[], int, int, @NonNull int[], int, int);
+ method public static int compare(@Nullable long[], @Nullable long[]);
+ method public static int compare(@NonNull long[], int, int, @NonNull long[], int, int);
+ method public static int compare(@Nullable float[], @Nullable float[]);
+ method public static int compare(@NonNull float[], int, int, @NonNull float[], int, int);
+ method public static int compare(@Nullable double[], @Nullable double[]);
+ method public static int compare(@NonNull double[], int, int, @NonNull double[], int, int);
+ method public static <T extends java.lang.Comparable<? super T>> int compare(@Nullable T[], @Nullable T[]);
+ method public static <T extends java.lang.Comparable<? super T>> int compare(@NonNull T[], int, int, @NonNull T[], int, int);
+ method public static <T> int compare(@Nullable T[], @Nullable T[], @NonNull java.util.Comparator<? super T>);
+ method public static <T> int compare(@NonNull T[], int, int, @NonNull T[], int, int, @NonNull java.util.Comparator<? super T>);
+ method public static int compareUnsigned(@Nullable byte[], @Nullable byte[]);
+ method public static int compareUnsigned(@NonNull byte[], int, int, @NonNull byte[], int, int);
+ method public static int compareUnsigned(@Nullable short[], @Nullable short[]);
+ method public static int compareUnsigned(@NonNull short[], int, int, @NonNull short[], int, int);
+ method public static int compareUnsigned(@Nullable int[], @Nullable int[]);
+ method public static int compareUnsigned(@NonNull int[], int, int, @NonNull int[], int, int);
+ method public static int compareUnsigned(@Nullable long[], @Nullable long[]);
+ method public static int compareUnsigned(@NonNull long[], int, int, @NonNull long[], int, int);
method @NonNull public static <T> T[] copyOf(@NonNull T[], int);
method @NonNull public static <T, U> T[] copyOf(@NonNull U[], int, @NonNull Class<? extends T[]>);
method @NonNull public static byte[] copyOf(@NonNull byte[], int);
@@ -12391,14 +12447,25 @@
method public static int deepHashCode(@Nullable Object[]);
method @NonNull public static String deepToString(@Nullable Object[]);
method public static boolean equals(@Nullable long[], @Nullable long[]);
+ method public static boolean equals(@NonNull long[], int, int, @NonNull long[], int, int);
method public static boolean equals(@Nullable int[], @Nullable int[]);
+ method public static boolean equals(@NonNull int[], int, int, @NonNull int[], int, int);
method public static boolean equals(@Nullable short[], @Nullable short[]);
+ method public static boolean equals(@NonNull short[], int, int, @NonNull short[], int, int);
method public static boolean equals(@Nullable char[], @Nullable char[]);
+ method public static boolean equals(@NonNull char[], int, int, @NonNull char[], int, int);
method public static boolean equals(@Nullable byte[], @Nullable byte[]);
+ method public static boolean equals(@NonNull byte[], int, int, @NonNull byte[], int, int);
method public static boolean equals(@Nullable boolean[], @Nullable boolean[]);
+ method public static boolean equals(@NonNull boolean[], int, int, @NonNull boolean[], int, int);
method public static boolean equals(@Nullable double[], @Nullable double[]);
+ method public static boolean equals(@NonNull double[], int, int, @NonNull double[], int, int);
method public static boolean equals(@Nullable float[], @Nullable float[]);
+ method public static boolean equals(@NonNull float[], int, int, @NonNull float[], int, int);
method public static boolean equals(@Nullable Object[], @Nullable Object[]);
+ method public static boolean equals(@NonNull Object[], int, int, @NonNull Object[], int, int);
+ method public static <T> boolean equals(@Nullable T[], @Nullable T[], @NonNull java.util.Comparator<? super T>);
+ method public static <T> boolean equals(@NonNull T[], int, int, @NonNull T[], int, int, @NonNull java.util.Comparator<? super T>);
method public static void fill(@NonNull long[], long);
method public static void fill(@NonNull long[], int, int, long);
method public static void fill(@NonNull int[], int);
@@ -12426,6 +12493,26 @@
method public static int hashCode(@Nullable float[]);
method public static int hashCode(@Nullable double[]);
method public static int hashCode(@Nullable Object[]);
+ method public static int mismatch(@NonNull boolean[], @NonNull boolean[]);
+ method public static int mismatch(@NonNull boolean[], int, int, @NonNull boolean[], int, int);
+ method public static int mismatch(@NonNull byte[], @NonNull byte[]);
+ method public static int mismatch(byte[], int, int, byte[], int, int);
+ method public static int mismatch(@NonNull char[], @NonNull char[]);
+ method public static int mismatch(@NonNull char[], int, int, @NonNull char[], int, int);
+ method public static int mismatch(@NonNull short[], @NonNull short[]);
+ method public static int mismatch(@NonNull short[], int, int, @NonNull short[], int, int);
+ method public static int mismatch(@NonNull int[], @NonNull int[]);
+ method public static int mismatch(@NonNull int[], int, int, @NonNull int[], int, int);
+ method public static int mismatch(@NonNull long[], @NonNull long[]);
+ method public static int mismatch(@NonNull long[], int, int, @NonNull long[], int, int);
+ method public static int mismatch(@NonNull float[], @NonNull float[]);
+ method public static int mismatch(@NonNull float[], int, int, @NonNull float[], int, int);
+ method public static int mismatch(@NonNull double[], @NonNull double[]);
+ method public static int mismatch(@NonNull double[], int, int, @NonNull double[], int, int);
+ method public static int mismatch(@NonNull Object[], @NonNull Object[]);
+ method public static int mismatch(@NonNull Object[], int, int, @NonNull Object[], int, int);
+ method public static <T> int mismatch(@NonNull T[], @NonNull T[], @NonNull java.util.Comparator<? super T>);
+ method public static <T> int mismatch(@NonNull T[], int, int, @NonNull T[], int, int, @NonNull java.util.Comparator<? super T>);
method public static <T> void parallelPrefix(@NonNull T[], @NonNull java.util.function.BinaryOperator<T>);
method public static <T> void parallelPrefix(@NonNull T[], int, int, @NonNull java.util.function.BinaryOperator<T>);
method public static void parallelPrefix(@NonNull long[], @NonNull java.util.function.LongBinaryOperator);
@@ -14238,6 +14325,7 @@
ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
method public int drainTo(java.util.Collection<? super E>);
method public int drainTo(java.util.Collection<? super E>, int);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public java.util.Iterator<E> iterator();
method public boolean offer(E);
method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
@@ -14478,7 +14566,7 @@
method public final boolean isEmpty();
method @NonNull public java.util.Iterator<K> iterator();
method public boolean remove(@NonNull Object);
- method public final boolean removeAll(@NonNull java.util.Collection<?>);
+ method public boolean removeAll(@NonNull java.util.Collection<?>);
method public final boolean retainAll(@NonNull java.util.Collection<?>);
method public final int size();
method @NonNull public java.util.Spliterator<K> spliterator();
@@ -14494,6 +14582,7 @@
method public void addLast(E);
method public java.util.Iterator<E> descendingIterator();
method public E element();
+ method public void forEach(java.util.function.Consumer<? super E>);
method public E getFirst();
method public E getLast();
method public java.util.Iterator<E> iterator();
@@ -14519,6 +14608,7 @@
public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue<E> implements java.util.Queue<E> java.io.Serializable {
ctor public ConcurrentLinkedQueue();
ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public java.util.Iterator<E> iterator();
method public boolean offer(E);
method public E peek();
@@ -14808,6 +14898,7 @@
ctor public ForkJoinPool();
ctor public ForkJoinPool(int);
ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
+ ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean, int, int, int, java.util.function.Predicate<? super java.util.concurrent.ForkJoinPool>, long, java.util.concurrent.TimeUnit);
method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
method public static java.util.concurrent.ForkJoinPool commonPool();
@@ -14934,6 +15025,7 @@
method public java.util.Iterator<E> descendingIterator();
method public int drainTo(java.util.Collection<? super E>);
method public int drainTo(java.util.Collection<? super E>, int);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public E getFirst();
method public E getLast();
method public java.util.Iterator<E> iterator();
@@ -14974,6 +15066,7 @@
ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
method public int drainTo(java.util.Collection<? super E>);
method public int drainTo(java.util.Collection<? super E>, int);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public java.util.Iterator<E> iterator();
method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
method public boolean offer(E);
@@ -14991,6 +15084,7 @@
ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
method public int drainTo(java.util.Collection<? super E>);
method public int drainTo(java.util.Collection<? super E>, int);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public int getWaitingConsumerCount();
method public boolean hasWaitingConsumer();
method public java.util.Iterator<E> iterator();
@@ -15040,6 +15134,7 @@
method public java.util.Comparator<? super E> comparator();
method public int drainTo(java.util.Collection<? super E>);
method public int drainTo(java.util.Collection<? super E>, int);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public java.util.Iterator<E> iterator();
method public boolean offer(E);
method public boolean offer(E, long, java.util.concurrent.TimeUnit);
@@ -15137,6 +15232,29 @@
method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
}
+ public class SubmissionPublisher<T> implements java.lang.AutoCloseable java.util.concurrent.Flow.Publisher<T> {
+ ctor public SubmissionPublisher(java.util.concurrent.Executor, int, java.util.function.BiConsumer<? super java.util.concurrent.Flow.Subscriber<? super T>,? super java.lang.Throwable>);
+ ctor public SubmissionPublisher(java.util.concurrent.Executor, int);
+ ctor public SubmissionPublisher();
+ method public void close();
+ method public void closeExceptionally(Throwable);
+ method public java.util.concurrent.CompletableFuture<java.lang.Void> consume(java.util.function.Consumer<? super T>);
+ method public int estimateMaximumLag();
+ method public long estimateMinimumDemand();
+ method public Throwable getClosedException();
+ method public java.util.concurrent.Executor getExecutor();
+ method public int getMaxBufferCapacity();
+ method public int getNumberOfSubscribers();
+ method public java.util.List<java.util.concurrent.Flow.Subscriber<? super T>> getSubscribers();
+ method public boolean hasSubscribers();
+ method public boolean isClosed();
+ method public boolean isSubscribed(java.util.concurrent.Flow.Subscriber<? super T>);
+ method public int offer(T, java.util.function.BiPredicate<java.util.concurrent.Flow.Subscriber<? super T>,? super T>);
+ method public int offer(T, long, java.util.concurrent.TimeUnit, java.util.function.BiPredicate<java.util.concurrent.Flow.Subscriber<? super T>,? super T>);
+ method public int submit(T);
+ method public void subscribe(java.util.concurrent.Flow.Subscriber<? super T>);
+ }
+
public class SynchronousQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
ctor public SynchronousQueue();
ctor public SynchronousQueue(boolean);
@@ -15178,7 +15296,7 @@
method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
method protected void beforeExecute(Thread, Runnable);
method public void execute(Runnable);
- method protected void finalize();
+ method @Deprecated protected void finalize();
method public int getActiveCount();
method public long getCompletedTaskCount();
method public int getCorePoolSize();
@@ -15229,9 +15347,12 @@
public enum TimeUnit {
method public long convert(long, java.util.concurrent.TimeUnit);
+ method public long convert(java.time.Duration);
+ method public static java.util.concurrent.TimeUnit of(java.time.temporal.ChronoUnit);
method public void sleep(long) throws java.lang.InterruptedException;
method public void timedJoin(Thread, long) throws java.lang.InterruptedException;
method public void timedWait(Object, long) throws java.lang.InterruptedException;
+ method public java.time.temporal.ChronoUnit toChronoUnit();
method public long toDays(long);
method public long toHours(long);
method public long toMicros(long);
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 15741a7..ce54d56 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -226,6 +226,7 @@
public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {
ctor public DelegateLastClassLoader(String, String, ClassLoader, ClassLoader[]);
+ ctor public DelegateLastClassLoader(String, String, ClassLoader, ClassLoader[], ClassLoader[]);
}
@Deprecated public final class DexFile {
@@ -246,6 +247,7 @@
public class PathClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public PathClassLoader(@NonNull String, @Nullable String, @Nullable ClassLoader, @Nullable ClassLoader[]);
+ ctor public PathClassLoader(@NonNull String, @Nullable String, @Nullable ClassLoader, @Nullable ClassLoader[], @Nullable ClassLoader[]);
}
public final class RuntimeHooks {
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index ee9c057..5fbf585 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -73,6 +73,19 @@
protected final ClassLoader[] sharedLibraryLoaders;
/**
+ * Array of ClassLoaders identical to {@code sharedLibraryLoaders} except that these library
+ * loaders are always checked after the {@code pathList} when looking up classes and resources.
+ *
+ * The placement of a library into this group is done by the OEM and cannot be configured by
+ * an App.
+ *
+ * <p>{@code null} if the class loader has no shared library.
+ *
+ * @hide
+ */
+ protected final ClassLoader[] sharedLibraryLoadersAfter;
+
+ /**
* Constructs an instance.
* Note that all the *.jar and *.apk files from {@code dexPath} might be
* first extracted in-memory before the code is loaded. This can be avoided
@@ -89,7 +102,7 @@
*/
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
- this(dexPath, librarySearchPath, parent, null, false);
+ this(dexPath, librarySearchPath, parent, null, null, false);
}
/**
@@ -98,7 +111,7 @@
@UnsupportedAppUsage
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent, boolean isTrusted) {
- this(dexPath, librarySearchPath, parent, null, isTrusted);
+ this(dexPath, librarySearchPath, parent, null, null, isTrusted);
}
/**
@@ -106,10 +119,19 @@
*/
public BaseDexClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, ClassLoader[] libraries) {
- this(dexPath, librarySearchPath, parent, libraries, false);
+ this(dexPath, librarySearchPath, parent, libraries, null, false);
}
/**
+ * @hide
+ */
+ public BaseDexClassLoader(String dexPath, String librarySearchPath,
+ ClassLoader parent, ClassLoader[] libraries, ClassLoader[] librariesAfter) {
+ this(dexPath, librarySearchPath, parent, libraries, librariesAfter, false);
+ }
+
+
+ /**
* BaseDexClassLoader implements the Android
* <a href=https://developer.android.com/guide/topics/manifest/uses-library-element>
* shared libraries</a> feature by changing the typical parent delegation mechanism
@@ -119,11 +141,15 @@
* after the parent.
* The shared library loaders are always checked before the {@code pathList} when looking
* up classes and resources.
+ * <p>
+ * The shared library loaders defined in sharedLibraryLoadersAfter are always checked
+ * <b>after</b> the {@code pathList}
*
* @hide
*/
public BaseDexClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders,
+ ClassLoader[] sharedLibraryLoadersAfter,
boolean isTrusted) {
super(parent);
// Setup shared libraries before creating the path list. ART relies on the class loader
@@ -133,6 +159,9 @@
: Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
+ this.sharedLibraryLoadersAfter = sharedLibraryLoadersAfter == null
+ ? null
+ : Arrays.copyOf(sharedLibraryLoadersAfter, sharedLibraryLoadersAfter.length);
// Run background verification after having set 'pathList'.
this.pathList.maybeRunBackgroundVerification(this);
@@ -192,6 +221,7 @@
public BaseDexClassLoader(ByteBuffer[] dexFiles, String librarySearchPath, ClassLoader parent) {
super(parent);
this.sharedLibraryLoaders = null;
+ this.sharedLibraryLoadersAfter = null;
this.pathList = new DexPathList(this, librarySearchPath);
this.pathList.initByteBufferDexPath(dexFiles);
// Run background verification after having set 'pathList'.
@@ -213,6 +243,18 @@
// this classloader operates on.
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
+ if (c != null) {
+ return c;
+ }
+ // Now, check whether the class is present in the "after" shared libraries.
+ if (sharedLibraryLoadersAfter != null) {
+ for (ClassLoader loader : sharedLibraryLoadersAfter) {
+ try {
+ return loader.loadClass(name);
+ } catch (ClassNotFoundException ignored) {
+ }
+ }
+ }
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException(
"Didn't find class \"" + name + "\" on path: " + pathList);
@@ -268,28 +310,59 @@
}
}
}
- return pathList.findResource(name);
+ URL url = pathList.findResource(name);
+ if (url != null) {
+ return url;
+ }
+ if (sharedLibraryLoadersAfter != null) {
+ for (ClassLoader loader : sharedLibraryLoadersAfter) {
+ URL url2 = loader.getResource(name);
+ if (url2 != null) {
+ return url2;
+ }
+ }
+ }
+ return null;
}
@Override
protected Enumeration<URL> findResources(String name) {
Enumeration<URL> myResources = pathList.findResources(name);
- if (sharedLibraryLoaders == null) {
+ if (sharedLibraryLoaders == null && sharedLibraryLoadersAfter == null) {
return myResources;
}
+ int sharedLibraryLoadersCount =
+ (sharedLibraryLoaders != null) ? sharedLibraryLoaders.length : 0;
+ int sharedLibraryLoadersAfterCount =
+ (sharedLibraryLoadersAfter != null) ? sharedLibraryLoadersAfter.length : 0;
+
Enumeration<URL>[] tmp =
- (Enumeration<URL>[]) new Enumeration<?>[sharedLibraryLoaders.length + 1];
+ (Enumeration<URL>[]) new Enumeration<?>[sharedLibraryLoadersCount +
+ sharedLibraryLoadersAfterCount
+ + 1];
+ // First add sharedLibrary resources.
// This will add duplicate resources if a shared library is loaded twice, but that's ok
// as we don't guarantee uniqueness.
- for (int i = 0; i < sharedLibraryLoaders.length; i++) {
+ int i = 0;
+ for (; i < sharedLibraryLoadersCount; i++) {
try {
tmp[i] = sharedLibraryLoaders[i].getResources(name);
} catch (IOException e) {
// Ignore.
}
}
- tmp[sharedLibraryLoaders.length] = myResources;
+ // Then add resource from this dex path.
+ tmp[i++] = myResources;
+
+ // Finally add resources from shared libraries that are to be loaded after.
+ for (int j = 0; j < sharedLibraryLoadersAfterCount; i++, j++) {
+ try {
+ tmp[i] = sharedLibraryLoadersAfter[j].getResources(name);
+ } catch (IOException e) {
+ // Ignore.
+ }
+ }
return new CompoundEnumeration<>(tmp);
}
diff --git a/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java b/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java
index f5e40b6..25a9557 100644
--- a/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DelegateLastClassLoader.java
@@ -136,7 +136,43 @@
public DelegateLastClassLoader(
String dexPath, String librarySearchPath, ClassLoader parent,
ClassLoader[] sharedLibraryLoaders) {
- super(dexPath, librarySearchPath, parent, sharedLibraryLoaders);
+ this(dexPath, librarySearchPath, parent, sharedLibraryLoaders, null);
+ }
+
+ /**
+ * Creates a {@code DelegateLastClassLoader} that operates on a given {@code dexPath}
+ * and a {@code librarySearchPath}.
+ *
+ * The {@code dexPath} should consist of one or more of the following, separated by
+ * {@code File.pathSeparator}, which is {@code ":"} on Android.
+ *
+ * <ul>
+ * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as well as arbitrary
+ * resources.
+ * <li>Raw ".dex" files (not inside a zip file).
+ * </ul>
+ *
+ * @param dexPath the list of jar/apk files containing classes and resources, delimited by
+ * {@code File.pathSeparator}, which defaults to {@code ":"} on Android.
+ * @param librarySearchPath the list of directories containing native libraries, delimited
+ * by {@code File.pathSeparator}; may be {@code null}.
+ * @param parent the parent class loader. May be {@code null} for the boot classloader.
+ * @param sharedLibraryLoaders class loaders of Java shared libraries
+ * used by this new class loader. The shared library loaders are
+ * always checked before the {@code dexPath} when looking
+ * up classes and resources.
+ * @param sharedLibraryLoadersAfter class loaders of Java shared libraries
+ * used by this new class loader. These shared library loaders are
+ * always checked <b>after</b> the {@code dexPath} when looking
+ * up classes and resources.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public DelegateLastClassLoader(
+ String dexPath, String librarySearchPath, ClassLoader parent,
+ ClassLoader[] sharedLibraryLoaders, ClassLoader[] sharedLibraryLoadersAfter) {
+ super(dexPath, librarySearchPath, parent, sharedLibraryLoaders, sharedLibraryLoadersAfter);
// Delegating is the default behavior.
this.delegateResourceLoading = true;
}
diff --git a/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
index 2cd3b61..5174d05 100644
--- a/dalvik/src/main/java/dalvik/system/PathClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -103,6 +103,46 @@
public PathClassLoader(
@NonNull String dexPath, @Nullable String librarySearchPath, @Nullable ClassLoader parent,
@Nullable ClassLoader[] sharedLibraryLoaders) {
- super(dexPath, librarySearchPath, parent, sharedLibraryLoaders);
+ this(dexPath, librarySearchPath, parent, sharedLibraryLoaders, null);
+ }
+
+ /**
+ * Creates a {@code PathClassLoader} that operates on two given
+ * lists of files and directories. The entries of the first list
+ * should be one of the following:
+ *
+ * <ul>
+ * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
+ * well as arbitrary resources.
+ * <li>Raw ".dex" files (not inside a zip file).
+ * </ul>
+ *
+ * The entries of the second list should be directories containing
+ * native library files.
+ *
+ * @param dexPath the list of jar/apk files containing classes and
+ * resources, delimited by {@code File.pathSeparator}, which
+ * defaults to {@code ":"} on Android
+ * @param librarySearchPath the list of directories containing native
+ * libraries, delimited by {@code File.pathSeparator}; may be
+ * {@code null}
+ * @param parent the parent class loader
+ * @param sharedLibraryLoaders class loaders of Java shared libraries
+ * used by this new class loader. The shared library loaders are always
+ * checked before the {@code dexPath} when looking
+ * up classes and resources.
+ * @param sharedLibraryLoadersAfter class loaders of Java shared libraries
+ * used by this new class loader. These shared library loaders are always
+ * checked <b>after</b> the {@code dexPath} when looking
+ * up classes and resources.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public PathClassLoader(
+ @NonNull String dexPath, @Nullable String librarySearchPath,
+ @Nullable ClassLoader parent, @Nullable ClassLoader[] sharedLibraryLoaders,
+ @Nullable ClassLoader[] sharedLibraryLoadersAfter) {
+ super(dexPath, librarySearchPath, parent, sharedLibraryLoaders, sharedLibraryLoadersAfter);
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
index 601d522..bd5c687 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
@@ -122,7 +122,7 @@
// regression for HARMONY-1195
try {
- os = new PrintStream(bos, true, null);
+ os = new PrintStream(bos, true, (String) null);
fail("Should throw NPE");
} catch (NullPointerException e) {
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java
index 31124ce..cb3c01d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/spi/AbstractSelectableChannelTest.java
@@ -220,7 +220,7 @@
// if channel closed
msc.close();
try {
- msc.register(acceptSelector, SelectionKey.OP_READ, null);
+ msc.register(acceptSelector, SelectionKey.OP_ACCEPT, null);
fail("Should throw ClosedChannelException");
} catch (ClosedChannelException e) {
// expected
diff --git a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
index 28517aa..53e0398 100644
--- a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
@@ -147,7 +147,7 @@
assertFalse(f.isCancelled());
assertTrue(f.isDone());
assertTrue(f.isCompletedExceptionally());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
}
void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -202,7 +202,7 @@
assertTrue(f.isDone());
assertTrue(f.isCompletedExceptionally());
assertTrue(f.isCancelled());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
}
/**
@@ -349,12 +349,12 @@
f = new CompletableFuture<String>();
assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
f = new CompletableFuture<String>();
assertTrue(f.cancel(mayInterruptIfRunning));
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
}
}
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
index e763ae4..194dd58 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
@@ -834,9 +834,7 @@
1, 1, MILLISECONDS));
periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
1, 1, MILLISECONDS));
- // Android-changed: Use a longer delay to ensure task does not expire
- // delayeds.add(p.schedule(task, 1, MILLISECONDS));
- delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
+ delayeds.add(p.schedule(task, 1, MILLISECONDS));
assertTrue(p.getQueue().containsAll(periodics));
assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
index 8f65c84..81f7370 100644
--- a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
@@ -783,9 +783,7 @@
1, 1, MILLISECONDS));
periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2),
1, 1, MILLISECONDS));
- // Android-changed: Use a longer delay to ensure task does not expire
- // delayeds.add(p.schedule(task, 1, MILLISECONDS));
- delayeds.add(p.schedule(task, LONG_DELAY_MS, MILLISECONDS));
+ delayeds.add(p.schedule(task, 1, MILLISECONDS));
assertTrue(p.getQueue().containsAll(periodics));
assertTrue(p.getQueue().containsAll(delayeds));
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 0b45784..28748f2 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+
<issue
id="NewApi"
message="Class requires API level 32 (current min is 31): `java.lang.invoke.VarHandle`"
@@ -7,7 +8,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="libcore/libart/src/main/java/java/lang/invoke/ArrayElementVarHandle.java"
- line="27"
+ line="26"
column="43"/>
</issue>
@@ -51,7 +52,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="libcore/ojluni/src/main/java/java/lang/invoke/MethodHandles.java"
- line="900"
+ line="901"
column="32"/>
</issue>
@@ -62,7 +63,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="libcore/ojluni/src/main/java/java/lang/invoke/MethodHandles.java"
- line="2470"
+ line="2471"
column="25"/>
</issue>
@@ -73,8 +74,108 @@
errorLine2=" ~~~~~~~~~">
<location
file="libcore/ojluni/src/main/java/java/lang/invoke/MethodHandles.java"
- line="2477"
+ line="2478"
column="62"/>
</issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 32 (current min is 31): `java.security.cert.URICertStoreParameters`"
+ errorLine1=" if (p == null || (!(p instanceof URICertStoreParameters))) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java"
+ line="127"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 32 (current min is 31): `java.security.cert.URICertStoreParameters`"
+ errorLine1=" URICertStoreParameters other = (URICertStoreParameters)p;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java"
+ line="135"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" return TWO;"
+ errorLine2=" ~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+ line="864"
+ column="20" />
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" result = result.add(TWO);"
+ errorLine2=" ~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+ line="882"
+ column="45" />
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" result = result.add(TWO);"
+ errorLine2=" ~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+ line="895"
+ column="37" />
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" z = z.modPow(TWO, this);"
+ errorLine2=" ~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+ line="1112"
+ column="30" />
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" if (w.equals(TWO))"
+ errorLine2=" ~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigInteger.java"
+ line="3821"
+ column="22" />
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" new BigDecimal(BigInteger.TWO, 2, 0, 1),"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigDecimal.java"
+ line="296"
+ column="24" />
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 32 (current min is 31): `java.math.BigInteger#TWO`"
+ errorLine1=" rb = BigInteger.TWO.pow(exponent).multiply(compactVal);"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="libcore/ojluni/src/main/java/java/math/BigDecimal.java"
+ line="956"
+ column="22" />
+ </issue>
+
</issues>
diff --git a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
index 7d3b6f2..064e042 100644
--- a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
@@ -17,6 +17,7 @@
package libcore.dalvik.system;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -234,6 +235,62 @@
}
@Test
+ public void testReporting_withSharedLibraries_loaded_after() throws Exception {
+ final ClassLoader parent = ClassLoader.getSystemClassLoader();
+ final ClassLoader sharedLoaders[] = new ClassLoader[] {
+ new PathClassLoader(jar2.getPath(), /* librarySearchPath */ null, parent),
+ };
+ // Reset so we don't get load reports from creating the shared library CL
+ reporter.reset();
+
+ BaseDexClassLoader bdcl = new PathClassLoader(
+ jar.getPath(), null, parent, null, sharedLoaders);
+
+ assertEquals(1, reporter.loadedDexMapping.size());
+
+ String[] contexts = separateSystemClassLoaderContext(
+ reporter.loadedDexMapping.get(jar.getPath()));
+ // We cannot fully verify the context of the system class loader because its classpath
+ // may vary based on system properties and whether or not we are in a test environment.
+ assertTrue(contexts[1].startsWith("PCL["));
+ // Verify the context for the loaded dex files. The system class loader should be part
+ // of the shared library class loader.
+ assertEquals("PCL[]{~PCL[" + jar2.getPath() + "];" + contexts[1] + "}",
+ contexts[0]);
+ }
+
+ @Test
+ public void testReporting_withSharedLibraries_loaded_before_and_after() throws Exception {
+ final ClassLoader parent = ClassLoader.getSystemClassLoader();
+ final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
+ final String sharedJarPath2 = resourcesMap.get("child.jar").getAbsolutePath();
+ final ClassLoader sharedLoaders[] = new ClassLoader[] {
+ new PathClassLoader(sharedJarPath, /* librarySearchPath */ null, parent),
+ };
+ final ClassLoader sharedLoadersAfter[] = new ClassLoader[] {
+ new PathClassLoader(sharedJarPath2, /* librarySearchPath */ null, parent),
+ };
+ // Reset so we don't get load reports from creating the shared library CL
+ reporter.reset();
+
+ BaseDexClassLoader bdcl = new PathClassLoader(jar.getPath(), null, parent, sharedLoaders,
+ sharedLoadersAfter);
+
+ assertEquals(1, reporter.loadedDexMapping.size());
+
+ String[] contexts = separateSystemClassLoaderContext(
+ reporter.loadedDexMapping.get(jar.getPath()));
+ // We cannot fully verify the context of the system class loader because its classpath
+ // may vary based on system properties and whether or not we are in a test environment.
+ assertTrue(contexts[1].startsWith("PCL["));
+ // Verify the context for the loaded dex files. The system class loader should be part
+ // of the shared library class loader.
+ assertEquals("PCL[]{PCL[" + sharedJarPath + "];" + contexts[1]
+ + "#~PCL[" + sharedJarPath2 + "];" + contexts[1] + "}",
+ contexts[0]);
+ }
+
+ @Test
public void testReporting_multipleJars_withSharedLibraries() throws Exception {
final ClassLoader parent = ClassLoader.getSystemClassLoader();
final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
@@ -277,6 +334,49 @@
}
@Test
+ public void testReporting_multipleJars_withSharedLibraries_loaded_after() throws Exception {
+ final ClassLoader parent = ClassLoader.getSystemClassLoader();
+ final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
+ final ClassLoader sharedLoaders[] = new ClassLoader[] {
+ new PathClassLoader(sharedJarPath, /* librarySearchPath */ null, parent),
+ };
+ // Reset so we don't get load reports from creating the shared library CL
+ reporter.reset();
+
+ BaseDexClassLoader bdcl = new PathClassLoader(
+ String.join(File.pathSeparator, jar.getPath(), jar2.getPath()),
+ null, parent, null, sharedLoaders);
+
+ assertEquals(2, reporter.loadedDexMapping.size());
+
+
+ // Verify the first jar.
+ String[] contexts = separateSystemClassLoaderContext(
+ reporter.loadedDexMapping.get(jar.getPath()));
+ String contextSuffix = "{~PCL[" + sharedJarPath + "];" + contexts[1] + "}";
+
+ // We cannot fully verify the context of the system class loader because its classpath
+ // may vary based on system properties and whether or not we are in a test environment.
+ assertTrue(contexts[1].startsWith("PCL["));
+ // Verify the context for the loaded dex files.
+ assertEquals("PCL[]" + contextSuffix, contexts[0]);
+ // We cannot fully verify the context of the system class loader because its classpath
+ // may vary based on system properties and whether or not we are in a test environment.
+ assertTrue(contexts[1].startsWith("PCL["));
+
+ // Verify the second jar.
+ String[] contexts2 = separateSystemClassLoaderContext(
+ reporter.loadedDexMapping.get(jar2.getPath()));
+ String contextSuffix2 = "{~PCL[" + sharedJarPath + "];" + contexts2[1] + "}";
+
+ // Verify the context for the loaded dex files.
+ assertEquals("PCL[" + jar.getPath() + "]" + contextSuffix2, contexts2[0]);
+ // We cannot fully verify the context of the system class loader because its classpath
+ // may vary based on system properties and whether or not we are in a test environment.
+ assertTrue(contexts2[1].startsWith("PCL[")) ;
+ }
+
+ @Test
public void testReporting_emptyPath() throws Exception {
BaseDexClassLoader cl1 = new PathClassLoader("", ClassLoader.getSystemClassLoader());
assertEquals(Map.<String, String>of(), reporter.loadedDexMapping);
@@ -345,6 +445,16 @@
loader = new DelegateLastClassLoader("", null, parent, sharedLibraries);
assertEquals("parent", readResource(loader, "resource.txt"));
checkResources(loader);
+
+ // PCL[]{~PCL[parent.jar]#~PCL[child.jar]}
+ loader = new PathClassLoader("", null, parent, null, sharedLibraries);
+ assertEquals("parent", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ // DLC[]{~PCL[parent.jar]#~PCL[child.jar]}
+ loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraries);
+ assertEquals("parent", readResource(loader, "resource.txt"));
+ checkResources(loader);
}
@Test
@@ -370,6 +480,16 @@
loader = new DelegateLastClassLoader("", null, parent, sharedLibraries);
assertEquals("child", readResource(loader, "resource.txt"));
checkResources(loader);
+
+ // PCL[]{~PCL[child.jar]#~PCL[parent.jar]}
+ loader = new PathClassLoader("", null, parent, null, sharedLibraries);
+ assertEquals("child", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ // DLC[]{~PCL[child.jar]#~PCL[parent.jar]}
+ loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraries);
+ assertEquals("child", readResource(loader, "resource.txt"));
+ checkResources(loader);
}
@Test
@@ -398,6 +518,16 @@
loader = new DelegateLastClassLoader("", null, parent, sharedLibraryLevel1);
assertEquals("parent", readResource(loader, "resource.txt"));
checkResources(loader);
+
+ // PCL[]{~PCL[child.jar]{PCL[parent.jar]}}
+ loader = new PathClassLoader("", null, parent, null, sharedLibraryLevel1);
+ assertEquals("parent", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ // DLC[]{~PCL[child.jar]{PCL[parent.jar]}}
+ loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraryLevel1);
+ assertEquals("parent", readResource(loader, "resource.txt"));
+ checkResources(loader);
}
@Test
@@ -426,6 +556,16 @@
loader = new DelegateLastClassLoader("", null, parent, sharedLibraryLevel1);
assertEquals("child", readResource(loader, "resource.txt"));
checkResources(loader);
+
+ // PCL[]{~PCL[parent.jar]{PCL[child.jar]}}
+ loader = new PathClassLoader("", null, parent, null, sharedLibraryLevel1);
+ assertEquals("child", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ // DLC[]{~PCL[parent.jar]{PCL[child.jar]}}
+ loader = new DelegateLastClassLoader("", null, parent, null, sharedLibraryLevel1);
+ assertEquals("child", readResource(loader, "resource.txt"));
+ checkResources(loader);
}
@Test
@@ -448,12 +588,163 @@
// Check that the parent was queried first.
assertEquals("parent", readResource(pathLoader, "resource.txt"));
+ // PCL[]{~PCL[child.jar]};PCL[parent.jar]
+ pathLoader = new PathClassLoader("", null, parent, null, sharedLibrary);
+
+ // Check that the parent was queried first.
+ assertEquals("parent", readResource(pathLoader, "resource.txt"));
+
// DLC[]{PCL[child.jar]};PCL[parent.jar]
ClassLoader delegateLast = new DelegateLastClassLoader("", null, parent, sharedLibrary);
// Check that the shared library was queried first.
assertEquals("child", readResource(delegateLast, "resource.txt"));
+ // DLC[]{~PCL[child.jar]};PCL[parent.jar]
+ delegateLast = new DelegateLastClassLoader("", null, parent, null, sharedLibrary);
+
+ // Check that the shared library was queried first.
+ assertEquals("child", readResource(delegateLast, "resource.txt"));
+
+ }
+
+ @Test
+ public void testGetResourceSharedLibraries6() throws Exception {
+ File parentPath = resourcesMap.get("parent.jar");
+ File childPath = resourcesMap.get("child.jar");
+ assertTrue(parentPath != null);
+ assertTrue(childPath != null);
+
+ ClassLoader parent = Object.class.getClassLoader();
+
+ ClassLoader[] sharedLibrary = {
+ new PathClassLoader(childPath.getAbsolutePath(), null, parent),
+ };
+
+ // PCL[]{PCL[child.jar]};PCL[parent.jar]
+ ClassLoader pathLoader = new PathClassLoader(
+ parentPath.getAbsolutePath(), null, parent, sharedLibrary);
+
+ // Check that the parent was queried first.
+ assertEquals("child", readResource(pathLoader, "resource.txt"));
+
+ // PCL[]{~PCL[child.jar]};PCL[parent.jar]
+ pathLoader = new PathClassLoader(
+ parentPath.getAbsolutePath(), null, parent, null, sharedLibrary);
+
+ // Check that the parent was queried first.
+ assertEquals("parent", readResource(pathLoader, "resource.txt"));
+ // confirm resource from shard lib is available
+ checkResources(pathLoader);
+
+ // PCL[]{~PCL[child.jar]};PCL[]
+ pathLoader = new PathClassLoader("", null, parent, null, sharedLibrary);
+ // Check that the shared library was queried last.
+ assertEquals("child", readResource(pathLoader, "resource.txt"));
+
+ // DLC[]{PCL[child.jar]};PCL[parent.jar]
+ ClassLoader delegateLast = new DelegateLastClassLoader(
+ parentPath.getAbsolutePath(), null, parent, sharedLibrary);
+
+ // Check that the shared library was queried first.
+ assertEquals("child", readResource(delegateLast, "resource.txt"));
+
+ // DLC[]{~PCL[child.jar]};PCL[parent.jar]
+ delegateLast = new DelegateLastClassLoader(
+ parentPath.getAbsolutePath(), null, parent, null, sharedLibrary);
+
+ // Check that the shared library was queried first.
+ assertEquals("parent", readResource(delegateLast, "resource.txt"));
+ // confirm resource from shard lib is available
+ checkResources(delegateLast);
+
+ // DLC[]{~PCL[child.jar]};PCL[]
+ delegateLast = new DelegateLastClassLoader("", null, parent, null, sharedLibrary);
+ // Check that the shared library was queried last.
+ assertEquals("child", readResource(delegateLast, "resource.txt"));
+
+ }
+
+ @Test
+ public void testGetResourceSharedLibraries7() throws Exception {
+ File parentPath = resourcesMap.get("parent.jar");
+ File childPath = resourcesMap.get("child.jar");
+ assertTrue(parentPath != null);
+ assertTrue(childPath != null);
+
+ ClassLoader parent = Object.class.getClassLoader();
+
+ ClassLoader[] sharedLibrary1 = {
+ new PathClassLoader(parentPath.getAbsolutePath(), null, parent),
+ };
+
+ ClassLoader[] sharedLibrary2 = {
+ new PathClassLoader(childPath.getAbsolutePath(), null, parent),
+ };
+
+ // PCL[]{PCL[parent.jar]#~PCL[child.jar]}
+ ClassLoader loader = new PathClassLoader("", null, parent, sharedLibrary1, sharedLibrary2);
+ assertEquals("parent", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ // PCL[]{PCL[child.jar]#~PCL[parent.jar]}
+ loader = new PathClassLoader("", null, parent, sharedLibrary2, sharedLibrary1);
+ assertEquals("child", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ loader = new DelegateLastClassLoader("", null, parent, sharedLibrary1, sharedLibrary2);
+ assertEquals("parent", readResource(loader, "resource.txt"));
+ checkResources(loader);
+
+ // PCL[]{PCL[child.jar]#~PCL[parent.jar]}
+ loader = new DelegateLastClassLoader("", null, parent, sharedLibrary2, sharedLibrary1);
+ assertEquals("child", readResource(loader, "resource.txt"));
+ checkResources(loader);
+ }
+
+ @Test
+ public void testLookupOrder_loadClass() throws Exception {
+ File parentPath = resourcesMap.get("parent.jar");
+ File childPath = resourcesMap.get("child.jar");
+ assertTrue(parentPath != null);
+ assertTrue(childPath != null);
+
+ ClassLoader parent = Object.class.getClassLoader();
+
+ ClassLoader[] sharedLibrary1 = {
+ new PathClassLoader(parentPath.getAbsolutePath(), null, parent),
+ };
+
+ ClassLoader[] sharedLibrary2 = {
+ new PathClassLoader(childPath.getAbsolutePath(), null, parent),
+ };
+
+ // PCL[]{PCL[parent.jar]#~PCL[child.jar]}
+ ClassLoader loader = new PathClassLoader("", null, parent, sharedLibrary1, sharedLibrary2);
+ assertEquals("A_parent", callMethod(loader, "toString", sharedLibrary1[0]));
+ Class<?> parentClass = loader.loadClass("libcore.test.delegatelast.Parent");
+ assertSame(sharedLibrary1[0], parentClass.getClassLoader());
+ Class<?> childClass = loader.loadClass("libcore.test.delegatelast.Child");
+ assertSame(sharedLibrary2[0], childClass.getClassLoader());
+
+
+ // Note that the order is reversed here. "parent" is looked up before "child".
+ loader = new PathClassLoader("", null, parent, sharedLibrary2, sharedLibrary1);
+ assertEquals("A_child", callMethod(loader, "toString", sharedLibrary2[0]));
+ parentClass = loader.loadClass("libcore.test.delegatelast.Parent");
+ assertSame(sharedLibrary1[0], parentClass.getClassLoader());
+ childClass = loader.loadClass("libcore.test.delegatelast.Child");
+ assertSame(sharedLibrary2[0], childClass.getClassLoader());
+ }
+
+ private static String callMethod(ClassLoader cl, String name, ClassLoader srcofclass)
+ throws Exception {
+ Class<?> clazz = cl.loadClass("libcore.test.delegatelast.A");
+ assertSame(srcofclass, clazz.getClassLoader());
+
+ Method method = clazz.getMethod(name);
+ Object obj = clazz.newInstance();
+ return (String) method.invoke(obj);
}
@Test
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTest.java b/luni/src/test/java/libcore/java/lang/ThreadTest.java
index 29ed4a2..439aa9a 100644
--- a/luni/src/test/java/libcore/java/lang/ThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThreadTest.java
@@ -590,6 +590,8 @@
}
}
+ // BEGIN Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ /*
@Test
public void onSpinWait() throws InterruptedException {
SpinWaitThread t = new SpinWaitThread();
@@ -614,4 +616,6 @@
done = true;
}
}
+ */
+ // END Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java
new file mode 100644
index 0000000..12ec722
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/ArrayBlockingQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ArrayBlockingQueueTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(capacity);
+ for (int i = 0; i < capacity; ++i) {
+ queue.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ queue.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java
new file mode 100644
index 0000000..6a6f7ea
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedDequeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConcurrentLinkedDequeTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();
+ for (int i = 0; i < capacity; ++i) {
+ deque.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ deque.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(deque.size() * (deque.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java
new file mode 100644
index 0000000..6a1bffa
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/ConcurrentLinkedQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConcurrentLinkedQueueTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
+ for (int i = 0; i < capacity; ++i) {
+ queue.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ queue.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java b/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
index 80005df..29ceaebe 100644
--- a/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
+++ b/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
@@ -285,7 +285,7 @@
public void testDoesNotRetainToArray() {
String[] strings = { "a", "b", "c" };
List<String> asList = Arrays.asList(strings);
- assertEquals(String[].class, asList.toArray().getClass());
+
CopyOnWriteArrayList<Object> objects = new CopyOnWriteArrayList<Object>(asList);
objects.add(Boolean.TRUE);
}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java b/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
index 578970e..48d4170 100644
--- a/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
+++ b/luni/src/test/java/libcore/java/util/concurrent/ForkJoinPoolTest.java
@@ -70,4 +70,94 @@
fail("Unexpected exception: " + t.getMessage());
}
}
+
+ @Test
+ public void testConstructor_withKeepAliveTime() {
+
+ try {
+ ForkJoinPool pool = new ForkJoinPool(0,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ /*handler*/ null,
+ /*asyncMode*/ false,
+ /*corePoolSize*/ 10,
+ /*maximumPoolSize*/ 10,
+ /*minimumRunnable*/ 1,
+ /*saturate*/ null,
+ /*keepAliveTime*/ 60,
+ /*unit*/ TimeUnit.SECONDS);
+ fail("Expected IllegalArgumentException when parallelism is 0");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ ForkJoinPool pool = new ForkJoinPool(-1,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ /*handler*/ null,
+ /*asyncMode*/ false,
+ /*corePoolSize*/ 10,
+ /*maximumPoolSize*/ 10,
+ /*minimumRunnable*/ 1,
+ /*saturate*/ null,
+ /*keepAliveTime*/ 60,
+ /*unit*/ TimeUnit.SECONDS);
+ fail("Expected IllegalArgumentException when parallelism is less than 0");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ ForkJoinPool pool = new ForkJoinPool(8,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ /*handler*/ null,
+ /*asyncMode*/ false,
+ /*corePoolSize*/ 10,
+ /*maximumPoolSize*/ 5,
+ /*minimumRunnable*/ 1,
+ /*saturate*/ null,
+ /*keepAliveTime*/ 60,
+ /*unit*/ TimeUnit.SECONDS);
+ fail("Expected IllegalArgumentException when maximumPoolSize is less than parallelism");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ ForkJoinPool pool = new ForkJoinPool(8,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ /*handler*/ null,
+ /*asyncMode*/ false,
+ /*corePoolSize*/ 10,
+ /*maximumPoolSize*/ 10,
+ /*minimumRunnable*/ 1,
+ /*saturate*/ null,
+ /*keepAliveTime*/ 0,
+ /*unit*/ TimeUnit.SECONDS);
+ fail("Expected IllegalArgumentException when keepAlivetime is 0");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ ForkJoinPool pool = new ForkJoinPool(8,
+ null,
+ /*handler*/ null,
+ /*asyncMode*/ false,
+ /*corePoolSize*/ 10,
+ /*maximumPoolSize*/ 10,
+ /*minimumRunnable*/ 1,
+ /*saturate*/ null,
+ /*keepAliveTime*/ 60,
+ /*unit*/ TimeUnit.SECONDS);
+ fail("Expected NullPointerException when factory is null");
+ } catch (NullPointerException e) {
+ }
+
+ ForkJoinPool pool = new ForkJoinPool(8,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ /*handler*/ null,
+ /*asyncMode*/ false,
+ /*corePoolSize*/ 10,
+ /*maximumPoolSize*/ 10,
+ /*minimumRunnable*/ 1,
+ /*saturate*/ null,
+ /*keepAliveTime*/ 60,
+ /*unit*/ TimeUnit.SECONDS);
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java
new file mode 100644
index 0000000..66dd942
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingDequeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LinkedBlockingDequeTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>();
+ for (int i = 0; i < capacity; ++i) {
+ deque.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ deque.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(deque.size() * (deque.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java
new file mode 100644
index 0000000..4363988
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/LinkedBlockingQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LinkedBlockingQueueTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
+ for (int i = 0; i < capacity; ++i) {
+ queue.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ queue.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java
new file mode 100644
index 0000000..5b09284
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/LinkedTransferQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LinkedTransferQueueTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ LinkedTransferQueue<Integer> queue = new LinkedTransferQueue<>();
+ for (int i = 0; i < capacity; ++i) {
+ queue.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ queue.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java b/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java
new file mode 100644
index 0000000..ba7bc0c
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/concurrent/PriorityBlockingQueueTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * 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 libcore.java.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.atomic.LongAdder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PriorityBlockingQueueTest {
+
+ @Test
+ public void testForEach() {
+ int capacity = 10;
+ PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>(capacity);
+ for (int i = 0; i < capacity; ++i) {
+ queue.add(Integer.valueOf(i+1));
+ }
+ LongAdder adder = new LongAdder();
+ queue.forEach((Integer x) -> adder.add(x.longValue()));
+ // The size is small enough for the sum not to overflow
+ assertEquals(queue.size() * (queue.size() + 1) / 2, adder.sum());
+ }
+}
diff --git a/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java b/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java
index 531dfb0..9c3a936 100644
--- a/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/io/PrintWriter.annotated.java
@@ -41,12 +41,18 @@
public PrintWriter(@libcore.util.NonNull java.io.OutputStream out, boolean autoFlush) { throw new RuntimeException("Stub!"); }
+public PrintWriter(@libcore.util.NonNull java.io.OutputStream out, boolean autoFlush, @libcore.util.NonNull java.nio.charset.Charset charset) { throw new RuntimeException("Stub!"); }
+
public PrintWriter(@libcore.util.NonNull java.lang.String fileName) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
public PrintWriter(@libcore.util.NonNull java.lang.String fileName, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+public PrintWriter(@libcore.util.NonNull java.lang.String fileName, @libcore.util.NonNull java.nio.charset.Charset charset) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
public PrintWriter(@libcore.util.NonNull java.io.File file) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+public PrintWriter(@libcore.util.NonNull java.io.File file, @libcore.util.NonNull java.nio.charset.Charset charset) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
public PrintWriter(@libcore.util.NonNull java.io.File file, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
public void flush() { throw new RuntimeException("Stub!"); }
diff --git a/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java b/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java
index 522c3af..e8f71c4 100644
--- a/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/math/BigInteger.annotated.java
@@ -28,8 +28,12 @@
@SuppressWarnings({"unchecked", "deprecation", "all"})
public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> {
+ public BigInteger(byte[] val, int off, int len) { throw new RuntimeException("Stub!"); }
+
public BigInteger(byte[] val) { throw new RuntimeException("Stub!"); }
+ public BigInteger(int signum, byte[] magnitude, int off, int len) { throw new RuntimeException("Stub!"); }
+
public BigInteger(int signum, byte[] magnitude) { throw new RuntimeException("Stub!"); }
public BigInteger(@libcore.util.NonNull java.lang.String val, int radix) { throw new RuntimeException("Stub!"); }
@@ -52,6 +56,8 @@
@libcore.util.NonNull public static final BigInteger ONE = null;
+ @libcore.util.NonNull public static final java.math.BigInteger TWO = null;
+
@libcore.util.NonNull public static final BigInteger TEN = null;
@libcore.util.NonNull public BigInteger add(@libcore.util.NonNull BigInteger val) { throw new RuntimeException("Stub!"); }
@@ -76,6 +82,10 @@
public int signum() { return 0; }
+ @libcore.util.NonNull public BigInteger sqrt() { throw new RuntimeException("Stub!"); }
+
+ @libcore.util.NonNull public BigInteger[] sqrtAndRemainder() { throw new RuntimeException("Stub!"); }
+
@libcore.util.NonNull public BigInteger mod(@libcore.util.NonNull BigInteger m) { throw new RuntimeException("Stub!"); }
@libcore.util.NonNull public BigInteger modPow(@libcore.util.NonNull BigInteger exponent, @libcore.util.NonNull BigInteger m) { throw new RuntimeException("Stub!"); }
diff --git a/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java
index 99dec24..891f9b9 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Arrays.annotated.java
@@ -169,22 +169,44 @@
public static boolean equals(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(char @libcore.util.Nullable [] a, char @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(byte @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, byte @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(boolean @libcore.util.Nullable [] a, boolean @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(boolean @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, boolean @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(double @libcore.util.Nullable [] a, double @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(double @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, double @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(float @libcore.util.Nullable [] a, float @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(float @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, float @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
public static boolean equals(java.lang.@libcore.util.Nullable Object @libcore.util.Nullable [] a, java.lang.@libcore.util.Nullable Object @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+public static boolean equals(java.lang.@libcore.util.Nullable java.lang.Object @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, java.lang.@libcore.util.Nullable java.lang.Object @libcore.util.NonNull[] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> boolean equals(T @libcore.util.Nullable[] a, T @libcore.util.Nullable [] a2, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> boolean equals(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
public static void fill(long @libcore.util.NonNull [] a, long val) { throw new RuntimeException("Stub!"); }
public static void fill(long @libcore.util.NonNull [] a, int fromIndex, int toIndex, long val) { throw new RuntimeException("Stub!"); }
@@ -353,4 +375,100 @@
@libcore.util.NonNull public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
@libcore.util.NonNull public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
+public static int compare(boolean @libcore.util.Nullable [] a, boolean @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(boolean @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, boolean @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(byte @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, byte @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(byte @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, byte @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(char @libcore.util.Nullable [] a, char @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(float @libcore.util.Nullable [] a, float @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(float @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, float @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int compare(double @libcore.util.Nullable [] a, double @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(double @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, double @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> int compare(T @libcore.util.Nullable [] a, T @libcore.util.Nullable [] b) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> int compare(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> int compare(T @libcore.util.Nullable [] a, T @libcore.utill.Nullable [] b, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> int compare(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(boolean @libcore.util.NonNull [] a, boolean @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(boolean @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, boolean @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(byte @libcore.util.NonNull [] a, byte @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(char @libcore.util.NonNull [] a, char @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(char @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, char @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(short @libcore.util.NonNull [] a, short @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(short @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, short @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(int @libcore.util.NonNull [] a, int @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(int @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, int @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(long @libcore.util.NonNull [] a, long @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(long @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, long @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(float @libcore.util.NonNull [] a, float @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(float @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, float @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(double @libcore.util.NonNull [] a, double @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(double @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, double @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(java.lang.Object @libcore.util.NonNull [] a, java.lang.Object @libcore.util.NonNull [] b) { throw new RuntimeException("Stub!"); }
+
+public static int mismatch(java.lang.Object @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, java.lang.Object @libcore.util.NonNull [] b, int bFromIndex, int bToIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> int mismatch(T @libcore.util.NonNull [] a, T @libcore.util.NonNull [] b, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> int mismatch(T @libcore.util.NonNull [] a, int aFromIndex, int aToIndex, T @libcore.util.NonNull [] b, int bFromIndex, int bToIndex, @libcore.util.NonNull java.util.Comparator<? super T> cmp) { throw new RuntimeException("Stub!"); }
}
diff --git a/ojluni/src/main/java/java/io/FileReader.java b/ojluni/src/main/java/java/io/FileReader.java
index acc3a19..d37cd8c 100644
--- a/ojluni/src/main/java/java/io/FileReader.java
+++ b/ojluni/src/main/java/java/io/FileReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2001, 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
@@ -25,30 +25,32 @@
package java.io;
+import java.nio.charset.Charset;
/**
- * Convenience class for reading character files. The constructors of this
- * class assume that the default character encoding and the default byte-buffer
- * size are appropriate. To specify these values yourself, construct an
- * InputStreamReader on a FileInputStream.
+ * Reads text from character files using a default buffer size. Decoding from bytes
+ * to characters uses either a specified {@linkplain java.nio.charset.Charset charset}
+ * or the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * <p><code>FileReader</code> is meant for reading streams of characters.
- * For reading streams of raw bytes, consider using a
- * <code>FileInputStream</code>.
+ * <p>
+ * The {@code FileReader} is meant for reading streams of characters. For reading
+ * streams of raw bytes, consider using a {@code FileInputStream}.
*
* @see InputStreamReader
* @see FileInputStream
*
* @author Mark Reinhold
- * @since JDK1.1
+ * @since 1.1
*/
public class FileReader extends InputStreamReader {
/**
- * Creates a new <tt>FileReader</tt>, given the name of the
- * file to read from.
+ * Creates a new {@code FileReader}, given the name of the file to read,
+ * using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * @param fileName the name of the file to read from
+ * @param fileName the name of the file to read
* @exception FileNotFoundException if the named file does not exist,
* is a directory rather than a regular file,
* or for some other reason cannot be opened for
@@ -59,10 +61,11 @@
}
/**
- * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
- * to read from.
+ * Creates a new {@code FileReader}, given the {@code File} to read,
+ * using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * @param file the <tt>File</tt> to read from
+ * @param file the {@code File} to read
* @exception FileNotFoundException if the file does not exist,
* is a directory rather than a regular file,
* or for some other reason cannot be opened for
@@ -73,13 +76,47 @@
}
/**
- * Creates a new <tt>FileReader</tt>, given the
- * <tt>FileDescriptor</tt> to read from.
+ * Creates a new {@code FileReader}, given the {@code FileDescriptor} to read,
+ * using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * @param fd the FileDescriptor to read from
+ * @param fd the {@code FileDescriptor} to read
*/
public FileReader(FileDescriptor fd) {
super(new FileInputStream(fd));
}
+ /**
+ * Creates a new {@code FileReader}, given the name of the file to read
+ * and the {@linkplain java.nio.charset.Charset charset}.
+ *
+ * @param fileName the name of the file to read
+ * @param charset the {@linkplain java.nio.charset.Charset charset}
+ * @exception IOException if the named file does not exist,
+ * is a directory rather than a regular file,
+ * or for some other reason cannot be opened for
+ * reading.
+ *
+ * @since 11
+ */
+ public FileReader(String fileName, Charset charset) throws IOException {
+ super(new FileInputStream(fileName), charset);
+ }
+
+ /**
+ * Creates a new {@code FileReader}, given the {@code File} to read and
+ * the {@linkplain java.nio.charset.Charset charset}.
+ *
+ * @param file the {@code File} to read
+ * @param charset the {@linkplain java.nio.charset.Charset charset}
+ * @exception IOException if the file does not exist,
+ * is a directory rather than a regular file,
+ * or for some other reason cannot be opened for
+ * reading.
+ *
+ * @since 11
+ */
+ public FileReader(File file, Charset charset) throws IOException {
+ super(new FileInputStream(file), charset);
+ }
}
diff --git a/ojluni/src/main/java/java/io/FileWriter.java b/ojluni/src/main/java/java/io/FileWriter.java
index 7475ea4..e49b316 100644
--- a/ojluni/src/main/java/java/io/FileWriter.java
+++ b/ojluni/src/main/java/java/io/FileWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2001, 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
@@ -25,34 +25,37 @@
package java.io;
+import java.nio.charset.Charset;
/**
- * Convenience class for writing character files. The constructors of this
- * class assume that the default character encoding and the default byte-buffer
- * size are acceptable. To specify these values yourself, construct an
- * OutputStreamWriter on a FileOutputStream.
+ * Writes text to character files using a default buffer size. Encoding from characters
+ * to bytes uses either a specified {@linkplain java.nio.charset.Charset charset}
+ * or the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * <p>Whether or not a file is available or may be created depends upon the
+ * <p>
+ * Whether or not a file is available or may be created depends upon the
* underlying platform. Some platforms, in particular, allow a file to be
- * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
+ * opened for writing by only one {@code FileWriter} (or other file-writing
* object) at a time. In such situations the constructors in this class
* will fail if the file involved is already open.
*
- * <p><code>FileWriter</code> is meant for writing streams of characters.
- * For writing streams of raw bytes, consider using a
- * <code>FileOutputStream</code>.
+ * <p>
+ * The {@code FileWriter} is meant for writing streams of characters. For writing
+ * streams of raw bytes, consider using a {@code FileOutputStream}.
*
* @see OutputStreamWriter
* @see FileOutputStream
*
* @author Mark Reinhold
- * @since JDK1.1
+ * @since 1.1
*/
public class FileWriter extends OutputStreamWriter {
/**
- * Constructs a FileWriter object given a file name.
+ * Constructs a {@code FileWriter} given a file name, using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
*
* @param fileName String The system-dependent filename.
* @throws IOException if the named file exists but is a directory rather
@@ -64,11 +67,12 @@
}
/**
- * Constructs a FileWriter object given a file name with a boolean
- * indicating whether or not to append the data written.
+ * Constructs a {@code FileWriter} given a file name and a boolean indicating
+ * whether to append the data written, using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
* @param fileName String The system-dependent filename.
- * @param append boolean if <code>true</code>, then data will be written
+ * @param append boolean if {@code true}, then data will be written
* to the end of the file rather than the beginning.
* @throws IOException if the named file exists but is a directory rather
* than a regular file, does not exist but cannot be
@@ -79,9 +83,11 @@
}
/**
- * Constructs a FileWriter object given a File object.
+ * Constructs a {@code FileWriter} given the {@code File} to write,
+ * using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
*
- * @param file a File object to write to.
+ * @param file the {@code File} to write.
* @throws IOException if the file exists but is a directory rather than
* a regular file, does not exist but cannot be created,
* or cannot be opened for any other reason
@@ -91,12 +97,12 @@
}
/**
- * Constructs a FileWriter object given a File object. If the second
- * argument is <code>true</code>, then bytes will be written to the end
- * of the file rather than the beginning.
+ * Constructs a {@code FileWriter} given the {@code File} to write and
+ * a boolean indicating whether to append the data written, using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * @param file a File object to write to
- * @param append if <code>true</code>, then bytes will be written
+ * @param file the {@code File} to write
+ * @param append if {@code true}, then bytes will be written
* to the end of the file rather than the beginning
* @throws IOException if the file exists but is a directory rather than
* a regular file, does not exist but cannot be created,
@@ -108,12 +114,83 @@
}
/**
- * Constructs a FileWriter object associated with a file descriptor.
+ * Constructs a {@code FileWriter} given a file descriptor,
+ * using the platform's
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
*
- * @param fd FileDescriptor object to write to.
+ * @param fd the {@code FileDescriptor} to write.
*/
public FileWriter(FileDescriptor fd) {
super(new FileOutputStream(fd));
}
+
+ /**
+ * Constructs a {@code FileWriter} given a file name and
+ * {@linkplain java.nio.charset.Charset charset}.
+ *
+ * @param fileName the name of the file to write
+ * @param charset the {@linkplain java.nio.charset.Charset charset}
+ * @throws IOException if the named file exists but is a directory rather
+ * than a regular file, does not exist but cannot be
+ * created, or cannot be opened for any other reason
+ *
+ * @since 11
+ */
+ public FileWriter(String fileName, Charset charset) throws IOException {
+ super(new FileOutputStream(fileName), charset);
+ }
+
+ /**
+ * Constructs a {@code FileWriter} given a file name,
+ * {@linkplain java.nio.charset.Charset charset} and a boolean indicating
+ * whether to append the data written.
+ *
+ * @param fileName the name of the file to write
+ * @param charset the {@linkplain java.nio.charset.Charset charset}
+ * @param append a boolean. If {@code true}, the writer will write the data
+ * to the end of the file rather than the beginning.
+ * @throws IOException if the named file exists but is a directory rather
+ * than a regular file, does not exist but cannot be
+ * created, or cannot be opened for any other reason
+ *
+ * @since 11
+ */
+ public FileWriter(String fileName, Charset charset, boolean append) throws IOException {
+ super(new FileOutputStream(fileName, append), charset);
+ }
+
+ /**
+ * Constructs a {@code FileWriter} given the {@code File} to write and
+ * {@linkplain java.nio.charset.Charset charset}.
+ *
+ * @param file the {@code File} to write
+ * @param charset the {@linkplain java.nio.charset.Charset charset}
+ * @throws IOException if the file exists but is a directory rather than
+ * a regular file, does not exist but cannot be created,
+ * or cannot be opened for any other reason
+ *
+ * @since 11
+ */
+ public FileWriter(File file, Charset charset) throws IOException {
+ super(new FileOutputStream(file), charset);
+ }
+
+ /**
+ * Constructs a {@code FileWriter} given the {@code File} to write,
+ * {@linkplain java.nio.charset.Charset charset} and a boolean indicating
+ * whether to append the data written.
+ *
+ * @param file the {@code File} to write
+ * @param charset the {@linkplain java.nio.charset.Charset charset}
+ * @param append a boolean. If {@code true}, the writer will write the data
+ * to the end of the file rather than the beginning.
+ * @throws IOException if the file exists but is a directory rather than
+ * a regular file, does not exist but cannot be created,
+ * or cannot be opened for any other reason
+ * @since 11
+ */
+ public FileWriter(File file, Charset charset, boolean append) throws IOException {
+ super(new FileOutputStream(file, append), charset);
+ }
}
diff --git a/ojluni/src/main/java/java/io/PrintStream.java b/ojluni/src/main/java/java/io/PrintStream.java
index 809d39b..7df8353 100644
--- a/ojluni/src/main/java/java/io/PrintStream.java
+++ b/ojluni/src/main/java/java/io/PrintStream.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
@@ -33,26 +33,32 @@
import java.nio.charset.UnsupportedCharsetException;
/**
- * A <code>PrintStream</code> adds functionality to another output stream,
+ * A {@code PrintStream} adds functionality to another output stream,
* namely the ability to print representations of various data values
* conveniently. Two other features are provided as well. Unlike other output
- * streams, a <code>PrintStream</code> never throws an
- * <code>IOException</code>; instead, exceptional situations merely set an
- * internal flag that can be tested via the <code>checkError</code> method.
- * Optionally, a <code>PrintStream</code> can be created so as to flush
- * automatically; this means that the <code>flush</code> method is
+ * streams, a {@code PrintStream} never throws an
+ * {@code IOException}; instead, exceptional situations merely set an
+ * internal flag that can be tested via the {@code checkError} method.
+ * Optionally, a {@code PrintStream} can be created so as to flush
+ * automatically; this means that the {@code flush} method is
* automatically invoked after a byte array is written, one of the
- * <code>println</code> methods is invoked, or a newline character or byte
- * (<code>'\n'</code>) is written.
+ * {@code println} methods is invoked, or a newline character or byte
+ * ({@code '\n'}) is written.
*
- * <p> All characters printed by a <code>PrintStream</code> are converted into
- * bytes using the platform's default character encoding. The <code>{@link
- * PrintWriter}</code> class should be used in situations that require writing
- * characters rather than bytes.
+ * <p> All characters printed by a {@code PrintStream} are converted into
+ * bytes using the given encoding or charset, or platform's default character
+ * encoding if not specified.
+ * The {@link PrintWriter} class should be used in situations that require
+ * writing characters rather than bytes.
+ *
+ * <p> This class always replaces malformed and unmappable character sequences with
+ * the charset's default replacement string.
+ * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
+ * control over the encoding process is required.
*
* @author Frank Yellin
* @author Mark Reinhold
- * @since JDK1.0
+ * @since 1.0
*/
public class PrintStream extends FilterOutputStream
@@ -110,24 +116,13 @@
// this.textOut = new BufferedWriter(charOut);
}
- private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
- super(out);
- this.autoFlush = autoFlush;
- // Android-changed: Lazy initialization of charOut and textOut.
- // this.charOut = new OutputStreamWriter(this, charset);
- // this.textOut = new BufferedWriter(charOut);
- this.charset = charset;
- }
-
/* Variant of the private constructor so that the given charset name
* can be verified before evaluating the OutputStream argument. Used
* by constructors creating a FileOutputStream that also take a
* charset name.
*/
- private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
- throws UnsupportedEncodingException
- {
- this(autoFlush, out, charset);
+ private PrintStream(boolean autoFlush, Charset charset, OutputStream out) {
+ this(out, autoFlush, charset);
}
/**
@@ -149,8 +144,8 @@
* printed
* @param autoFlush A boolean; if true, the output buffer will be flushed
* whenever a byte array is written, one of the
- * <code>println</code> methods is invoked, or a newline
- * character or byte (<code>'\n'</code>) is written
+ * {@code println} methods is invoked, or a newline
+ * character or byte ({@code '\n'}) is written
*
* @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
*/
@@ -165,8 +160,8 @@
* printed
* @param autoFlush A boolean; if true, the output buffer will be flushed
* whenever a byte array is written, one of the
- * <code>println</code> methods is invoked, or a newline
- * character or byte (<code>'\n'</code>) is written
+ * {@code println} methods is invoked, or a newline
+ * character or byte ({@code '\n'}) is written
* @param encoding The name of a supported
* <a href="../lang/package-summary.html#charenc">
* character encoding</a>
@@ -179,9 +174,30 @@
public PrintStream(OutputStream out, boolean autoFlush, String encoding)
throws UnsupportedEncodingException
{
- this(autoFlush,
- requireNonNull(out, "Null output stream"),
- toCharset(encoding));
+ this(requireNonNull(out, "Null output stream"), autoFlush, toCharset(encoding));
+ }
+
+ /**
+ * Creates a new print stream, with the specified OutputStream, automatic line
+ * flushing and charset. This convenience constructor creates the necessary
+ * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+ * which will encode characters using the provided charset.
+ *
+ * @param out The output stream to which values and objects will be
+ * printed
+ * @param autoFlush A boolean; if true, the output buffer will be flushed
+ * whenever a byte array is written, one of the
+ * {@code println} methods is invoked, or a newline
+ * character or byte ({@code '\n'}) is written
+ * @param charset A {@linkplain java.nio.charset.Charset charset}
+ *
+ * @since 10
+ */
+ public PrintStream(OutputStream out, boolean autoFlush, Charset charset) {
+ super(out);
+ this.autoFlush = autoFlush;
+ this.charOut = new OutputStreamWriter(this, charset);
+ this.textOut = new BufferedWriter(charOut);
}
/**
@@ -257,6 +273,36 @@
/**
* Creates a new print stream, without automatic line flushing, with the
+ * specified file name and charset. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this print
+ * stream. 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}
+ *
+ * @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
+ *
+ * @since 10
+ */
+ public PrintStream(String fileName, Charset charset) throws IOException {
+ this(false, requireNonNull(charset, "charset"), new FileOutputStream(fileName));
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
* specified file. This convenience constructor creates the necessary
* intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
* which will encode characters using the {@linkplain
@@ -326,6 +372,37 @@
this(false, toCharset(csn), new FileOutputStream(file));
}
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file and charset. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param file
+ * The file to use as the destination of this print stream. 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}
+ *
+ * @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
+ *
+ * @since 10
+ */
+ public PrintStream(File file, Charset charset) throws IOException {
+ this(false, requireNonNull(charset, "charset"), new FileOutputStream(file));
+ }
+
/** Check to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
if (out == null)
@@ -394,21 +471,21 @@
/**
* Flushes the stream and checks its error state. The internal error state
- * is set to <code>true</code> when the underlying output stream throws an
- * <code>IOException</code> other than <code>InterruptedIOException</code>,
- * and when the <code>setError</code> method is invoked. If an operation
+ * is set to {@code true} when the underlying output stream throws an
+ * {@code IOException} other than {@code InterruptedIOException},
+ * and when the {@code setError} method is invoked. If an operation
* on the underlying output stream throws an
- * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
+ * {@code InterruptedIOException}, then the {@code PrintStream}
* converts the exception back into an interrupt by doing:
- * <pre>
+ * <pre>{@code
* Thread.currentThread().interrupt();
- * </pre>
+ * }</pre>
* or the equivalent.
*
- * @return <code>true</code> if and only if this stream has encountered an
- * <code>IOException</code> other than
- * <code>InterruptedIOException</code>, or the
- * <code>setError</code> method has been invoked
+ * @return {@code true} if and only if this stream has encountered an
+ * {@code IOException} other than
+ * {@code InterruptedIOException}, or the
+ * {@code setError} method has been invoked
*/
public boolean checkError() {
if (out != null)
@@ -421,13 +498,13 @@
}
/**
- * Sets the error state of the stream to <code>true</code>.
+ * Sets the error state of the stream to {@code true}.
*
* <p> This method will cause subsequent invocations of {@link
- * #checkError()} to return <tt>true</tt> until {@link
- * #clearError()} is invoked.
+ * #checkError()} to return {@code true} until
+ * {@link #clearError()} is invoked.
*
- * @since JDK1.1
+ * @since 1.1
*/
protected void setError() {
trouble = true;
@@ -437,7 +514,7 @@
* Clears the internal error state of this stream.
*
* <p> This method will cause subsequent invocations of {@link
- * #checkError()} to return <tt>false</tt> until another write
+ * #checkError()} to return {@code false} until another write
* operation fails and invokes {@link #setError()}.
*
* @since 1.6
@@ -453,12 +530,12 @@
/**
* Writes the specified byte to this stream. If the byte is a newline and
- * automatic flushing is enabled then the <code>flush</code> method will be
+ * automatic flushing is enabled then the {@code flush} method will be
* invoked.
*
* <p> Note that the byte is written as given; to write a character that
* will be translated according to the platform's default character
- * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+ * encoding, use the {@code print(char)} or {@code println(char)}
* methods.
*
* @param b The byte to be written
@@ -483,13 +560,13 @@
}
/**
- * Writes <code>len</code> bytes from the specified byte array starting at
- * offset <code>off</code> to this stream. If automatic flushing is
- * enabled then the <code>flush</code> method will be invoked.
+ * Writes {@code len} bytes from the specified byte array starting at
+ * offset {@code off} to this stream. If automatic flushing is
+ * enabled then the {@code flush} method will be invoked.
*
* <p> Note that the bytes will be written as given; to write characters
* that will be translated according to the platform's default character
- * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+ * encoding, use the {@code print(char)} or {@code println(char)}
* methods.
*
* @param buf A byte array
@@ -588,38 +665,38 @@
/* Methods that do not terminate lines */
/**
- * Prints a boolean value. The string produced by <code>{@link
- * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+ * Prints a boolean value. The string produced by {@link
+ * java.lang.String#valueOf(boolean)} is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param b The <code>boolean</code> to be printed
+ * @param b The {@code boolean} to be printed
*/
public void print(boolean b) {
- write(b ? "true" : "false");
+ write(String.valueOf(b));
}
/**
* Prints a character. The character is translated into one or more bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param c The <code>char</code> to be printed
+ * @param c The {@code char} to be printed
*/
public void print(char c) {
write(String.valueOf(c));
}
/**
- * Prints an integer. The string produced by <code>{@link
- * java.lang.String#valueOf(int)}</code> is translated into bytes
+ * Prints an integer. The string produced by {@link
+ * java.lang.String#valueOf(int)} is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param i The <code>int</code> to be printed
+ * @param i The {@code int} to be printed
* @see java.lang.Integer#toString(int)
*/
public void print(int i) {
@@ -627,13 +704,13 @@
}
/**
- * Prints a long integer. The string produced by <code>{@link
- * java.lang.String#valueOf(long)}</code> is translated into bytes
+ * Prints a long integer. The string produced by {@link
+ * java.lang.String#valueOf(long)} is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param l The <code>long</code> to be printed
+ * @param l The {@code long} to be printed
* @see java.lang.Long#toString(long)
*/
public void print(long l) {
@@ -641,13 +718,13 @@
}
/**
- * Prints a floating-point number. The string produced by <code>{@link
- * java.lang.String#valueOf(float)}</code> is translated into bytes
+ * Prints a floating-point number. The string produced by {@link
+ * java.lang.String#valueOf(float)} is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param f The <code>float</code> to be printed
+ * @param f The {@code float} to be printed
* @see java.lang.Float#toString(float)
*/
public void print(float f) {
@@ -656,12 +733,12 @@
/**
* Prints a double-precision floating-point number. The string produced by
- * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+ * {@link java.lang.String#valueOf(double)} is translated into
* bytes according to the platform's default character encoding, and these
- * bytes are written in exactly the manner of the <code>{@link
- * #write(int)}</code> method.
+ * bytes are written in exactly the manner of the {@link
+ * #write(int)} method.
*
- * @param d The <code>double</code> to be printed
+ * @param d The {@code double} to be printed
* @see java.lang.Double#toString(double)
*/
public void print(double d) {
@@ -672,40 +749,37 @@
* Prints an array of characters. The characters are converted into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
* @param s The array of chars to be printed
*
- * @throws NullPointerException If <code>s</code> is <code>null</code>
+ * @throws NullPointerException If {@code s} is {@code null}
*/
public void print(char s[]) {
write(s);
}
/**
- * Prints a string. If the argument is <code>null</code> then the string
- * <code>"null"</code> is printed. Otherwise, the string's characters are
+ * Prints a string. If the argument is {@code null} then the string
+ * {@code "null"} is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param s The <code>String</code> to be printed
+ * @param s The {@code String} to be printed
*/
public void print(String s) {
- if (s == null) {
- s = "null";
- }
- write(s);
+ write(String.valueOf(s));
}
/**
- * Prints an object. The string produced by the <code>{@link
- * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+ * Prints an object. The string produced by the {@link
+ * java.lang.String#valueOf(Object)} method is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param obj The <code>Object</code> to be printed
+ * @param obj The {@code Object} to be printed
* @see java.lang.Object#toString()
*/
public void print(Object obj) {
@@ -718,8 +792,8 @@
/**
* Terminates the current line by writing the line separator string. The
* line separator string is defined by the system property
- * <code>line.separator</code>, and is not necessarily a single newline
- * character (<code>'\n'</code>).
+ * {@code line.separator}, and is not necessarily a single newline
+ * character ({@code '\n'}).
*/
public void println() {
newLine();
@@ -727,10 +801,10 @@
/**
* Prints a boolean and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(boolean)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(boolean)} and then
+ * {@link #println()}.
*
- * @param x The <code>boolean</code> to be printed
+ * @param x The {@code boolean} to be printed
*/
public void println(boolean x) {
synchronized (this) {
@@ -741,10 +815,10 @@
/**
* Prints a character and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(char)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(char)} and then
+ * {@link #println()}.
*
- * @param x The <code>char</code> to be printed.
+ * @param x The {@code char} to be printed.
*/
public void println(char x) {
synchronized (this) {
@@ -755,10 +829,10 @@
/**
* Prints an integer and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(int)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(int)} and then
+ * {@link #println()}.
*
- * @param x The <code>int</code> to be printed.
+ * @param x The {@code int} to be printed.
*/
public void println(int x) {
synchronized (this) {
@@ -769,10 +843,10 @@
/**
* Prints a long and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(long)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(long)} and then
+ * {@link #println()}.
*
- * @param x a The <code>long</code> to be printed.
+ * @param x a The {@code long} to be printed.
*/
public void println(long x) {
synchronized (this) {
@@ -783,10 +857,10 @@
/**
* Prints a float and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(float)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(float)} and then
+ * {@link #println()}.
*
- * @param x The <code>float</code> to be printed.
+ * @param x The {@code float} to be printed.
*/
public void println(float x) {
synchronized (this) {
@@ -797,10 +871,10 @@
/**
* Prints a double and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(double)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(double)} and then
+ * {@link #println()}.
*
- * @param x The <code>double</code> to be printed.
+ * @param x The {@code double} to be printed.
*/
public void println(double x) {
synchronized (this) {
@@ -811,8 +885,8 @@
/**
* Prints an array of characters and then terminate the line. This method
- * behaves as though it invokes <code>{@link #print(char[])}</code> and
- * then <code>{@link #println()}</code>.
+ * behaves as though it invokes {@link #print(char[])} and
+ * then {@link #println()}.
*
* @param x an array of chars to print.
*/
@@ -825,10 +899,10 @@
/**
* Prints a String and then terminate the line. This method behaves as
- * though it invokes <code>{@link #print(String)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(String)} and then
+ * {@link #println()}.
*
- * @param x The <code>String</code> to be printed.
+ * @param x The {@code String} to be printed.
*/
public void println(String x) {
synchronized (this) {
@@ -841,10 +915,10 @@
* Prints an Object and then terminate the line. This method calls
* at first String.valueOf(x) to get the printed object's string value,
* then behaves as
- * though it invokes <code>{@link #print(String)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(String)} and then
+ * {@link #println()}.
*
- * @param x The <code>Object</code> to be printed.
+ * @param x The {@code Object} to be printed.
*/
public void println(Object x) {
String s = String.valueOf(x);
@@ -859,11 +933,13 @@
* A convenience method to write a formatted string to this output stream
* using the specified format string and arguments.
*
- * <p> An invocation of this method of the form <tt>out.printf(format,
- * args)</tt> behaves in exactly the same way as the invocation
+ * <p> An invocation of this method of the form
+ * {@code out.printf(format, args)} behaves
+ * in exactly the same way as the invocation
*
- * <pre>
- * out.format(format, args) </pre>
+ * <pre>{@code
+ * out.format(format, args)
+ * }</pre>
*
* @param format
* A format string as described in <a
@@ -877,7 +953,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -890,7 +966,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This output stream
*
@@ -904,15 +980,17 @@
* A convenience method to write a formatted string to this output stream
* using the specified format string and arguments.
*
- * <p> An invocation of this method of the form <tt>out.printf(l, format,
- * args)</tt> behaves in exactly the same way as the invocation
+ * <p> An invocation of this method of the form
+ * {@code out.printf(l, format, args)} behaves
+ * in exactly the same way as the invocation
*
- * <pre>
- * out.format(l, format, args) </pre>
+ * <pre>{@code
+ * out.format(l, format, args)
+ * }</pre>
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -927,7 +1005,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -940,7 +1018,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This output stream
*
@@ -955,8 +1033,10 @@
* format string and arguments.
*
* <p> The locale always used is the one returned by {@link
- * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
- * previous invocations of other formatting methods on this object.
+ * java.util.Locale#getDefault(Locale.Category)} with
+ * {@link java.util.Locale.Category#FORMAT FORMAT} category specified,
+ * regardless of any previous invocations of other formatting methods on
+ * this object.
*
* @param format
* A format string as described in <a
@@ -970,7 +1050,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -983,7 +1063,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This output stream
*
@@ -994,9 +1074,11 @@
synchronized (this) {
ensureOpen();
if ((formatter == null)
- || (formatter.locale() != Locale.getDefault()))
+ || (formatter.locale() !=
+ Locale.getDefault(Locale.Category.FORMAT)))
formatter = new Formatter((Appendable) this);
- formatter.format(Locale.getDefault(), format, args);
+ formatter.format(Locale.getDefault(Locale.Category.FORMAT),
+ format, args);
}
} catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
@@ -1012,7 +1094,7 @@
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -1027,7 +1109,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -1040,7 +1122,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This output stream
*
@@ -1066,21 +1148,22 @@
/**
* Appends the specified character sequence to this output stream.
*
- * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * <p> An invocation of this method of the form {@code out.append(csq)}
* behaves in exactly the same way as the invocation
*
- * <pre>
- * out.print(csq.toString()) </pre>
+ * <pre>{@code
+ * out.print(csq.toString())
+ * }</pre>
*
- * <p> Depending on the specification of <tt>toString</tt> for the
- * character sequence <tt>csq</tt>, the entire sequence may not be
- * appended. For instance, invoking then <tt>toString</tt> method of a
+ * <p> Depending on the specification of {@code toString} for the
+ * character sequence {@code csq}, the entire sequence may not be
+ * appended. For instance, invoking then {@code toString} method of a
* character buffer will return a subsequence whose content depends upon
* the buffer's position and limit.
*
* @param csq
- * The character sequence to append. If <tt>csq</tt> is
- * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * The character sequence to append. If {@code csq} is
+ * {@code null}, then the four characters {@code "null"} are
* appended to this output stream.
*
* @return This output stream
@@ -1088,10 +1171,7 @@
* @since 1.5
*/
public PrintStream append(CharSequence csq) {
- if (csq == null)
- print("null");
- else
- print(csq.toString());
+ print(String.valueOf(csq));
return this;
}
@@ -1099,18 +1179,20 @@
* Appends a subsequence of the specified character sequence to this output
* stream.
*
- * <p> An invocation of this method of the form <tt>out.append(csq, start,
- * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+ * <p> An invocation of this method of the form
+ * {@code out.append(csq, start, end)} when
+ * {@code csq} is not {@code null}, behaves in
* exactly the same way as the invocation
*
- * <pre>
- * out.print(csq.subSequence(start, end).toString()) </pre>
+ * <pre>{@code
+ * out.print(csq.subSequence(start, end).toString())
+ * }</pre>
*
* @param csq
* The character sequence from which a subsequence will be
- * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
- * will be appended as if <tt>csq</tt> contained the four
- * characters <tt>"null"</tt>.
+ * appended. If {@code csq} is {@code null}, then characters
+ * will be appended as if {@code csq} contained the four
+ * characters {@code "null"}.
*
* @param start
* The index of the first character in the subsequence
@@ -1122,26 +1204,26 @@
* @return This output stream
*
* @throws IndexOutOfBoundsException
- * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
- * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
- * <tt>csq.length()</tt>
+ * If {@code start} or {@code end} are negative, {@code start}
+ * is greater than {@code end}, or {@code end} is greater than
+ * {@code csq.length()}
*
* @since 1.5
*/
public PrintStream append(CharSequence csq, int start, int end) {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
* Appends the specified character to this output stream.
*
- * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * <p> An invocation of this method of the form {@code out.append(c)}
* behaves in exactly the same way as the invocation
*
- * <pre>
- * out.print(c) </pre>
+ * <pre>{@code
+ * out.print(c)
+ * }</pre>
*
* @param c
* The 16-bit character to append
diff --git a/ojluni/src/main/java/java/io/PrintWriter.java b/ojluni/src/main/java/java/io/PrintWriter.java
index 9287a19..37d4200 100644
--- a/ojluni/src/main/java/java/io/PrintWriter.java
+++ b/ojluni/src/main/java/java/io/PrintWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, 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
@@ -34,13 +34,13 @@
/**
* Prints formatted representations of objects to a text-output stream. This
- * class implements all of the <tt>print</tt> methods found in {@link
+ * class implements all of the {@code print} methods found in {@link
* PrintStream}. It does not contain methods for writing raw bytes, for which
* a program should use unencoded byte streams.
*
* <p> Unlike the {@link PrintStream} class, if automatic flushing is enabled
- * it will be done only when one of the <tt>println</tt>, <tt>printf</tt>, or
- * <tt>format</tt> methods is invoked, rather than whenever a newline character
+ * it will be done only when one of the {@code println}, {@code printf}, or
+ * {@code format} methods is invoked, rather than whenever a newline character
* happens to be output. These methods use the platform's own notion of line
* separator rather than the newline character.
*
@@ -48,16 +48,21 @@
* constructors may. The client may inquire as to whether any errors have
* occurred by invoking {@link #checkError checkError()}.
*
+ * <p> This class always replaces malformed and unmappable character sequences with
+ * the charset's default replacement string.
+ * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
+ * control over the encoding process is required.
+ *
* @author Frank Yellin
* @author Mark Reinhold
- * @since JDK1.1
+ * @since 1.1
*/
public class PrintWriter extends Writer {
/**
* The underlying character-output stream of this
- * <code>PrintWriter</code>.
+ * {@code PrintWriter}.
*
* @since 1.2
*/
@@ -69,12 +74,6 @@
private PrintStream psOut = null;
/**
- * Line separator string. This is the value of the line.separator
- * property at the moment that the stream was created.
- */
- private final String lineSeparator;
-
- /**
* Returns a charset object for the given charset name.
* @throws NullPointerException is csn is null
* @throws UnsupportedEncodingException if the charset is not supported
@@ -113,8 +112,6 @@
super(out);
this.out = out;
this.autoFlush = autoFlush;
- lineSeparator = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("line.separator"));
}
/**
@@ -138,14 +135,33 @@
* default character encoding.
*
* @param out An output stream
- * @param autoFlush A boolean; if true, the <tt>println</tt>,
- * <tt>printf</tt>, or <tt>format</tt> methods will
+ * @param autoFlush A boolean; if true, the {@code println},
+ * {@code printf}, or {@code format} methods will
* flush the output buffer
*
* @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
*/
public PrintWriter(OutputStream out, boolean autoFlush) {
- this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
+ this(out, autoFlush, Charset.defaultCharset());
+ }
+
+ /**
+ * Creates a new PrintWriter from an existing OutputStream. This
+ * convenience constructor creates the necessary intermediate
+ * OutputStreamWriter, which will convert characters into bytes using the
+ * specified charset.
+ *
+ * @param out An output stream
+ * @param autoFlush A boolean; if true, the {@code println},
+ * {@code printf}, or {@code format} methods will
+ * flush the output buffer
+ * @param charset
+ * A {@linkplain java.nio.charset.Charset charset}
+ *
+ * @since 10
+ */
+ public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) {
+ this(new BufferedWriter(new OutputStreamWriter(out, charset)), autoFlush);
// save print stream for error propagation
if (out instanceof java.io.PrintStream) {
@@ -234,6 +250,36 @@
/**
* Creates a new PrintWriter, without automatic line flushing, with the
+ * specified file name and charset. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this writer.
+ * 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}
+ *
+ * @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
+ *
+ * @since 10
+ */
+ public PrintWriter(String fileName, Charset charset) throws IOException {
+ this(Objects.requireNonNull(charset, "charset"), new File(fileName));
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, with the
* specified file. This convenience constructor creates the necessary
* intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
* which will encode characters using the {@linkplain
@@ -303,6 +349,36 @@
this(toCharset(csn), file);
}
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, with the
+ * specified file and charset. This convenience constructor creates the
+ * necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param file
+ * The file to use as the destination of this writer. 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}
+ *
+ * @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
+ *
+ * @since 10
+ */
+ public PrintWriter(File file, Charset charset) throws IOException {
+ this(Objects.requireNonNull(charset, "charset"), file);
+ }
+
/** Checks to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
if (out == null)
@@ -348,7 +424,7 @@
/**
* Flushes the stream if it's not closed and checks its error state.
*
- * @return <code>true</code> if the print stream has encountered an error,
+ * @return {@code true} if the print stream has encountered an error,
* either on the underlying output stream or during a format
* conversion.
*/
@@ -369,7 +445,7 @@
* Indicates that an error has occurred.
*
* <p> This method will cause subsequent invocations of {@link
- * #checkError()} to return <tt>true</tt> until {@link
+ * #checkError()} to return {@code true} until {@link
* #clearError()} is invoked.
*/
protected void setError() {
@@ -380,7 +456,7 @@
* Clears the error state of this stream.
*
* <p> This method will cause subsequent invocations of {@link
- * #checkError()} to return <tt>false</tt> until another write
+ * #checkError()} to return {@code false} until another write
* operation fails and invokes {@link #setError()}.
*
* @since 1.6
@@ -418,6 +494,11 @@
* @param buf Array of characters
* @param off Offset from which to start writing characters
* @param len Number of characters to write
+ *
+ * @throws IndexOutOfBoundsException
+ * If the values of the {@code off} and {@code len} parameters
+ * cause the corresponding method of the underlying {@code Writer}
+ * to throw an {@code IndexOutOfBoundsException}
*/
public void write(char buf[], int off, int len) {
try {
@@ -448,6 +529,11 @@
* @param s A String
* @param off Offset from which to start writing characters
* @param len Number of characters to write
+ *
+ * @throws IndexOutOfBoundsException
+ * If the values of the {@code off} and {@code len} parameters
+ * cause the corresponding method of the underlying {@code Writer}
+ * to throw an {@code IndexOutOfBoundsException}
*/
public void write(String s, int off, int len) {
try {
@@ -477,7 +563,7 @@
try {
synchronized (lock) {
ensureOpen();
- out.write(lineSeparator);
+ out.write(System.lineSeparator());
if (autoFlush)
out.flush();
}
@@ -493,38 +579,38 @@
/* Methods that do not terminate lines */
/**
- * Prints a boolean value. The string produced by <code>{@link
- * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+ * Prints a boolean value. The string produced by {@link
+ * java.lang.String#valueOf(boolean)} is translated into bytes
* according to the platform's default character encoding, and these bytes
- * are written in exactly the manner of the <code>{@link
- * #write(int)}</code> method.
+ * are written in exactly the manner of the {@link
+ * #write(int)} method.
*
- * @param b The <code>boolean</code> to be printed
+ * @param b The {@code boolean} to be printed
*/
public void print(boolean b) {
- write(b ? "true" : "false");
+ write(String.valueOf(b));
}
/**
* Prints a character. The character is translated into one or more bytes
* according to the platform's default character encoding, and these bytes
- * are written in exactly the manner of the <code>{@link
- * #write(int)}</code> method.
+ * are written in exactly the manner of the {@link
+ * #write(int)} method.
*
- * @param c The <code>char</code> to be printed
+ * @param c The {@code char} to be printed
*/
public void print(char c) {
write(c);
}
/**
- * Prints an integer. The string produced by <code>{@link
- * java.lang.String#valueOf(int)}</code> is translated into bytes according
+ * Prints an integer. The string produced by {@link
+ * java.lang.String#valueOf(int)} is translated into bytes according
* to the platform's default character encoding, and these bytes are
- * written in exactly the manner of the <code>{@link #write(int)}</code>
+ * written in exactly the manner of the {@link #write(int)}
* method.
*
- * @param i The <code>int</code> to be printed
+ * @param i The {@code int} to be printed
* @see java.lang.Integer#toString(int)
*/
public void print(int i) {
@@ -532,13 +618,13 @@
}
/**
- * Prints a long integer. The string produced by <code>{@link
- * java.lang.String#valueOf(long)}</code> is translated into bytes
+ * Prints a long integer. The string produced by {@link
+ * java.lang.String#valueOf(long)} is translated into bytes
* according to the platform's default character encoding, and these bytes
- * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * are written in exactly the manner of the {@link #write(int)}
* method.
*
- * @param l The <code>long</code> to be printed
+ * @param l The {@code long} to be printed
* @see java.lang.Long#toString(long)
*/
public void print(long l) {
@@ -546,13 +632,13 @@
}
/**
- * Prints a floating-point number. The string produced by <code>{@link
- * java.lang.String#valueOf(float)}</code> is translated into bytes
+ * Prints a floating-point number. The string produced by {@link
+ * java.lang.String#valueOf(float)} is translated into bytes
* according to the platform's default character encoding, and these bytes
- * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * are written in exactly the manner of the {@link #write(int)}
* method.
*
- * @param f The <code>float</code> to be printed
+ * @param f The {@code float} to be printed
* @see java.lang.Float#toString(float)
*/
public void print(float f) {
@@ -561,12 +647,12 @@
/**
* Prints a double-precision floating-point number. The string produced by
- * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+ * {@link java.lang.String#valueOf(double)} is translated into
* bytes according to the platform's default character encoding, and these
- * bytes are written in exactly the manner of the <code>{@link
- * #write(int)}</code> method.
+ * bytes are written in exactly the manner of the {@link
+ * #write(int)} method.
*
- * @param d The <code>double</code> to be printed
+ * @param d The {@code double} to be printed
* @see java.lang.Double#toString(double)
*/
public void print(double d) {
@@ -576,41 +662,38 @@
/**
* Prints an array of characters. The characters are converted into bytes
* according to the platform's default character encoding, and these bytes
- * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * are written in exactly the manner of the {@link #write(int)}
* method.
*
* @param s The array of chars to be printed
*
- * @throws NullPointerException If <code>s</code> is <code>null</code>
+ * @throws NullPointerException If {@code s} is {@code null}
*/
public void print(char s[]) {
write(s);
}
/**
- * Prints a string. If the argument is <code>null</code> then the string
- * <code>"null"</code> is printed. Otherwise, the string's characters are
+ * Prints a string. If the argument is {@code null} then the string
+ * {@code "null"} is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
- * <code>{@link #write(int)}</code> method.
+ * {@link #write(int)} method.
*
- * @param s The <code>String</code> to be printed
+ * @param s The {@code String} to be printed
*/
public void print(String s) {
- if (s == null) {
- s = "null";
- }
- write(s);
+ write(String.valueOf(s));
}
/**
- * Prints an object. The string produced by the <code>{@link
- * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+ * Prints an object. The string produced by the {@link
+ * java.lang.String#valueOf(Object)} method is translated into bytes
* according to the platform's default character encoding, and these bytes
- * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * are written in exactly the manner of the {@link #write(int)}
* method.
*
- * @param obj The <code>Object</code> to be printed
+ * @param obj The {@code Object} to be printed
* @see java.lang.Object#toString()
*/
public void print(Object obj) {
@@ -622,8 +705,8 @@
/**
* Terminates the current line by writing the line separator string. The
* line separator string is defined by the system property
- * <code>line.separator</code>, and is not necessarily a single newline
- * character (<code>'\n'</code>).
+ * {@code line.separator}, and is not necessarily a single newline
+ * character ({@code '\n'}).
*/
public void println() {
newLine();
@@ -631,10 +714,10 @@
/**
* Prints a boolean value and then terminates the line. This method behaves
- * as though it invokes <code>{@link #print(boolean)}</code> and then
- * <code>{@link #println()}</code>.
+ * as though it invokes {@link #print(boolean)} and then
+ * {@link #println()}.
*
- * @param x the <code>boolean</code> value to be printed
+ * @param x the {@code boolean} value to be printed
*/
public void println(boolean x) {
synchronized (lock) {
@@ -645,10 +728,10 @@
/**
* Prints a character and then terminates the line. This method behaves as
- * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
- * #println()}</code>.
+ * though it invokes {@link #print(char)} and then {@link
+ * #println()}.
*
- * @param x the <code>char</code> value to be printed
+ * @param x the {@code char} value to be printed
*/
public void println(char x) {
synchronized (lock) {
@@ -659,10 +742,10 @@
/**
* Prints an integer and then terminates the line. This method behaves as
- * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
- * #println()}</code>.
+ * though it invokes {@link #print(int)} and then {@link
+ * #println()}.
*
- * @param x the <code>int</code> value to be printed
+ * @param x the {@code int} value to be printed
*/
public void println(int x) {
synchronized (lock) {
@@ -673,10 +756,10 @@
/**
* Prints a long integer and then terminates the line. This method behaves
- * as though it invokes <code>{@link #print(long)}</code> and then
- * <code>{@link #println()}</code>.
+ * as though it invokes {@link #print(long)} and then
+ * {@link #println()}.
*
- * @param x the <code>long</code> value to be printed
+ * @param x the {@code long} value to be printed
*/
public void println(long x) {
synchronized (lock) {
@@ -687,10 +770,10 @@
/**
* Prints a floating-point number and then terminates the line. This method
- * behaves as though it invokes <code>{@link #print(float)}</code> and then
- * <code>{@link #println()}</code>.
+ * behaves as though it invokes {@link #print(float)} and then
+ * {@link #println()}.
*
- * @param x the <code>float</code> value to be printed
+ * @param x the {@code float} value to be printed
*/
public void println(float x) {
synchronized (lock) {
@@ -701,10 +784,10 @@
/**
* Prints a double-precision floating-point number and then terminates the
- * line. This method behaves as though it invokes <code>{@link
- * #print(double)}</code> and then <code>{@link #println()}</code>.
+ * line. This method behaves as though it invokes {@link
+ * #print(double)} and then {@link #println()}.
*
- * @param x the <code>double</code> value to be printed
+ * @param x the {@code double} value to be printed
*/
public void println(double x) {
synchronized (lock) {
@@ -715,10 +798,10 @@
/**
* Prints an array of characters and then terminates the line. This method
- * behaves as though it invokes <code>{@link #print(char[])}</code> and then
- * <code>{@link #println()}</code>.
+ * behaves as though it invokes {@link #print(char[])} and then
+ * {@link #println()}.
*
- * @param x the array of <code>char</code> values to be printed
+ * @param x the array of {@code char} values to be printed
*/
public void println(char x[]) {
synchronized (lock) {
@@ -729,10 +812,10 @@
/**
* Prints a String and then terminates the line. This method behaves as
- * though it invokes <code>{@link #print(String)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(String)} and then
+ * {@link #println()}.
*
- * @param x the <code>String</code> value to be printed
+ * @param x the {@code String} value to be printed
*/
public void println(String x) {
synchronized (lock) {
@@ -745,10 +828,10 @@
* Prints an Object and then terminates the line. This method calls
* at first String.valueOf(x) to get the printed object's string value,
* then behaves as
- * though it invokes <code>{@link #print(String)}</code> and then
- * <code>{@link #println()}</code>.
+ * though it invokes {@link #print(String)} and then
+ * {@link #println()}.
*
- * @param x The <code>Object</code> to be printed.
+ * @param x The {@code Object} to be printed.
*/
public void println(Object x) {
String s = String.valueOf(x);
@@ -763,11 +846,13 @@
* the specified format string and arguments. If automatic flushing is
* enabled, calls to this method will flush the output buffer.
*
- * <p> An invocation of this method of the form <tt>out.printf(format,
- * args)</tt> behaves in exactly the same way as the invocation
+ * <p> An invocation of this method of the form
+ * {@code out.printf(format, args)}
+ * behaves in exactly the same way as the invocation
*
- * <pre>
- * out.format(format, args) </pre>
+ * <pre>{@code
+ * out.format(format, args)
+ * }</pre>
*
* @param format
* A format string as described in <a
@@ -781,7 +866,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -794,7 +879,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This writer
*
@@ -809,15 +894,17 @@
* the specified format string and arguments. If automatic flushing is
* enabled, calls to this method will flush the output buffer.
*
- * <p> An invocation of this method of the form <tt>out.printf(l, format,
- * args)</tt> behaves in exactly the same way as the invocation
+ * <p> An invocation of this method of the form
+ * {@code out.printf(l, format, args)}
+ * behaves in exactly the same way as the invocation
*
- * <pre>
- * out.format(l, format, args) </pre>
+ * <pre>{@code
+ * out.format(l, format, args)
+ * }</pre>
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -832,7 +919,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -845,7 +932,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This writer
*
@@ -876,7 +963,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -889,7 +976,7 @@
* Formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This writer
*
@@ -921,7 +1008,7 @@
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -936,7 +1023,7 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* @throws java.util.IllegalFormatException
@@ -949,7 +1036,7 @@
* formatter class specification.
*
* @throws NullPointerException
- * If the <tt>format</tt> is <tt>null</tt>
+ * If the {@code format} is {@code null}
*
* @return This writer
*
@@ -976,21 +1063,22 @@
/**
* Appends the specified character sequence to this writer.
*
- * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * <p> An invocation of this method of the form {@code out.append(csq)}
* behaves in exactly the same way as the invocation
*
- * <pre>
- * out.write(csq.toString()) </pre>
+ * <pre>{@code
+ * out.write(csq.toString())
+ * }</pre>
*
- * <p> Depending on the specification of <tt>toString</tt> for the
- * character sequence <tt>csq</tt>, the entire sequence may not be
- * appended. For instance, invoking the <tt>toString</tt> method of a
+ * <p> Depending on the specification of {@code toString} for the
+ * character sequence {@code csq}, the entire sequence may not be
+ * appended. For instance, invoking the {@code toString} method of a
* character buffer will return a subsequence whose content depends upon
* the buffer's position and limit.
*
* @param csq
- * The character sequence to append. If <tt>csq</tt> is
- * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * The character sequence to append. If {@code csq} is
+ * {@code null}, then the four characters {@code "null"} are
* appended to this writer.
*
* @return This writer
@@ -998,28 +1086,27 @@
* @since 1.5
*/
public PrintWriter append(CharSequence csq) {
- if (csq == null)
- write("null");
- else
- write(csq.toString());
+ write(String.valueOf(csq));
return this;
}
/**
* Appends a subsequence of the specified character sequence to this writer.
*
- * <p> An invocation of this method of the form <tt>out.append(csq, start,
- * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+ * <p> An invocation of this method of the form
+ * {@code out.append(csq, start, end)}
+ * when {@code csq} is not {@code null}, behaves in
* exactly the same way as the invocation
*
- * <pre>
- * out.write(csq.subSequence(start, end).toString()) </pre>
+ * <pre>{@code
+ * out.write(csq.subSequence(start, end).toString())
+ * }</pre>
*
* @param csq
* The character sequence from which a subsequence will be
- * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
- * will be appended as if <tt>csq</tt> contained the four
- * characters <tt>"null"</tt>.
+ * appended. If {@code csq} is {@code null}, then characters
+ * will be appended as if {@code csq} contained the four
+ * characters {@code "null"}.
*
* @param start
* The index of the first character in the subsequence
@@ -1031,26 +1118,26 @@
* @return This writer
*
* @throws IndexOutOfBoundsException
- * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
- * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
- * <tt>csq.length()</tt>
+ * If {@code start} or {@code end} are negative, {@code start}
+ * is greater than {@code end}, or {@code end} is greater than
+ * {@code csq.length()}
*
* @since 1.5
*/
public PrintWriter append(CharSequence csq, int start, int end) {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
* Appends the specified character to this writer.
*
- * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * <p> An invocation of this method of the form {@code out.append(c)}
* behaves in exactly the same way as the invocation
*
- * <pre>
- * out.write(c) </pre>
+ * <pre>{@code
+ * out.write(c)
+ * }</pre>
*
* @param c
* The 16-bit character to append
diff --git a/ojluni/src/main/java/java/io/Reader.java b/ojluni/src/main/java/java/io/Reader.java
index 1c9cca6..fd3a87f 100644
--- a/ojluni/src/main/java/java/io/Reader.java
+++ b/ojluni/src/main/java/java/io/Reader.java
@@ -26,6 +26,9 @@
package java.io;
+import java.nio.CharBuffer;
+import java.util.Objects;
+
/**
* Abstract class for reading character streams. The only methods that a
* subclass must implement are read(char[], int, int) and close(). Most
@@ -45,16 +48,102 @@
* @see Writer
*
* @author Mark Reinhold
- * @since JDK1.1
+ * @since 1.1
*/
public abstract class Reader implements Readable, Closeable {
+ private static final int TRANSFER_BUFFER_SIZE = 8192;
+
+ /**
+ * Returns a new {@code Reader} that reads no characters. The returned
+ * stream is initially open. The stream is closed by calling the
+ * {@code close()} method. Subsequent calls to {@code close()} have no
+ * effect.
+ *
+ * <p> While the stream is open, the {@code read()}, {@code read(char[])},
+ * {@code read(char[], int, int)}, {@code read(Charbuffer)}, {@code
+ * ready()}, {@code skip(long)}, and {@code transferTo()} methods all
+ * behave as if end of stream has been reached. After the stream has been
+ * closed, these methods all throw {@code IOException}.
+ *
+ * <p> The {@code markSupported()} method returns {@code false}. The
+ * {@code mark()} and {@code reset()} methods throw an {@code IOException}.
+ *
+ * <p> The {@link #lock object} used to synchronize operations on the
+ * returned {@code Reader} is not specified.
+ *
+ * @return a {@code Reader} which reads no characters
+ *
+ * @since 11
+ */
+ public static Reader nullReader() {
+ return new Reader() {
+ private volatile boolean closed;
+
+ private void ensureOpen() throws IOException {
+ if (closed) {
+ throw new IOException("Stream closed");
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ ensureOpen();
+ return -1;
+ }
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ Objects.checkFromIndexSize(off, len, cbuf.length);
+ ensureOpen();
+ if (len == 0) {
+ return 0;
+ }
+ return -1;
+ }
+
+ @Override
+ public int read(CharBuffer target) throws IOException {
+ Objects.requireNonNull(target);
+ ensureOpen();
+ if (target.hasRemaining()) {
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean ready() throws IOException {
+ ensureOpen();
+ return false;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ ensureOpen();
+ return 0L;
+ }
+
+ @Override
+ public long transferTo(Writer out) throws IOException {
+ Objects.requireNonNull(out);
+ ensureOpen();
+ return 0L;
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ }
+ };
+ }
+
/**
* The object used to synchronize operations on this stream. For
* efficiency, a character-stream object may use an object other than
* itself to protect critical sections. A subclass should therefore use
- * the object in this field rather than <tt>this</tt> or a synchronized
+ * the object in this field rather than {@code this} or a synchronized
* method.
*/
protected Object lock;
@@ -111,7 +200,7 @@
* should override this method.
*
* @return The character read, as an integer in the range 0 to 65535
- * (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has
+ * ({@code 0x00-0xffff}), or -1 if the end of the stream has
* been reached
*
* @exception IOException If an I/O error occurs
@@ -153,8 +242,11 @@
* stream has been reached
*
* @exception IOException If an I/O error occurs
+ * @exception IndexOutOfBoundsException
+ * If {@code off} is negative, or {@code len} is negative,
+ * or {@code len} is greater than {@code cbuf.length - off}
*/
- abstract public int read(char cbuf[], int off, int len) throws IOException;
+ public abstract int read(char cbuf[], int off, int len) throws IOException;
/** Maximum skip-buffer size */
private static final int maxSkipBufferSize = 8192;
@@ -257,6 +349,43 @@
*
* @exception IOException If an I/O error occurs
*/
- abstract public void close() throws IOException;
+ public abstract void close() throws IOException;
+
+ /**
+ * Reads all characters from this reader and writes the characters to the
+ * given writer in the order that they are read. On return, this reader
+ * will be at end of the stream. This method does not close either reader
+ * or writer.
+ * <p>
+ * This method may block indefinitely reading from the reader, or
+ * writing to the writer. The behavior for the case where the reader
+ * and/or writer is <i>asynchronously closed</i>, or the thread
+ * interrupted during the transfer, is highly reader and writer
+ * specific, and therefore not specified.
+ * <p>
+ * If an I/O error occurs reading from the reader or writing to the
+ * writer, then it may do so after some characters have been read or
+ * written. Consequently the reader may not be at end of the stream and
+ * one, or both, streams may be in an inconsistent state. It is strongly
+ * recommended that both streams be promptly closed if an I/O error occurs.
+ *
+ * @param out the writer, non-null
+ * @return the number of characters transferred
+ * @throws IOException if an I/O error occurs when reading or writing
+ * @throws NullPointerException if {@code out} is {@code null}
+ *
+ * @since 10
+ */
+ public long transferTo(Writer out) throws IOException {
+ Objects.requireNonNull(out, "out");
+ long transferred = 0;
+ char[] buffer = new char[TRANSFER_BUFFER_SIZE];
+ int nRead;
+ while ((nRead = read(buffer, 0, TRANSFER_BUFFER_SIZE)) >= 0) {
+ out.write(buffer, 0, nRead);
+ transferred += nRead;
+ }
+ return transferred;
+ }
}
diff --git a/ojluni/src/main/java/java/io/Writer.java b/ojluni/src/main/java/java/io/Writer.java
index 8747a13..f83a618 100644
--- a/ojluni/src/main/java/java/io/Writer.java
+++ b/ojluni/src/main/java/java/io/Writer.java
@@ -26,25 +26,26 @@
package java.io;
+import java.util.Objects;
+
/**
* Abstract class for writing to character streams. The only methods that a
* subclass must implement are write(char[], int, int), flush(), and close().
* Most subclasses, however, will override some of the methods defined here in
* order to provide higher efficiency, additional functionality, or both.
*
- * @see Writer
* @see BufferedWriter
* @see CharArrayWriter
* @see FilterWriter
* @see OutputStreamWriter
- * @see FileWriter
+ * @see FileWriter
* @see PipedWriter
* @see PrintWriter
* @see StringWriter
* @see Reader
*
* @author Mark Reinhold
- * @since JDK1.1
+ * @since 1.1
*/
public abstract class Writer implements Appendable, Closeable, Flushable {
@@ -60,10 +61,95 @@
private static final int WRITE_BUFFER_SIZE = 1024;
/**
+ * Returns a new {@code Writer} which discards all characters. The
+ * returned stream is initially open. The stream is closed by calling
+ * the {@code close()} method. Subsequent calls to {@code close()} have
+ * no effect.
+ *
+ * <p> While the stream is open, the {@code append(char)}, {@code
+ * append(CharSequence)}, {@code append(CharSequence, int, int)},
+ * {@code flush()}, {@code write(int)}, {@code write(char[])}, and
+ * {@code write(char[], int, int)} methods do nothing. After the stream
+ * has been closed, these methods all throw {@code IOException}.
+ *
+ * <p> The {@link #lock object} used to synchronize operations on the
+ * returned {@code Writer} is not specified.
+ *
+ * @return a {@code Writer} which discards all characters
+ *
+ * @since 11
+ */
+ public static Writer nullWriter() {
+ return new Writer() {
+ private volatile boolean closed;
+
+ private void ensureOpen() throws IOException {
+ if (closed) {
+ throw new IOException("Stream closed");
+ }
+ }
+
+ @Override
+ public Writer append(char c) throws IOException {
+ ensureOpen();
+ return this;
+ }
+
+ @Override
+ public Writer append(CharSequence csq) throws IOException {
+ ensureOpen();
+ return this;
+ }
+
+ @Override
+ public Writer append(CharSequence csq, int start, int end) throws IOException {
+ ensureOpen();
+ if (csq != null) {
+ Objects.checkFromToIndex(start, end, csq.length());
+ }
+ return this;
+ }
+
+ @Override
+ public void write(int c) throws IOException {
+ ensureOpen();
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ Objects.checkFromIndexSize(off, len, cbuf.length);
+ ensureOpen();
+ }
+
+ @Override
+ public void write(String str) throws IOException {
+ Objects.requireNonNull(str);
+ ensureOpen();
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException {
+ Objects.checkFromIndexSize(off, len, str.length());
+ ensureOpen();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ ensureOpen();
+ }
+
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ }
+ };
+ }
+
+ /**
* The object used to synchronize operations on this stream. For
* efficiency, a character-stream object may use an object other than
* itself to protect critical sections. A subclass should therefore use
- * the object in this field rather than <tt>this</tt> or a synchronized
+ * the object in this field rather than {@code this} or a synchronized
* method.
*/
protected Object lock;
@@ -139,10 +225,16 @@
* @param len
* Number of characters to write
*
+ * @throws IndexOutOfBoundsException
+ * Implementations should throw this exception
+ * if {@code off} is negative, or {@code len} is negative,
+ * or {@code off + len} is negative or greater than the length
+ * of the given array
+ *
* @throws IOException
* If an I/O error occurs
*/
- abstract public void write(char cbuf[], int off, int len) throws IOException;
+ public abstract void write(char cbuf[], int off, int len) throws IOException;
/**
* Writes a string.
@@ -160,6 +252,11 @@
/**
* Writes a portion of a string.
*
+ * @implSpec
+ * The implementation in this class throws an
+ * {@code IndexOutOfBoundsException} for the indicated conditions;
+ * overriding methods may choose to do otherwise.
+ *
* @param str
* A String
*
@@ -170,8 +267,9 @@
* Number of characters to write
*
* @throws IndexOutOfBoundsException
- * If <tt>off</tt> is negative, or <tt>len</tt> is negative,
- * or <tt>off+len</tt> is negative or greater than the length
+ * Implementations should throw this exception
+ * if {@code off} is negative, or {@code len} is negative,
+ * or {@code off + len} is negative or greater than the length
* of the given string
*
* @throws IOException
@@ -196,21 +294,21 @@
/**
* Appends the specified character sequence to this writer.
*
- * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * <p> An invocation of this method of the form {@code out.append(csq)}
* behaves in exactly the same way as the invocation
*
* <pre>
* out.write(csq.toString()) </pre>
*
- * <p> Depending on the specification of <tt>toString</tt> for the
- * character sequence <tt>csq</tt>, the entire sequence may not be
- * appended. For instance, invoking the <tt>toString</tt> method of a
+ * <p> Depending on the specification of {@code toString} for the
+ * character sequence {@code csq}, the entire sequence may not be
+ * appended. For instance, invoking the {@code toString} method of a
* character buffer will return a subsequence whose content depends upon
* the buffer's position and limit.
*
* @param csq
- * The character sequence to append. If <tt>csq</tt> is
- * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * The character sequence to append. If {@code csq} is
+ * {@code null}, then the four characters {@code "null"} are
* appended to this writer.
*
* @return This writer
@@ -221,29 +319,28 @@
* @since 1.5
*/
public Writer append(CharSequence csq) throws IOException {
- if (csq == null)
- write("null");
- else
- write(csq.toString());
+ write(String.valueOf(csq));
return this;
}
/**
* Appends a subsequence of the specified character sequence to this writer.
- * <tt>Appendable</tt>.
+ * {@code Appendable}.
*
- * <p> An invocation of this method of the form <tt>out.append(csq, start,
- * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
+ * <p> An invocation of this method of the form
+ * {@code out.append(csq, start, end)} when {@code csq}
+ * is not {@code null} behaves in exactly the
* same way as the invocation
*
- * <pre>
- * out.write(csq.subSequence(start, end).toString()) </pre>
+ * <pre>{@code
+ * out.write(csq.subSequence(start, end).toString())
+ * }</pre>
*
* @param csq
* The character sequence from which a subsequence will be
- * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
- * will be appended as if <tt>csq</tt> contained the four
- * characters <tt>"null"</tt>.
+ * appended. If {@code csq} is {@code null}, then characters
+ * will be appended as if {@code csq} contained the four
+ * characters {@code "null"}.
*
* @param start
* The index of the first character in the subsequence
@@ -255,9 +352,9 @@
* @return This writer
*
* @throws IndexOutOfBoundsException
- * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
- * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
- * <tt>csq.length()</tt>
+ * If {@code start} or {@code end} are negative, {@code start}
+ * is greater than {@code end}, or {@code end} is greater than
+ * {@code csq.length()}
*
* @throws IOException
* If an I/O error occurs
@@ -265,15 +362,14 @@
* @since 1.5
*/
public Writer append(CharSequence csq, int start, int end) throws IOException {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
* Appends the specified character to this writer.
*
- * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * <p> An invocation of this method of the form {@code out.append(c)}
* behaves in exactly the same way as the invocation
*
* <pre>
@@ -310,7 +406,7 @@
* @throws IOException
* If an I/O error occurs
*/
- abstract public void flush() throws IOException;
+ public abstract void flush() throws IOException;
/**
* Closes the stream, flushing it first. Once the stream has been closed,
@@ -320,6 +416,6 @@
* @throws IOException
* If an I/O error occurs
*/
- abstract public void close() throws IOException;
+ public abstract void close() throws IOException;
}
diff --git a/ojluni/src/main/java/java/lang/Boolean.java b/ojluni/src/main/java/java/lang/Boolean.java
index bfd704f..c600a06 100644
--- a/ojluni/src/main/java/java/lang/Boolean.java
+++ b/ojluni/src/main/java/java/lang/Boolean.java
@@ -25,6 +25,8 @@
package java.lang;
+import jdk.internal.HotSpotIntrinsicCandidate;
+
/**
* The Boolean class wraps a value of the primitive type
* {@code boolean} in an object. An object of type
@@ -136,8 +138,7 @@
*
* @return the primitive {@code boolean} value of this object.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public boolean booleanValue() {
return value;
}
@@ -156,8 +157,7 @@
* @return a {@code Boolean} instance representing {@code b}.
* @since 1.4
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index bc397f9..9988333 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -25,8 +25,7 @@
package java.lang;
-// Android-removed: Unsupported @HotSpotIntrinsicCandidate annotation.
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
import libcore.util.HexEncoding;
/**
@@ -102,8 +101,7 @@
* @return a {@code Byte} instance representing {@code b}.
* @since 1.5
*/
- // Android-removed: Unsupported @HotSpotIntrinsicCandidate annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
@@ -338,8 +336,7 @@
* Returns the value of this {@code Byte} as a
* {@code byte}.
*/
- // Android-removed: Unsupported @HotSpotIntrinsicCandidate annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public byte byteValue() {
return value;
}
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index 7925408..722968c 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -2396,6 +2396,8 @@
* assertion status that was (or will be) associated with the specified
* class when it was (or will be) initialized.
*
+ * Android-note: AssertionStatuses are unsupported. This method will always return false.
+ *
* @return the desired assertion status of the specified class.
* @see java.lang.ClassLoader#setClassAssertionStatus
* @see java.lang.ClassLoader#setPackageAssertionStatus
diff --git a/ojluni/src/main/java/java/lang/ClassLoader.java b/ojluni/src/main/java/java/lang/ClassLoader.java
index 0a8b08a..6c01ffa 100644
--- a/ojluni/src/main/java/java/lang/ClassLoader.java
+++ b/ojluni/src/main/java/java/lang/ClassLoader.java
@@ -1242,6 +1242,8 @@
* invoking {@link #setPackageAssertionStatus(String, boolean)} or {@link
* #setClassAssertionStatus(String, boolean)}.
*
+ * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+ *
* @param enabled
* <tt>true</tt> if classes loaded by this class loader will
* henceforth have assertions enabled by default, <tt>false</tt>
@@ -1274,6 +1276,8 @@
* assertion status, and may be overridden on a per-class basis by invoking
* {@link #setClassAssertionStatus(String, boolean)}. </p>
*
+ * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+ *
* @param packageName
* The name of the package whose package default assertion status
* is to be set. A <tt>null</tt> value indicates the unnamed
@@ -1304,6 +1308,8 @@
* <p> If the named class is not a top-level class, this invocation will
* have no effect on the actual assertion status of any class. </p>
*
+ * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+ *
* @param className
* The fully qualified class name of the top-level class whose
* assertion status is to be set.
@@ -1325,6 +1331,8 @@
* provided so that class loaders can be made to ignore any command line or
* persistent assertion status settings and "start with a clean slate."
*
+ * Android-note: AssertionStatuses are unsupported. This method is a no-op.
+ *
* @since 1.4
*/
public void clearAssertionStatus() {
diff --git a/ojluni/src/main/java/java/lang/Double.java b/ojluni/src/main/java/java/lang/Double.java
index 35e1f52..52bf32c 100644
--- a/ojluni/src/main/java/java/lang/Double.java
+++ b/ojluni/src/main/java/java/lang/Double.java
@@ -27,8 +27,7 @@
import jdk.internal.math.FloatingDecimal;
import jdk.internal.math.DoubleConsts;
-// Android-removed: HotSpotIntrinsicCandidate
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Double} class wraps a value of the primitive type
@@ -520,8 +519,7 @@
* @return a {@code Double} instance representing {@code d}.
* @since 1.5
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static Double valueOf(double d) {
return new Double(d);
}
@@ -731,8 +729,7 @@
*
* @return the {@code double} value represented by this object
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public double doubleValue() {
return value;
}
@@ -853,8 +850,7 @@
* @param value a {@code double} precision floating-point number.
* @return the bits that represent the floating-point number.
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long doubleToLongBits(double value) {
if (!isNaN(value)) {
return doubleToRawLongBits(value);
@@ -898,8 +894,7 @@
* @return the bits that represent the floating-point number.
* @since 1.3
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static native long doubleToRawLongBits(double value);
/**
@@ -963,8 +958,7 @@
* @return the {@code double} floating-point value with the same
* bit pattern.
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static native double longBitsToDouble(long bits);
/**
diff --git a/ojluni/src/main/java/java/lang/Float.java b/ojluni/src/main/java/java/lang/Float.java
index b24af88..52cb2c0 100644
--- a/ojluni/src/main/java/java/lang/Float.java
+++ b/ojluni/src/main/java/java/lang/Float.java
@@ -26,8 +26,7 @@
package java.lang;
import jdk.internal.math.FloatingDecimal;
-// Android-removed: HotSpotIntrinsicCandidate
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Float} class wraps a value of primitive type
@@ -433,8 +432,7 @@
* @return a {@code Float} instance representing {@code f}.
* @since 1.5
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static Float valueOf(float f) {
return new Float(f);
}
@@ -646,8 +644,7 @@
*
* @return the {@code float} value represented by this object
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public float floatValue() {
return value;
}
@@ -766,8 +763,7 @@
* @param value a floating-point number.
* @return the bits that represent the floating-point number.
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int floatToIntBits(float value) {
if (!isNaN(value)) {
return floatToRawIntBits(value);
@@ -810,8 +806,7 @@
* @return the bits that represent the floating-point number.
* @since 1.3
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static native int floatToRawIntBits(float value);
/**
@@ -873,8 +868,7 @@
* @return the {@code float} floating-point value with the same bit
* pattern.
*/
- // Android-removed: HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static native float intBitsToFloat(int bits);
/**
diff --git a/ojluni/src/main/java/java/lang/Math.java b/ojluni/src/main/java/java/lang/Math.java
index ea38fab..e446371c 100644
--- a/ojluni/src/main/java/java/lang/Math.java
+++ b/ojluni/src/main/java/java/lang/Math.java
@@ -30,9 +30,9 @@
import java.math.BigDecimal;
import java.util.Random;
-
import jdk.internal.math.FloatConsts;
import jdk.internal.math.DoubleConsts;
+import jdk.internal.HotSpotIntrinsicCandidate;
// Android-note: Document that the results from Math are based on libm's behavior.
// For performance, Android implements many of the methods in this class in terms of the underlying
@@ -964,8 +964,7 @@
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int addExact(int x, int y) {
int r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
@@ -985,8 +984,7 @@
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long addExact(long x, long y) {
long r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
@@ -1006,8 +1004,7 @@
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int subtractExact(int x, int y) {
int r = x - y;
// HD 2-12 Overflow iff the arguments have different signs and
@@ -1028,8 +1025,7 @@
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long subtractExact(long x, long y) {
long r = x - y;
// HD 2-12 Overflow iff the arguments have different signs and
@@ -1050,8 +1046,7 @@
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int multiplyExact(int x, int y) {
long r = (long)x * (long)y;
if ((int)r != r) {
@@ -1084,8 +1079,7 @@
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long multiplyExact(long x, long y) {
long r = x * y;
long ax = Math.abs(x);
@@ -1111,8 +1105,7 @@
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int incrementExact(int a) {
if (a == Integer.MAX_VALUE) {
throw new ArithmeticException("integer overflow");
@@ -1130,8 +1123,7 @@
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long incrementExact(long a) {
if (a == Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
@@ -1149,8 +1141,7 @@
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int decrementExact(int a) {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow");
@@ -1168,8 +1159,7 @@
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long decrementExact(long a) {
if (a == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
@@ -1187,8 +1177,7 @@
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int negateExact(int a) {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow");
@@ -1206,8 +1195,7 @@
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long negateExact(long a) {
if (a == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
@@ -1253,8 +1241,7 @@
* @return the result
* @since 9
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static long multiplyHigh(long x, long y) {
if (x < 0 || y < 0) {
// Use technique from section 8-2 of Henry S. Warren, Jr.,
@@ -1574,8 +1561,7 @@
* @param a the argument whose absolute value is to be determined
* @return the absolute value of the argument.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static double abs(double a) {
// Android-changed: Implementation modified to exactly match ART intrinsics behavior.
// Note, as a "quality of implementation", rather than pure "spec compliance",
@@ -1596,8 +1582,7 @@
* @param b another argument.
* @return the larger of {@code a} and {@code b}.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
@@ -1682,8 +1667,7 @@
* @param b another argument.
* @return the smaller of {@code a} and {@code b}.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int min(int a, int b) {
return (a <= b) ? a : b;
}
@@ -1804,8 +1788,7 @@
*
* @since 9
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static double fma(double a, double b, double c) {
/*
* Infinity and NaN arithmetic is not quite the same with two
@@ -1922,8 +1905,7 @@
*
* @since 9
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static float fma(float a, float b, float c) {
/*
* Since the double format has more than twice the precision
diff --git a/ojluni/src/main/java/java/lang/Short.java b/ojluni/src/main/java/java/lang/Short.java
index dd6e2e2..57b291f 100644
--- a/ojluni/src/main/java/java/lang/Short.java
+++ b/ojluni/src/main/java/java/lang/Short.java
@@ -25,8 +25,7 @@
package java.lang;
-// Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
-// import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Short} class wraps a value of primitive type {@code
@@ -230,8 +229,7 @@
* @return a {@code Short} instance representing {@code s}.
* @since 1.5
*/
- // Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
@@ -351,8 +349,7 @@
* Returns the value of this {@code Short} as a
* {@code short}.
*/
- // Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public short shortValue() {
return value;
}
@@ -522,8 +519,7 @@
* the bytes in the specified {@code short} value.
* @since 1.5
*/
- // Android-removed: unsupported @HotSpotIntrinsicCandidate annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static short reverseBytes(short i) {
return (short) (((i & 0xFF00) >> 8) | (i << 8));
}
diff --git a/ojluni/src/main/java/java/lang/StrictMath.java b/ojluni/src/main/java/java/lang/StrictMath.java
index 8ebf741..2c9f497 100644
--- a/ojluni/src/main/java/java/lang/StrictMath.java
+++ b/ojluni/src/main/java/java/lang/StrictMath.java
@@ -27,6 +27,7 @@
import java.util.Random;
import jdk.internal.math.DoubleConsts;
+import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The class {@code StrictMath} contains methods for performing basic
@@ -287,8 +288,7 @@
* @param a a value.
* @return the positive square root of {@code a}.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static native double sqrt(double a);
/**
@@ -1136,8 +1136,7 @@
* @param b another argument.
* @return the larger of {@code a} and {@code b}.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int max(int a, int b) {
return Math.max(a, b);
}
@@ -1202,8 +1201,7 @@
* @param b another argument.
* @return the smaller of {@code a} and {@code b}.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static int min(int a, int b) {
return Math.min(a, b);
}
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index 2ba7b1f..75583cc 100644
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -112,22 +112,23 @@
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
-
// BEGIN Android-changed: The character data is managed by the runtime.
- // We only keep track of the length here and compression here. This has several consequences
- // throughout this class:
- // - References to value[i] are replaced by charAt(i).
- // - References to value.length are replaced by calls to length().
- // - Sometimes the result of length() is assigned to a local variable to avoid repeated calls.
- // - We skip several attempts at optimization where the values field was assigned to a local
- // variable to avoid the getfield opcode.
- // These changes are not all marked individually.
- //
- // private final char value[];
- //
- // If STRING_COMPRESSION_ENABLED, count stores the length shifted one bit to the left with the
- // lowest bit used to indicate whether or not the bytes are compressed (see GetFlaggedCount in
- // the native code).
+ /*
+ We only keep track of the length here and compression here. This has several consequences
+ throughout this class:
+ - References to value[i] are replaced by charAt(i).
+ - References to value.length are replaced by calls to length().
+ - Sometimes the result of length() is assigned to a local variable to avoid repeated calls.
+ - We skip several attempts at optimization where the values field was assigned to a local
+ variable to avoid the getfield opcode.
+ These changes are not all marked individually.
+
+ If STRING_COMPRESSION_ENABLED, count stores the length shifted one bit to the left with the
+ lowest bit used to indicate whether or not the bytes are compressed (see GetFlaggedCount in
+ the native code).
+ /** The value is used for character storage. *
+ private final char value[];
+ */
private final int count;
// END Android-changed: The character data is managed by the runtime.
@@ -156,7 +157,8 @@
* unnecessary since Strings are immutable.
*/
public String() {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this.value = "".value;
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -171,7 +173,9 @@
* A {@code String}
*/
public String(String original) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this.value = original.value;
+ // this.hash = original.hash;
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -185,7 +189,8 @@
* The initial value of the string
*/
public String(char value[]) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this.value = Arrays.copyOf(value, value.length);
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -211,8 +216,28 @@
* characters outside the bounds of the {@code value} array
*/
public String(char value[], int offset, int count) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ if (offset < 0) {
+ throw new StringIndexOutOfBoundsException(offset);
+ }
+ if (count <= 0) {
+ if (count < 0) {
+ throw new StringIndexOutOfBoundsException(count);
+ }
+ if (offset <= value.length) {
+ this.value = "".value;
+ return;
+ }
+ }
+ // Note: offset or count might be near -1>>>1.
+ if (offset > value.length - count) {
+ throw new StringIndexOutOfBoundsException(offset + count);
+ }
+ this.value = Arrays.copyOfRange(value, offset, offset+count);
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
/**
@@ -244,8 +269,53 @@
* @since 1.5
*/
public String(int[] codePoints, int offset, int count) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ if (offset < 0) {
+ throw new StringIndexOutOfBoundsException(offset);
+ }
+ if (count <= 0) {
+ if (count < 0) {
+ throw new StringIndexOutOfBoundsException(count);
+ }
+ if (offset <= codePoints.length) {
+ this.value = "".value;
+ return;
+ }
+ }
+ // Note: offset or count might be near -1>>>1.
+ if (offset > codePoints.length - count) {
+ throw new StringIndexOutOfBoundsException(offset + count);
+ }
+
+ final int end = offset + count;
+
+ // Pass 1: Compute precise size of char[]
+ int n = count;
+ for (int i = offset; i < end; i++) {
+ int c = codePoints[i];
+ if (Character.isBmpCodePoint(c))
+ continue;
+ else if (Character.isValidCodePoint(c))
+ n++;
+ else throw new IllegalArgumentException(Integer.toString(c));
+ }
+
+ // Pass 2: Allocate and fill in char[]
+ final char[] v = new char[n];
+
+ for (int i = offset, j = 0; i < end; i++, j++) {
+ int c = codePoints[i];
+ if (Character.isBmpCodePoint(c))
+ v[j] = (char)c;
+ else
+ Character.toSurrogates(c, v, j++);
+ }
+
+ this.value = v;
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
/**
@@ -289,8 +359,25 @@
*/
@Deprecated
public String(byte ascii[], int hibyte, int offset, int count) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ checkBounds(ascii, offset, count);
+ char value[] = new char[count];
+
+ if (hibyte == 0) {
+ for (int i = count; i-- > 0;) {
+ value[i] = (char)(ascii[i + offset] & 0xff);
+ }
+ } else {
+ hibyte <<= 8;
+ for (int i = count; i-- > 0;) {
+ value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
+ }
+ }
+ this.value = value;
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
/**
@@ -325,10 +412,29 @@
*/
@Deprecated
public String(byte ascii[], int hibyte) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ this(ascii, hibyte, 0, ascii.length);
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
+ // BEGIN Android-removed: checkBounds(byte[] bytes, int offset, int length) utility method.
+ /* Common private utility method used to bounds check the byte array
+ * and requested offset & length values used by the String(byte[],..)
+ * constructors.
+ *
+ private static void checkBounds(byte[] bytes, int offset, int length) {
+ if (length < 0)
+ throw new StringIndexOutOfBoundsException(length);
+ if (offset < 0)
+ throw new StringIndexOutOfBoundsException(offset);
+ if (offset > bytes.length - length)
+ throw new StringIndexOutOfBoundsException(offset + length);
+ }
+ // END Android-removed: checkBounds(byte[] bytes, int offset, int length) utility method.
+
/**
* Constructs a new {@code String} by decoding the specified subarray of
* bytes using the specified charset. The length of the new {@code String}
@@ -364,8 +470,15 @@
*/
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ if (charsetName == null)
+ throw new NullPointerException("charsetName");
+ checkBounds(bytes, offset, length);
+ this.value = StringCoding.decode(charsetName, bytes, offset, length);
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
/**
@@ -399,8 +512,15 @@
* @since 1.6
*/
public String(byte bytes[], int offset, int length, Charset charset) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ if (charset == null)
+ throw new NullPointerException("charset");
+ checkBounds(bytes, offset, length);
+ this.value = StringCoding.decode(charset, bytes, offset, length);
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
/**
@@ -428,7 +548,8 @@
*/
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this(bytes, 0, bytes.length, charsetName);
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -453,7 +574,8 @@
* @since 1.6
*/
public String(byte bytes[], Charset charset) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this(bytes, 0, bytes.length, charset);
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -484,7 +606,9 @@
* @since JDK1.1
*/
public String(byte bytes[], int offset, int length) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // checkBounds(bytes, offset, length);
+ // this.value = StringCoding.decode(bytes, offset, length);
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -505,7 +629,8 @@
* @since JDK1.1
*/
public String(byte bytes[]) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this(bytes, 0, bytes.length);
throw new UnsupportedOperationException("Use StringFactory instead.");
}
@@ -519,8 +644,14 @@
* A {@code StringBuffer}
*/
public String(StringBuffer buffer) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // BEGIN Android-changed: Implemented as compiler and runtime intrinsics.
+ /*
+ synchronized(buffer) {
+ this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
+ }
+ */
throw new UnsupportedOperationException("Use StringFactory instead.");
+ // END Android-changed: Implemented as compiler and runtime intrinsics.
}
/**
@@ -539,11 +670,25 @@
* @since 1.5
*/
public String(StringBuilder builder) {
- // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+ // Android-changed: Implemented as compiler and runtime intrinsics.
+ // this.value = Arrays.copyOf(builder.getValue(), builder.length());
throw new UnsupportedOperationException("Use StringFactory instead.");
}
- // Android-removed: Unused package-private constructor String(char[] value, boolean share).
+ // BEGIN Android-removed: Unused package-private constructor String(char[] value, boolean share).
+ /*
+ /*
+ * Package private constructor which shares value array for speed.
+ * this constructor is always expected to be called with share==true.
+ * a separate constructor is needed because we already have a public
+ * String(char[]) constructor that makes a copy of the given char[].
+ *
+ String(char[] value, boolean share) {
+ // assert share : "unshared not supported";
+ this.value = value;
+ }
+ */
+ // END Android-removed: Unused package-private constructor String(char[] value, boolean share).
// BEGIN Android-added: Constructor for internal use.
// Not implemented in java as all calls are intercepted by the runtime.
@@ -568,7 +713,9 @@
*/
public int length() {
// BEGIN Android-changed: Get length from count field rather than value array (see above).
- // return value.length;
+ /*
+ return value.length;
+ */
final boolean STRING_COMPRESSION_ENABLED = true;
if (STRING_COMPRESSION_ENABLED) {
// For the compression purposes (save the characters as 8-bit if all characters
@@ -614,6 +761,14 @@
* string.
*/
// BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+ /*
+ public char charAt(int index) {
+ if ((index < 0) || (index >= value.length)) {
+ throw new StringIndexOutOfBoundsException(index);
+ }
+ return value[index];
+ }
+ */
@FastNative
public native char charAt(int index);
// END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -742,6 +897,7 @@
*/
void getChars(char dst[], int dstBegin) {
// Android-changed: Replace arraycopy with native call since chars are managed by runtime.
+ // System.arraycopy(value, 0, dst, dstBegin, value.length);
getCharsNoCheck(0, length(), dst, dstBegin);
}
@@ -777,6 +933,18 @@
*/
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
// BEGIN Android-changed: Implement in terms of length() and native getCharsNoCheck method.
+ /*
+ if (srcBegin < 0) {
+ throw new StringIndexOutOfBoundsException(srcBegin);
+ }
+ if (srcEnd > value.length) {
+ throw new StringIndexOutOfBoundsException(srcEnd);
+ }
+ if (srcBegin > srcEnd) {
+ throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
+ }
+ System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
+ */
if (dst == null) {
throw new NullPointerException("dst == null");
}
@@ -934,8 +1102,10 @@
*/
public byte[] getBytes(Charset charset) {
// BEGIN Android-changed: Skip StringCoding optimization that needs access to java chars.
- // if (charset == null) throw new NullPointerException();
- // return StringCoding.encode(charset, value, 0, value.length);
+ /*
+ if (charset == null) throw new NullPointerException();
+ return StringCoding.encode(charset, value, 0, value.length);
+ */
if (charset == null) {
throw new NullPointerException("charset == null");
}
@@ -1168,6 +1338,26 @@
* lexicographically greater than the string argument.
*/
// BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+ /*
+ public int compareTo(String anotherString) {
+ int len1 = value.length;
+ int len2 = anotherString.value.length;
+ int lim = Math.min(len1, len2);
+ char v1[] = value;
+ char v2[] = anotherString.value;
+
+ int k = 0;
+ while (k < lim) {
+ char c1 = v1[k];
+ char c2 = v2[k];
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ k++;
+ }
+ return len1 - len2;
+ }
+ */
@FastNative
public native int compareTo(String anotherString);
// END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -1708,6 +1898,8 @@
*/
public int indexOf(String str, int fromIndex) {
// Android-changed: Delegate to the static indexOf method below.
+ // return indexOf(value, 0, value.length,
+ // str.value, 0, str.value.length, fromIndex);
return indexOf(this, str, fromIndex);
}
@@ -1865,6 +2057,8 @@
*/
public int lastIndexOf(String str, int fromIndex) {
// Android-changed: Change parameters to static lastIndexOf to match new signature below.
+ // return lastIndexOf(value, 0, value.length,
+ // str.value, 0, str.value.length, fromIndex);
return lastIndexOf(this, str, fromIndex);
}
@@ -2027,6 +2221,7 @@
throw new StringIndexOutOfBoundsException(this, beginIndex);
}
// Android-changed: Use native fastSubstring instead of String constructor.
+ // return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
return (beginIndex == 0) ? this : fastSubstring(beginIndex, subLen);
}
@@ -2066,6 +2261,7 @@
// Android-changed: Use native fastSubstring instead of String constructor.
return ((beginIndex == 0) && (endIndex == length())) ? this
+ // : new String(value, beginIndex, subLen);
: fastSubstring(beginIndex, subLen);
}
@@ -2128,6 +2324,18 @@
* characters followed by the string argument's characters.
*/
// BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+ /*
+ public String concat(String str) {
+ int otherLen = str.length();
+ if (otherLen == 0) {
+ return this;
+ }
+ int len = value.length;
+ char buf[] = Arrays.copyOf(value, len + otherLen);
+ str.getChars(buf, len);
+ return new String(buf, true);
+ }
+ */
@FastNative
public native String concat(String str);
// END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -2164,6 +2372,29 @@
public String replace(char oldChar, char newChar) {
// BEGIN Android-changed: Replace with implementation using native doReplace method.
if (oldChar != newChar) {
+ /*
+ int len = value.length;
+ int i = -1;
+ char[] val = value; /* avoid getfield opcode *
+
+ while (++i < len) {
+ if (val[i] == oldChar) {
+ break;
+ }
+ }
+ if (i < len) {
+ char buf[] = new char[len];
+ for (int j = 0; j < i; j++) {
+ buf[j] = val[j];
+ }
+ while (i < len) {
+ char c = val[i];
+ buf[i] = (c == oldChar) ? newChar : c;
+ i++;
+ }
+ return new String(buf, true);
+ }
+ */
final int len = length();
for (int i = 0; i < len; ++i) {
if (charAt(i) == oldChar) {
@@ -2328,6 +2559,10 @@
*/
public String replace(CharSequence target, CharSequence replacement) {
// BEGIN Android-changed: Replace regex-based implementation with a bespoke one.
+ /*
+ return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
+ this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
+ */
if (target == null) {
throw new NullPointerException("target == null");
}
@@ -2475,6 +2710,58 @@
public String[] split(String regex, int limit) {
// BEGIN Android-changed: Replace custom fast-path with use of new Pattern.fastSplit method.
// Try fast splitting without allocating Pattern object
+ /*
+ /* fastpath if the regex is a
+ (1)one-char String and this character is not one of the
+ RegEx's meta characters ".$|()[{^?*+\\", or
+ (2)two-char String and the first char is the backslash and
+ the second is not the ascii digit or ascii letter.
+ *
+ char ch = 0;
+ if (((regex.value.length == 1 &&
+ ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
+ (regex.length() == 2 &&
+ regex.charAt(0) == '\\' &&
+ (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
+ ((ch-'a')|('z'-ch)) < 0 &&
+ ((ch-'A')|('Z'-ch)) < 0)) &&
+ (ch < Character.MIN_HIGH_SURROGATE ||
+ ch > Character.MAX_LOW_SURROGATE))
+ {
+ int off = 0;
+ int next = 0;
+ boolean limited = limit > 0;
+ ArrayList<String> list = new ArrayList<>();
+ while ((next = indexOf(ch, off)) != -1) {
+ if (!limited || list.size() < limit - 1) {
+ list.add(substring(off, next));
+ off = next + 1;
+ } else { // last one
+ //assert (list.size() == limit - 1);
+ list.add(substring(off, value.length));
+ off = value.length;
+ break;
+ }
+ }
+ // If no match was found, return this
+ if (off == 0)
+ return new String[]{this};
+
+ // Add remaining segment
+ if (!limited || list.size() < limit)
+ list.add(substring(off, value.length));
+
+ // Construct result
+ int resultSize = list.size();
+ if (limit == 0) {
+ while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
+ resultSize--;
+ }
+ }
+ String[] result = new String[resultSize];
+ return list.subList(0, resultSize).toArray(result);
+ }
+ */
String[] fast = Pattern.fastSplit(regex, this, limit);
if (fast != null) {
return fast;
@@ -2662,8 +2949,97 @@
* @since 1.1
*/
public String toLowerCase(Locale locale) {
- // Android-changed: Replace custom code with call to new CaseMapper class.
+ // BEGIN Android-changed: Replace custom code with call to new CaseMapper class.
+ /*
+ if (locale == null) {
+ throw new NullPointerException();
+ }
+
+ int firstUpper;
+ final int len = value.length;
+
+ /* Now check if there are any characters that need to be changed. *
+ scan: {
+ for (firstUpper = 0 ; firstUpper < len; ) {
+ char c = value[firstUpper];
+ if ((c >= Character.MIN_HIGH_SURROGATE)
+ && (c <= Character.MAX_HIGH_SURROGATE)) {
+ int supplChar = codePointAt(firstUpper);
+ if (supplChar != Character.toLowerCase(supplChar)) {
+ break scan;
+ }
+ firstUpper += Character.charCount(supplChar);
+ } else {
+ if (c != Character.toLowerCase(c)) {
+ break scan;
+ }
+ firstUpper++;
+ }
+ }
+ return this;
+ }
+
+ char[] result = new char[len];
+ int resultOffset = 0; /* result may grow, so i+resultOffset
+ * is the write location in result *
+
+ /* Just copy the first few lowerCase characters. *
+ System.arraycopy(value, 0, result, 0, firstUpper);
+
+ String lang = locale.getLanguage();
+ boolean localeDependent =
+ (lang == "tr" || lang == "az" || lang == "lt");
+ char[] lowerCharArray;
+ int lowerChar;
+ int srcChar;
+ int srcCount;
+ for (int i = firstUpper; i < len; i += srcCount) {
+ srcChar = (int)value[i];
+ if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
+ && (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
+ srcChar = codePointAt(i);
+ srcCount = Character.charCount(srcChar);
+ } else {
+ srcCount = 1;
+ }
+ if (localeDependent ||
+ srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
+ srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
+ lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
+ } else {
+ lowerChar = Character.toLowerCase(srcChar);
+ }
+ if ((lowerChar == Character.ERROR)
+ || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
+ if (lowerChar == Character.ERROR) {
+ lowerCharArray =
+ ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
+ } else if (srcCount == 2) {
+ resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
+ continue;
+ } else {
+ lowerCharArray = Character.toChars(lowerChar);
+ }
+
+ /* Grow result if needed *
+ int mapLen = lowerCharArray.length;
+ if (mapLen > srcCount) {
+ char[] result2 = new char[result.length + mapLen - srcCount];
+ System.arraycopy(result, 0, result2, 0, i + resultOffset);
+ result = result2;
+ }
+ for (int x = 0; x < mapLen; ++x) {
+ result[i + resultOffset + x] = lowerCharArray[x];
+ }
+ resultOffset += (mapLen - srcCount);
+ } else {
+ result[i + resultOffset] = (char)lowerChar;
+ }
+ }
+ return new String(result, 0, len + resultOffset);
+ */
return CaseMapper.toLowerCase(locale, this);
+ // END Android-changed: Replace custom code with call to new CaseMapper class.
}
/**
@@ -2738,8 +3114,100 @@
* @since 1.1
*/
public String toUpperCase(Locale locale) {
- // Android-changed: Replace custom code with call to new CaseMapper class.
+ // BEGIN Android-changed: Replace custom code with call to new CaseMapper class.
+ /*
+ if (locale == null) {
+ throw new NullPointerException();
+ }
+
+ int firstLower;
+ final int len = value.length;
+
+ /* Now check if there are any characters that need to be changed. *
+ scan: {
+ for (firstLower = 0 ; firstLower < len; ) {
+ int c = (int)value[firstLower];
+ int srcCount;
+ if ((c >= Character.MIN_HIGH_SURROGATE)
+ && (c <= Character.MAX_HIGH_SURROGATE)) {
+ c = codePointAt(firstLower);
+ srcCount = Character.charCount(c);
+ } else {
+ srcCount = 1;
+ }
+ int upperCaseChar = Character.toUpperCaseEx(c);
+ if ((upperCaseChar == Character.ERROR)
+ || (c != upperCaseChar)) {
+ break scan;
+ }
+ firstLower += srcCount;
+ }
+ return this;
+ }
+
+ /* result may grow, so i+resultOffset is the write location in result *
+ int resultOffset = 0;
+ char[] result = new char[len]; /* may grow *
+
+ /* Just copy the first few upperCase characters. *
+ System.arraycopy(value, 0, result, 0, firstLower);
+
+ String lang = locale.getLanguage();
+ boolean localeDependent =
+ (lang == "tr" || lang == "az" || lang == "lt");
+ char[] upperCharArray;
+ int upperChar;
+ int srcChar;
+ int srcCount;
+ for (int i = firstLower; i < len; i += srcCount) {
+ srcChar = (int)value[i];
+ if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
+ (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
+ srcChar = codePointAt(i);
+ srcCount = Character.charCount(srcChar);
+ } else {
+ srcCount = 1;
+ }
+ if (localeDependent) {
+ upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
+ } else {
+ upperChar = Character.toUpperCaseEx(srcChar);
+ }
+ if ((upperChar == Character.ERROR)
+ || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
+ if (upperChar == Character.ERROR) {
+ if (localeDependent) {
+ upperCharArray =
+ ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
+ } else {
+ upperCharArray = Character.toUpperCaseCharArray(srcChar);
+ }
+ } else if (srcCount == 2) {
+ resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
+ continue;
+ } else {
+ upperCharArray = Character.toChars(upperChar);
+ }
+
+ /* Grow result if needed *
+ int mapLen = upperCharArray.length;
+ if (mapLen > srcCount) {
+ char[] result2 = new char[result.length + mapLen - srcCount];
+ System.arraycopy(result, 0, result2, 0, i + resultOffset);
+ result = result2;
+ }
+ for (int x = 0; x < mapLen; ++x) {
+ result[i + resultOffset + x] = upperCharArray[x];
+ }
+ resultOffset += (mapLen - srcCount);
+ } else {
+ result[i + resultOffset] = (char)upperChar;
+ }
+ }
+ return new String(result, 0, len + resultOffset);
+ */
return CaseMapper.toUpperCase(locale, this, length());
+ // END Android-changed: Replace custom code with call to new CaseMapper class.
}
/**
@@ -2826,6 +3294,14 @@
* the character sequence represented by this string.
*/
// BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+ /*
+ public char[] toCharArray() {
+ // Cannot use Arrays.copyOf because of class initialization order issues
+ char result[] = new char[value.length];
+ System.arraycopy(value, 0, result, 0, value.length);
+ return result;
+ }
+ */
@FastNative
public native char[] toCharArray();
// END Android-changed: Replace with implementation in runtime to access chars (see above).
@@ -3097,8 +3573,7 @@
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
- // BEGIN Android-changed: Annotate native method as @FastNative.
+ // Android-added: Annotate native method as @FastNative.
@FastNative
- // END Android-changed: Annotate native method as @FastNative.
public native String intern();
}
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index e22c3aa..3263383 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -42,6 +42,7 @@
import sun.reflect.CallerSensitive;
import dalvik.system.VMStack;
import libcore.util.EmptyArray;
+import jdk.internal.HotSpotIntrinsicCandidate;
/**
@@ -310,8 +311,7 @@
*
* @return the currently executing thread.
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public static native Thread currentThread();
@@ -489,8 +489,7 @@
*
* @since 9
*/
- // Android-removed: @HotSpotIntrinsicCandidate
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static void onSpinWait() {}
/**
@@ -2412,19 +2411,17 @@
// concurrent code, and we can not risk accidental false sharing.
// Hence, the fields are isolated with @Contended.
- // BEGIN Android-changed: @jdk.internal.vm.annotation.Contended is not supported on Android.
/** The current seed for a ThreadLocalRandom */
- // @jdk.internal.vm.annotation.Contended("tlr")
+ @jdk.internal.vm.annotation.Contended("tlr")
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
- // @jdk.internal.vm.annotation.Contended("tlr")
+ @jdk.internal.vm.annotation.Contended("tlr")
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
- // @jdk.internal.vm.annotation.Contended("tlr")
+ @jdk.internal.vm.annotation.Contended("tlr")
int threadLocalRandomSecondarySeed;
- // END Android-changed: @jdk.internal.vm.annotation.Contended is not supported on Android.
/* Some private helper methods */
private native void setPriority0(int newPriority);
diff --git a/ojluni/src/main/java/java/lang/invoke/VarHandle.java b/ojluni/src/main/java/java/lang/invoke/VarHandle.java
index 40473f0..0febea9 100644
--- a/ojluni/src/main/java/java/lang/invoke/VarHandle.java
+++ b/ojluni/src/main/java/java/lang/invoke/VarHandle.java
@@ -26,6 +26,7 @@
package java.lang.invoke;
import dalvik.system.VMRuntime;
+import jdk.internal.HotSpotIntrinsicCandidate;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
@@ -490,8 +491,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object get(Object... args);
/**
@@ -517,8 +517,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
void set(Object... args);
@@ -550,8 +549,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getVolatile(Object... args);
/**
@@ -581,8 +579,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
void setVolatile(Object... args);
@@ -612,8 +609,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getOpaque(Object... args);
/**
@@ -640,8 +636,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
void setOpaque(Object... args);
@@ -678,8 +673,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAcquire(Object... args);
/**
@@ -710,8 +704,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
void setRelease(Object... args);
@@ -747,8 +740,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
boolean compareAndSet(Object... args);
/**
@@ -783,8 +775,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object compareAndExchange(Object... args);
/**
@@ -819,8 +810,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object compareAndExchangeAcquire(Object... args);
/**
@@ -855,8 +845,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object compareAndExchangeRelease(Object... args);
// Weak (spurious failures allowed)
@@ -895,8 +884,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
boolean weakCompareAndSetPlain(Object... args);
/**
@@ -933,8 +921,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
boolean weakCompareAndSet(Object... args);
/**
@@ -972,8 +959,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
boolean weakCompareAndSetAcquire(Object... args);
/**
@@ -1011,8 +997,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
boolean weakCompareAndSetRelease(Object... args);
/**
@@ -1045,8 +1030,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndSet(Object... args);
/**
@@ -1079,8 +1063,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndSetAcquire(Object... args);
/**
@@ -1113,8 +1096,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndSetRelease(Object... args);
// Primitive adders
@@ -1150,8 +1132,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndAdd(Object... args);
/**
@@ -1184,8 +1165,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndAddAcquire(Object... args);
/**
@@ -1218,8 +1198,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndAddRelease(Object... args);
@@ -1260,8 +1239,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseOr(Object... args);
/**
@@ -1298,8 +1276,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseOrAcquire(Object... args);
/**
@@ -1336,8 +1313,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseOrRelease(Object... args);
/**
@@ -1374,8 +1350,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseAnd(Object... args);
/**
@@ -1412,8 +1387,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseAndAcquire(Object... args);
/**
@@ -1450,8 +1424,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseAndRelease(Object... args);
/**
@@ -1488,8 +1461,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseXor(Object... args);
/**
@@ -1526,8 +1498,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseXorAcquire(Object... args);
/**
@@ -1564,8 +1535,7 @@
*/
public final native
@MethodHandle.PolymorphicSignature
- // Android-removed: unsupported annotation.
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
Object getAndBitwiseXorRelease(Object... args);
diff --git a/ojluni/src/main/java/java/math/BigDecimal.java b/ojluni/src/main/java/java/math/BigDecimal.java
index 9e012a6..25d8f2b 100644
--- a/ojluni/src/main/java/java/math/BigDecimal.java
+++ b/ojluni/src/main/java/java/math/BigDecimal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2019, 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
@@ -40,7 +40,7 @@
* decimal point. If negative, the unscaled value of the number is
* multiplied by ten to the power of the negation of the scale. The
* value of the number represented by the {@code BigDecimal} is
- * therefore <tt>(unscaledValue × 10<sup>-scale</sup>)</tt>.
+ * therefore <code>(unscaledValue × 10<sup>-scale</sup>)</code>.
*
* <p>The {@code BigDecimal} class provides operations for
* arithmetic, scale manipulation, rounding, comparison, hashing, and
@@ -55,7 +55,7 @@
* object to the operation. In either case, eight <em>rounding
* modes</em> are provided for the control of rounding. Using the
* integer fields in this class (such as {@link #ROUND_HALF_UP}) to
- * represent rounding mode is largely obsolete; the enumeration values
+ * represent rounding mode is deprecated; the enumeration values
* of the {@code RoundingMode} {@code enum}, (such as {@link
* RoundingMode#HALF_UP}) should be used instead.
*
@@ -93,7 +93,7 @@
* <p>In general the rounding modes and precision setting determine
* how operations return results with a limited number of digits when
* the exact result has more digits (perhaps infinitely many in the
- * case of division) than the number of digits returned.
+ * case of division and square root) than the number of digits returned.
*
* First, the
* total number of digits to return is specified by the
@@ -120,14 +120,19 @@
* preferred scale for representing a result. The preferred
* scale for each operation is listed in the table below.
*
- * <table border>
- * <caption><b>Preferred Scales for Results of Arithmetic Operations
- * </b></caption>
- * <tr><th>Operation</th><th>Preferred Scale of Result</th></tr>
- * <tr><td>Add</td><td>max(addend.scale(), augend.scale())</td>
- * <tr><td>Subtract</td><td>max(minuend.scale(), subtrahend.scale())</td>
- * <tr><td>Multiply</td><td>multiplier.scale() + multiplicand.scale()</td>
- * <tr><td>Divide</td><td>dividend.scale() - divisor.scale()</td>
+ * <table class="striped" style="text-align:left">
+ * <caption>Preferred Scales for Results of Arithmetic Operations
+ * </caption>
+ * <thead>
+ * <tr><th scope="col">Operation</th><th scope="col">Preferred Scale of Result</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><th scope="row">Add</th><td>max(addend.scale(), augend.scale())</td>
+ * <tr><th scope="row">Subtract</th><td>max(minuend.scale(), subtrahend.scale())</td>
+ * <tr><th scope="row">Multiply</th><td>multiplier.scale() + multiplicand.scale()</td>
+ * <tr><th scope="row">Divide</th><td>dividend.scale() - divisor.scale()</td>
+ * <tr><th scope="row">Square root</th><td>radicand.scale()/2</td>
+ * </tbody>
* </table>
*
* These scales are the ones used by the methods which return exact
@@ -195,18 +200,19 @@
* {@code BigDecimal} value; for example [19, 2] is the
* {@code BigDecimal} numerically equal to 0.19 having a scale of 2.
*
- * <p>Note: care should be exercised if {@code BigDecimal} objects
- * are used as keys in a {@link java.util.SortedMap SortedMap} or
- * elements in a {@link java.util.SortedSet SortedSet} since
- * {@code BigDecimal}'s <i>natural ordering</i> is <i>inconsistent
- * with equals</i>. See {@link Comparable}, {@link
- * java.util.SortedMap} or {@link java.util.SortedSet} for more
- * information.
*
* <p>All methods and constructors for this class throw
* {@code NullPointerException} when passed a {@code null} object
* reference for any input parameter.
*
+ * @apiNote Care should be exercised if {@code BigDecimal} objects
+ * are used as keys in a {@link java.util.SortedMap SortedMap} or
+ * elements in a {@link java.util.SortedSet SortedSet} since
+ * {@code BigDecimal}'s <i>natural ordering</i> is <em>inconsistent
+ * with equals</em>. See {@link Comparable}, {@link
+ * java.util.SortedMap} or {@link java.util.SortedSet} for more
+ * information.
+ *
* @see BigInteger
* @see MathContext
* @see RoundingMode
@@ -216,6 +222,7 @@
* @author Mike Cowlishaw
* @author Joseph D. Darcy
* @author Sergey V. Kuksenko
+ * @since 1.1
*/
public class BigDecimal extends Number implements Comparable<BigDecimal> {
/**
@@ -283,10 +290,10 @@
};
// Cache of common small BigDecimal values.
- private static final BigDecimal zeroThroughTen[] = {
+ private static final BigDecimal ZERO_THROUGH_TEN[] = {
new BigDecimal(BigInteger.ZERO, 0, 0, 1),
new BigDecimal(BigInteger.ONE, 1, 0, 1),
- new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
+ new BigDecimal(BigInteger.TWO, 2, 0, 1),
new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
@@ -299,7 +306,7 @@
// Cache of zero scaled by 0 - 15
private static final BigDecimal[] ZERO_SCALED_BY = {
- zeroThroughTen[0],
+ ZERO_THROUGH_TEN[0],
new BigDecimal(BigInteger.ZERO, 0, 1, 1),
new BigDecimal(BigInteger.ZERO, 0, 2, 1),
new BigDecimal(BigInteger.ZERO, 0, 3, 1),
@@ -328,7 +335,7 @@
* @since 1.5
*/
public static final BigDecimal ZERO =
- zeroThroughTen[0];
+ ZERO_THROUGH_TEN[0];
/**
* The value 1, with a scale of 0.
@@ -336,7 +343,7 @@
* @since 1.5
*/
public static final BigDecimal ONE =
- zeroThroughTen[1];
+ ZERO_THROUGH_TEN[1];
/**
* The value 10, with a scale of 0.
@@ -344,7 +351,17 @@
* @since 1.5
*/
public static final BigDecimal TEN =
- zeroThroughTen[10];
+ ZERO_THROUGH_TEN[10];
+
+ /**
+ * The value 0.1, with a scale of 1.
+ */
+ private static final BigDecimal ONE_TENTH = valueOf(1L, 1);
+
+ /**
+ * The value 0.5, with a scale of 1.
+ */
+ private static final BigDecimal ONE_HALF = valueOf(5L, 1);
// Constructors
@@ -366,10 +383,10 @@
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor, while allowing a sub-array to be specified.
*
- * <p>Note that if the sequence of characters is already available
+ * @implNote If the sequence of characters is already available
* within a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
- * {@code BigDecimal(String)} constructor .
+ * {@code BigDecimal(String)} constructor.
*
* @param in {@code char} array that is the source of characters.
* @param offset first character in the array to inspect.
@@ -390,14 +407,14 @@
* constructor, while allowing a sub-array to be specified and
* with rounding according to the context settings.
*
- * <p>Note that if the sequence of characters is already available
+ * @implNote If the sequence of characters is already available
* within a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
- * {@code BigDecimal(String)} constructor .
+ * {@code BigDecimal(String)} constructor.
*
* @param in {@code char} array that is the source of characters.
* @param offset first character in the array to inspect.
- * @param len number of characters to consider..
+ * @param len number of characters to consider.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
@@ -407,12 +424,9 @@
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
- // protect against huge length, negative values, and integer overflow
- if ((in.length | len | offset) < 0 || len > in.length - offset) {
- throw new NumberFormatException
- ("Bad offset or len arguments for char[] input.");
- }
-
+ // protect against huge length.
+ if (offset + len > in.length || offset < 0)
+ throw new NumberFormatException("Bad offset or len arguments for char[] input.");
// This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate
@@ -469,7 +483,8 @@
} else if (c == '.') { // have dot
// have dot
if (dot) // two dots
- throw new NumberFormatException();
+ throw new NumberFormatException("Character array"
+ + " contains more than one decimal point.");
dot = true;
} else if (Character.isDigit(c)) { // slow path
int digit = Character.digit(c, 10);
@@ -491,14 +506,16 @@
exp = parseExp(in, offset, len);
// Next test is required for backwards compatibility
if ((int) exp != exp) // overflow
- throw new NumberFormatException();
+ throw new NumberFormatException("Exponent overflow.");
break; // [saves a test]
} else {
- throw new NumberFormatException();
+ throw new NumberFormatException("Character " + c
+ + " is neither a decimal digit number, decimal point, nor"
+ + " \"e\" notation exponential mark.");
}
}
if (prec == 0) // no digits found
- throw new NumberFormatException();
+ throw new NumberFormatException("No digits found.");
// Adjust scale if exp is not zero.
if (exp != 0) { // had significant exponent
scl = adjustScale(scl, exp);
@@ -544,22 +561,24 @@
if (c == '.') {
// have dot
if (dot) // two dots
- throw new NumberFormatException();
+ throw new NumberFormatException("Character array"
+ + " contains more than one decimal point.");
dot = true;
continue;
}
// exponent expected
if ((c != 'e') && (c != 'E'))
- throw new NumberFormatException();
+ throw new NumberFormatException("Character array"
+ + " is missing \"e\" notation exponential mark.");
exp = parseExp(in, offset, len);
// Next test is required for backwards compatibility
if ((int) exp != exp) // overflow
- throw new NumberFormatException();
+ throw new NumberFormatException("Exponent overflow.");
break; // [saves a test]
}
// here when no characters left
if (prec == 0) // no digits found
- throw new NumberFormatException();
+ throw new NumberFormatException("No digits found.");
// Adjust scale if exp is not zero.
if (exp != 0) { // had significant exponent
scl = adjustScale(scl, exp);
@@ -595,10 +614,10 @@
}
}
}
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new NumberFormatException();
- } catch (NegativeArraySizeException e) {
- throw new NumberFormatException();
+ } catch (ArrayIndexOutOfBoundsException | NegativeArraySizeException e) {
+ NumberFormatException nfe = new NumberFormatException();
+ nfe.initCause(e);
+ throw nfe;
}
this.scale = scl;
this.precision = prec;
@@ -630,7 +649,7 @@
len--;
}
if (len <= 0) // no exponent digits
- throw new NumberFormatException();
+ throw new NumberFormatException("No exponent digits.");
// skip leading zeros in the exponent
while (len > 10 && (c=='0' || (Character.digit(c, 10) == 0))) {
offset++;
@@ -638,7 +657,7 @@
len--;
}
if (len > 10) // too many nonzero exponent digits
- throw new NumberFormatException();
+ throw new NumberFormatException("Too many nonzero exponent digits.");
// c now holds first digit of exponent
for (;; len--) {
int v;
@@ -647,7 +666,7 @@
} else {
v = Character.digit(c, 10);
if (v < 0) // not a digit
- throw new NumberFormatException();
+ throw new NumberFormatException("Not a digit.");
}
exp = exp * 10 + v;
if (len == 1)
@@ -666,10 +685,10 @@
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor.
*
- * <p>Note that if the sequence of characters is already available
+ * @implNote If the sequence of characters is already available
* as a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
- * {@code BigDecimal(String)} constructor .
+ * {@code BigDecimal(String)} constructor.
*
* @param in {@code char} array that is the source of characters.
* @throws NumberFormatException if {@code in} is not a valid
@@ -687,10 +706,10 @@
* constructor and with rounding according to the context
* settings.
*
- * <p>Note that if the sequence of characters is already available
+ * @implNote If the sequence of characters is already available
* as a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
- * {@code BigDecimal(String)} constructor .
+ * {@code BigDecimal(String)} constructor.
*
* @param in {@code char} array that is the source of characters.
* @param mc the context to use.
@@ -707,8 +726,8 @@
/**
* Translates the string representation of a {@code BigDecimal}
* into a {@code BigDecimal}. The string representation consists
- * of an optional sign, {@code '+'} (<tt> '\u002B'</tt>) or
- * {@code '-'} (<tt>'\u002D'</tt>), followed by a sequence of
+ * of an optional sign, {@code '+'} (<code> '\u002B'</code>) or
+ * {@code '-'} (<code>'\u002D'</code>), followed by a sequence of
* zero or more decimal digits ("the integer"), optionally
* followed by a fraction, optionally followed by an exponent.
*
@@ -719,7 +738,7 @@
* <i>significand</i>.
*
* <p>The exponent consists of the character {@code 'e'}
- * (<tt>'\u0065'</tt>) or {@code 'E'} (<tt>'\u0045'</tt>)
+ * (<code>'\u0065'</code>) or {@code 'E'} (<code>'\u0045'</code>)
* followed by one or more decimal digits. The value of the
* exponent must lie between -{@link Integer#MAX_VALUE} ({@link
* Integer#MIN_VALUE}+1) and {@link Integer#MAX_VALUE}, inclusive.
@@ -792,7 +811,7 @@
* "-0" [0,0]
* </pre>
*
- * <p>Note: For values other than {@code float} and
+ * @apiNote For values other than {@code float} and
* {@code double} NaN and ±Infinity, this constructor is
* compatible with the values returned by {@link Float#toString}
* and {@link Double#toString}. This is generally the preferred
@@ -832,7 +851,7 @@
* is the exact decimal representation of the {@code double}'s
* binary floating-point value. The scale of the returned
* {@code BigDecimal} is the smallest value such that
- * <tt>(10<sup>scale</sup> × val)</tt> is an integer.
+ * <code>(10<sup>scale</sup> × val)</code> is an integer.
* <p>
* <b>Notes:</b>
* <ol>
@@ -846,16 +865,16 @@
* This is because 0.1 cannot be represented exactly as a
* {@code double} (or, for that matter, as a binary fraction of
* any finite length). Thus, the value that is being passed
- * <i>in</i> to the constructor is not exactly equal to 0.1,
+ * <em>in</em> to the constructor is not exactly equal to 0.1,
* appearances notwithstanding.
*
* <li>
* The {@code String} constructor, on the other hand, is
* perfectly predictable: writing {@code new BigDecimal("0.1")}
- * creates a {@code BigDecimal} which is <i>exactly</i> equal to
+ * creates a {@code BigDecimal} which is <em>exactly</em> equal to
* 0.1, as one would expect. Therefore, it is generally
* recommended that the {@linkplain #BigDecimal(String)
- * <tt>String</tt> constructor} be used in preference to this one.
+ * String constructor} be used in preference to this one.
*
* <li>
* When a {@code double} must be used as a source for a
@@ -879,7 +898,7 @@
* Translates a {@code double} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is the smallest value such that
- * <tt>(10<sup>scale</sup> × val)</tt> is an integer.
+ * <code>(10<sup>scale</sup> × val)</code> is an integer.
*
* <p>The results of this constructor can be somewhat unpredictable
* and its use is generally not recommended; see the notes under
@@ -923,20 +942,20 @@
significand >>= 1;
exponent++;
}
- int scale = 0;
+ int scl = 0;
// Calculate intVal and scale
- BigInteger intVal;
+ BigInteger rb;
long compactVal = sign * significand;
if (exponent == 0) {
- intVal = (compactVal == INFLATED) ? INFLATED_BIGINT : null;
+ rb = (compactVal == INFLATED) ? INFLATED_BIGINT : null;
} else {
if (exponent < 0) {
- intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);
- scale = -exponent;
+ rb = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);
+ scl = -exponent;
} else { // (exponent > 0)
- intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal);
+ rb = BigInteger.TWO.pow(exponent).multiply(compactVal);
}
- compactVal = compactValFor(intVal);
+ compactVal = compactValFor(rb);
}
int prec = 0;
int mcp = mc.precision;
@@ -944,16 +963,16 @@
int mode = mc.roundingMode.oldMode;
int drop;
if (compactVal == INFLATED) {
- prec = bigDigitLength(intVal);
+ prec = bigDigitLength(rb);
drop = prec - mcp;
while (drop > 0) {
- scale = checkScaleNonZero((long) scale - drop);
- intVal = divideAndRoundByTenPow(intVal, drop, mode);
- compactVal = compactValFor(intVal);
+ scl = checkScaleNonZero((long) scl - drop);
+ rb = divideAndRoundByTenPow(rb, drop, mode);
+ compactVal = compactValFor(rb);
if (compactVal != INFLATED) {
break;
}
- prec = bigDigitLength(intVal);
+ prec = bigDigitLength(rb);
drop = prec - mcp;
}
}
@@ -961,17 +980,17 @@
prec = longDigitLength(compactVal);
drop = prec - mcp;
while (drop > 0) {
- scale = checkScaleNonZero((long) scale - drop);
+ scl = checkScaleNonZero((long) scl - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
}
- intVal = null;
+ rb = null;
}
}
- this.intVal = intVal;
+ this.intVal = rb;
this.intCompact = compactVal;
- this.scale = scale;
+ this.scale = scl;
this.precision = prec;
}
@@ -1008,7 +1027,7 @@
* Translates a {@code BigInteger} unscaled value and an
* {@code int} scale into a {@code BigDecimal}. The value of
* the {@code BigDecimal} is
- * <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
+ * <code>(unscaledVal × 10<sup>-scale</sup>)</code>.
*
* @param unscaledVal unscaled value of the {@code BigDecimal}.
* @param scale scale of the {@code BigDecimal}.
@@ -1024,8 +1043,8 @@
* Translates a {@code BigInteger} unscaled value and an
* {@code int} scale into a {@code BigDecimal}, with rounding
* according to the context settings. The value of the
- * {@code BigDecimal} is <tt>(unscaledVal ×
- * 10<sup>-scale</sup>)</tt>, rounded according to the
+ * {@code BigDecimal} is <code>(unscaledVal ×
+ * 10<sup>-scale</sup>)</code>, rounded according to the
* {@code precision} and rounding mode settings.
*
* @param unscaledVal unscaled value of the {@code BigDecimal}.
@@ -1101,13 +1120,13 @@
public BigDecimal(int val, MathContext mc) {
int mcp = mc.precision;
long compactVal = val;
- int scale = 0;
+ int scl = 0;
int prec = 0;
if (mcp > 0) { // do rounding
prec = longDigitLength(compactVal);
int drop = prec - mcp; // drop can't be more than 18
while (drop > 0) {
- scale = checkScaleNonZero((long) scale - drop);
+ scl = checkScaleNonZero((long) scl - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
@@ -1115,7 +1134,7 @@
}
this.intVal = null;
this.intCompact = compactVal;
- this.scale = scale;
+ this.scale = scl;
this.precision = prec;
}
@@ -1147,20 +1166,20 @@
int mcp = mc.precision;
int mode = mc.roundingMode.oldMode;
int prec = 0;
- int scale = 0;
- BigInteger intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
+ int scl = 0;
+ BigInteger rb = (val == INFLATED) ? INFLATED_BIGINT : null;
if (mcp > 0) { // do rounding
if (val == INFLATED) {
prec = 19;
int drop = prec - mcp;
while (drop > 0) {
- scale = checkScaleNonZero((long) scale - drop);
- intVal = divideAndRoundByTenPow(intVal, drop, mode);
- val = compactValFor(intVal);
+ scl = checkScaleNonZero((long) scl - drop);
+ rb = divideAndRoundByTenPow(rb, drop, mode);
+ val = compactValFor(rb);
if (val != INFLATED) {
break;
}
- prec = bigDigitLength(intVal);
+ prec = bigDigitLength(rb);
drop = prec - mcp;
}
}
@@ -1168,17 +1187,17 @@
prec = longDigitLength(val);
int drop = prec - mcp;
while (drop > 0) {
- scale = checkScaleNonZero((long) scale - drop);
+ scl = checkScaleNonZero((long) scl - drop);
val = divideAndRound(val, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(val);
drop = prec - mcp;
}
- intVal = null;
+ rb = null;
}
}
- this.intVal = intVal;
+ this.intVal = rb;
this.intCompact = val;
- this.scale = scale;
+ this.scale = scl;
this.precision = prec;
}
@@ -1186,15 +1205,16 @@
/**
* Translates a {@code long} unscaled value and an
- * {@code int} scale into a {@code BigDecimal}. This
- * {@literal "static factory method"} is provided in preference to
- * a ({@code long}, {@code int}) constructor because it
- * allows for reuse of frequently used {@code BigDecimal} values..
+ * {@code int} scale into a {@code BigDecimal}.
+ *
+ * @apiNote This static factory method is provided in preference
+ * to a ({@code long}, {@code int}) constructor because it allows
+ * for reuse of frequently used {@code BigDecimal} values.
*
* @param unscaledVal unscaled value of the {@code BigDecimal}.
* @param scale scale of the {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is
- * <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
+ * <code>(unscaledVal × 10<sup>-scale</sup>)</code>.
*/
public static BigDecimal valueOf(long unscaledVal, int scale) {
if (scale == 0)
@@ -1209,25 +1229,26 @@
/**
* Translates a {@code long} value into a {@code BigDecimal}
- * with a scale of zero. This {@literal "static factory method"}
- * is provided in preference to a ({@code long}) constructor
- * because it allows for reuse of frequently used
- * {@code BigDecimal} values.
+ * with a scale of zero.
+ *
+ * @apiNote This static factory method is provided in preference
+ * to a ({@code long}) constructor because it allows for reuse of
+ * frequently used {@code BigDecimal} values.
*
* @param val value of the {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is {@code val}.
*/
public static BigDecimal valueOf(long val) {
- if (val >= 0 && val < zeroThroughTen.length)
- return zeroThroughTen[(int)val];
+ if (val >= 0 && val < ZERO_THROUGH_TEN.length)
+ return ZERO_THROUGH_TEN[(int)val];
else if (val != INFLATED)
return new BigDecimal(null, val, 0, 0);
return new BigDecimal(INFLATED_BIGINT, val, 0, 0);
}
static BigDecimal valueOf(long unscaledVal, int scale, int prec) {
- if (scale == 0 && unscaledVal >= 0 && unscaledVal < zeroThroughTen.length) {
- return zeroThroughTen[(int) unscaledVal];
+ if (scale == 0 && unscaledVal >= 0 && unscaledVal < ZERO_THROUGH_TEN.length) {
+ return ZERO_THROUGH_TEN[(int) unscaledVal];
} else if (unscaledVal == 0) {
return zeroValueOf(scale);
}
@@ -1239,8 +1260,8 @@
long val = compactValFor(intVal);
if (val == 0) {
return zeroValueOf(scale);
- } else if (scale == 0 && val >= 0 && val < zeroThroughTen.length) {
- return zeroThroughTen[(int) val];
+ } else if (scale == 0 && val >= 0 && val < ZERO_THROUGH_TEN.length) {
+ return ZERO_THROUGH_TEN[(int) val];
}
return new BigDecimal(intVal, val, scale, prec);
}
@@ -1257,11 +1278,11 @@
* the {@code double}'s canonical string representation provided
* by the {@link Double#toString(double)} method.
*
- * <p><b>Note:</b> This is generally the preferred way to convert
- * a {@code double} (or {@code float}) into a
- * {@code BigDecimal}, as the value returned is equal to that
- * resulting from constructing a {@code BigDecimal} from the
- * result of using {@link Double#toString(double)}.
+ * @apiNote This is generally the preferred way to convert a
+ * {@code double} (or {@code float}) into a {@code BigDecimal}, as
+ * the value returned is equal to that resulting from constructing
+ * a {@code BigDecimal} from the result of using {@link
+ * Double#toString(double)}.
*
* @param val {@code double} to convert to a {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is equal to or approximately
@@ -1474,8 +1495,8 @@
}
/**
- * Returns a {@code BigDecimal} whose value is <tt>(this ×
- * multiplicand)</tt>, and whose scale is {@code (this.scale() +
+ * Returns a {@code BigDecimal} whose value is <code>(this ×
+ * multiplicand)</code>, and whose scale is {@code (this.scale() +
* multiplicand.scale())}.
*
* @param multiplicand value to be multiplied by this {@code BigDecimal}.
@@ -1499,8 +1520,8 @@
}
/**
- * Returns a {@code BigDecimal} whose value is <tt>(this ×
- * multiplicand)</tt>, with rounding according to the context settings.
+ * Returns a {@code BigDecimal} whose value is <code>(this ×
+ * multiplicand)</code>, with rounding according to the context settings.
*
* @param multiplicand value to be multiplied by this {@code BigDecimal}.
* @param mc the context to use.
@@ -1534,7 +1555,7 @@
* be performed to generate a result with the specified scale, the
* specified rounding mode is applied.
*
- * <p>The new {@link #divide(BigDecimal, int, RoundingMode)} method
+ * @deprecated The method {@link #divide(BigDecimal, int, RoundingMode)}
* should be used in preference to this legacy method.
*
* @param divisor value by which this {@code BigDecimal} is to be divided.
@@ -1556,6 +1577,7 @@
* @see #ROUND_HALF_EVEN
* @see #ROUND_UNNECESSARY
*/
+ @Deprecated(since="9")
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
@@ -1600,7 +1622,7 @@
* rounding must be performed to generate a result with the given
* scale, the specified rounding mode is applied.
*
- * <p>The new {@link #divide(BigDecimal, RoundingMode)} method
+ * @deprecated The method {@link #divide(BigDecimal, RoundingMode)}
* should be used in preference to this legacy method.
*
* @param divisor value by which this {@code BigDecimal} is to be divided.
@@ -1621,6 +1643,7 @@
* @see #ROUND_HALF_EVEN
* @see #ROUND_UNNECESSARY
*/
+ @Deprecated(since="9")
public BigDecimal divide(BigDecimal divisor, int roundingMode) {
return this.divide(divisor, scale, roundingMode);
}
@@ -1881,7 +1904,7 @@
*
* <p>The remainder is given by
* {@code this.subtract(this.divideToIntegralValue(divisor).multiply(divisor))}.
- * Note that this is not the modulo operation (the result can be
+ * Note that this is <em>not</em> the modulo operation (the result can be
* negative).
*
* @param divisor value by which this {@code BigDecimal} is to be divided.
@@ -1992,8 +2015,298 @@
}
/**
+ * Returns an approximation to the square root of {@code this}
+ * with rounding according to the context settings.
+ *
+ * <p>The preferred scale of the returned result is equal to
+ * {@code this.scale()/2}. The value of the returned result is
+ * always within one ulp of the exact decimal value for the
+ * precision in question. If the rounding mode is {@link
+ * RoundingMode#HALF_UP HALF_UP}, {@link RoundingMode#HALF_DOWN
+ * HALF_DOWN}, or {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
+ * result is within one half an ulp of the exact decimal value.
+ *
+ * <p>Special case:
+ * <ul>
+ * <li> The square root of a number numerically equal to {@code
+ * ZERO} is numerically equal to {@code ZERO} with a preferred
+ * scale according to the general rule above. In particular, for
+ * {@code ZERO}, {@code ZERO.sqrt(mc).equals(ZERO)} is true with
+ * any {@code MathContext} as an argument.
+ * </ul>
+ *
+ * @param mc the context to use.
+ * @return the square root of {@code this}.
+ * @throws ArithmeticException if {@code this} is less than zero.
+ * @throws ArithmeticException if an exact result is requested
+ * ({@code mc.getPrecision()==0}) and there is no finite decimal
+ * expansion of the exact result
+ * @throws ArithmeticException if
+ * {@code (mc.getRoundingMode()==RoundingMode.UNNECESSARY}) and
+ * the exact result cannot fit in {@code mc.getPrecision()}
+ * digits.
+ * @see BigInteger#sqrt()
+ * @since 9
+ */
+ public BigDecimal sqrt(MathContext mc) {
+ int signum = signum();
+ if (signum == 1) {
+ /*
+ * The following code draws on the algorithm presented in
+ * "Properly Rounded Variable Precision Square Root," Hull and
+ * Abrham, ACM Transactions on Mathematical Software, Vol 11,
+ * No. 3, September 1985, Pages 229-237.
+ *
+ * The BigDecimal computational model differs from the one
+ * presented in the paper in several ways: first BigDecimal
+ * numbers aren't necessarily normalized, second many more
+ * rounding modes are supported, including UNNECESSARY, and
+ * exact results can be requested.
+ *
+ * The main steps of the algorithm below are as follows,
+ * first argument reduce the value to the numerical range
+ * [1, 10) using the following relations:
+ *
+ * x = y * 10 ^ exp
+ * sqrt(x) = sqrt(y) * 10^(exp / 2) if exp is even
+ * sqrt(x) = sqrt(y/10) * 10 ^((exp+1)/2) is exp is odd
+ *
+ * Then use Newton's iteration on the reduced value to compute
+ * the numerical digits of the desired result.
+ *
+ * Finally, scale back to the desired exponent range and
+ * perform any adjustment to get the preferred scale in the
+ * representation.
+ */
+
+ // The code below favors relative simplicity over checking
+ // for special cases that could run faster.
+
+ int preferredScale = this.scale()/2;
+ BigDecimal zeroWithFinalPreferredScale = valueOf(0L, preferredScale);
+
+ // First phase of numerical normalization, strip trailing
+ // zeros and check for even powers of 10.
+ BigDecimal stripped = this.stripTrailingZeros();
+ int strippedScale = stripped.scale();
+
+ // Numerically sqrt(10^2N) = 10^N
+ if (stripped.isPowerOfTen() &&
+ strippedScale % 2 == 0) {
+ BigDecimal result = valueOf(1L, strippedScale/2);
+ if (result.scale() != preferredScale) {
+ // Adjust to requested precision and preferred
+ // scale as appropriate.
+ result = result.add(zeroWithFinalPreferredScale, mc);
+ }
+ return result;
+ }
+
+ // After stripTrailingZeros, the representation is normalized as
+ //
+ // unscaledValue * 10^(-scale)
+ //
+ // where unscaledValue is an integer with the mimimum
+ // precision for the cohort of the numerical value. To
+ // allow binary floating-point hardware to be used to get
+ // approximately a 15 digit approximation to the square
+ // root, it is helpful to instead normalize this so that
+ // the significand portion is to right of the decimal
+ // point by roughly (scale() - precision() +1).
+
+ // Now the precision / scale adjustment
+ int scaleAdjust = 0;
+ int scale = stripped.scale() - stripped.precision() + 1;
+ if (scale % 2 == 0) {
+ scaleAdjust = scale;
+ } else {
+ scaleAdjust = scale - 1;
+ }
+
+ BigDecimal working = stripped.scaleByPowerOfTen(scaleAdjust);
+
+ assert // Verify 0.1 <= working < 10
+ ONE_TENTH.compareTo(working) <= 0 && working.compareTo(TEN) < 0;
+
+ // Use good ole' Math.sqrt to get the initial guess for
+ // the Newton iteration, good to at least 15 decimal
+ // digits. This approach does incur the cost of a
+ //
+ // BigDecimal -> double -> BigDecimal
+ //
+ // conversion cycle, but it avoids the need for several
+ // Newton iterations in BigDecimal arithmetic to get the
+ // working answer to 15 digits of precision. If many fewer
+ // than 15 digits were needed, it might be faster to do
+ // the loop entirely in BigDecimal arithmetic.
+ //
+ // (A double value might have as much many as 17 decimal
+ // digits of precision; it depends on the relative density
+ // of binary and decimal numbers at different regions of
+ // the number line.)
+ //
+ // (It would be possible to check for certain special
+ // cases to avoid doing any Newton iterations. For
+ // example, if the BigDecimal -> double conversion was
+ // known to be exact and the rounding mode had a
+ // low-enough precision, the post-Newton rounding logic
+ // could be applied directly.)
+
+ BigDecimal guess = new BigDecimal(Math.sqrt(working.doubleValue()));
+ int guessPrecision = 15;
+ int originalPrecision = mc.getPrecision();
+ int targetPrecision;
+
+ // If an exact value is requested, it must only need about
+ // half of the input digits to represent since multiplying
+ // an N digit number by itself yield a 2N-1 digit or 2N
+ // digit result.
+ if (originalPrecision == 0) {
+ targetPrecision = stripped.precision()/2 + 1;
+ } else {
+ targetPrecision = originalPrecision;
+ }
+
+ // When setting the precision to use inside the Newton
+ // iteration loop, take care to avoid the case where the
+ // precision of the input exceeds the requested precision
+ // and rounding the input value too soon.
+ BigDecimal approx = guess;
+ int workingPrecision = working.precision();
+ do {
+ int tmpPrecision = Math.max(Math.max(guessPrecision, targetPrecision + 2),
+ workingPrecision);
+ MathContext mcTmp = new MathContext(tmpPrecision, RoundingMode.HALF_EVEN);
+ // approx = 0.5 * (approx + fraction / approx)
+ approx = ONE_HALF.multiply(approx.add(working.divide(approx, mcTmp), mcTmp));
+ guessPrecision *= 2;
+ } while (guessPrecision < targetPrecision + 2);
+
+ BigDecimal result;
+ RoundingMode targetRm = mc.getRoundingMode();
+ if (targetRm == RoundingMode.UNNECESSARY || originalPrecision == 0) {
+ RoundingMode tmpRm =
+ (targetRm == RoundingMode.UNNECESSARY) ? RoundingMode.DOWN : targetRm;
+ MathContext mcTmp = new MathContext(targetPrecision, tmpRm);
+ result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mcTmp);
+
+ // If result*result != this numerically, the square
+ // root isn't exact
+ if (this.subtract(result.multiply(result)).compareTo(ZERO) != 0) {
+ throw new ArithmeticException("Computed square root not exact.");
+ }
+ } else {
+ result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc);
+ }
+
+ if (result.scale() != preferredScale) {
+ // The preferred scale of an add is
+ // max(addend.scale(), augend.scale()). Therefore, if
+ // the scale of the result is first minimized using
+ // stripTrailingZeros(), adding a zero of the
+ // preferred scale rounding the correct precision will
+ // perform the proper scale vs precision tradeoffs.
+ result = result.stripTrailingZeros().
+ add(zeroWithFinalPreferredScale,
+ new MathContext(originalPrecision, RoundingMode.UNNECESSARY));
+ }
+ assert squareRootResultAssertions(result, mc);
+ return result;
+ } else {
+ switch (signum) {
+ case -1:
+ throw new ArithmeticException("Attempted square root " +
+ "of negative BigDecimal");
+ case 0:
+ return valueOf(0L, scale()/2);
+
+ default:
+ throw new AssertionError("Bad value from signum");
+ }
+ }
+ }
+
+ private boolean isPowerOfTen() {
+ return BigInteger.ONE.equals(this.unscaledValue());
+ }
+
+ /**
+ * For nonzero values, check numerical correctness properties of
+ * the computed result for the chosen rounding mode.
+ *
+ * For the directed roundings, for DOWN and FLOOR, result^2 must
+ * be {@code <=} the input and (result+ulp)^2 must be {@code >} the
+ * input. Conversely, for UP and CEIL, result^2 must be {@code >=} the
+ * input and (result-ulp)^2 must be {@code <} the input.
+ */
+ private boolean squareRootResultAssertions(BigDecimal result, MathContext mc) {
+ if (result.signum() == 0) {
+ return squareRootZeroResultAssertions(result, mc);
+ } else {
+ RoundingMode rm = mc.getRoundingMode();
+ BigDecimal ulp = result.ulp();
+ BigDecimal neighborUp = result.add(ulp);
+ // Make neighbor down accurate even for powers of ten
+ if (this.isPowerOfTen()) {
+ ulp = ulp.divide(TEN);
+ }
+ BigDecimal neighborDown = result.subtract(ulp);
+
+ // Both the starting value and result should be nonzero and positive.
+ if (result.signum() != 1 ||
+ this.signum() != 1) {
+ return false;
+ }
+
+ switch (rm) {
+ case DOWN:
+ case FLOOR:
+ return
+ result.multiply(result).compareTo(this) <= 0 &&
+ neighborUp.multiply(neighborUp).compareTo(this) > 0;
+
+ case UP:
+ case CEILING:
+ return
+ result.multiply(result).compareTo(this) >= 0 &&
+ neighborDown.multiply(neighborDown).compareTo(this) < 0;
+
+ case HALF_DOWN:
+ case HALF_EVEN:
+ case HALF_UP:
+ BigDecimal err = result.multiply(result).subtract(this).abs();
+ BigDecimal errUp = neighborUp.multiply(neighborUp).subtract(this);
+ BigDecimal errDown = this.subtract(neighborDown.multiply(neighborDown));
+ // All error values should be positive so don't need to
+ // compare absolute values.
+
+ int err_comp_errUp = err.compareTo(errUp);
+ int err_comp_errDown = err.compareTo(errDown);
+
+ return
+ errUp.signum() == 1 &&
+ errDown.signum() == 1 &&
+
+ err_comp_errUp <= 0 &&
+ err_comp_errDown <= 0 &&
+
+ ((err_comp_errUp == 0 ) ? err_comp_errDown < 0 : true) &&
+ ((err_comp_errDown == 0 ) ? err_comp_errUp < 0 : true);
+ // && could check for digit conditions for ties too
+
+ default: // Definition of UNNECESSARY already verified.
+ return true;
+ }
+ }
+ }
+
+ private boolean squareRootZeroResultAssertions(BigDecimal result, MathContext mc) {
+ return this.compareTo(ZERO) == 0;
+ }
+
+ /**
* Returns a {@code BigDecimal} whose value is
- * <tt>(this<sup>n</sup>)</tt>, The power is computed exactly, to
+ * <code>(this<sup>n</sup>)</code>, The power is computed exactly, to
* unlimited precision.
*
* <p>The parameter {@code n} must be in the range 0 through
@@ -2004,7 +2317,7 @@
* range of this method.
*
* @param n power to raise this {@code BigDecimal} to.
- * @return <tt>this<sup>n</sup></tt>
+ * @return <code>this<sup>n</sup></code>
* @throws ArithmeticException if {@code n} is out of range.
* @since 1.5
*/
@@ -2020,7 +2333,7 @@
/**
* Returns a {@code BigDecimal} whose value is
- * <tt>(this<sup>n</sup>)</tt>. The current implementation uses
+ * <code>(this<sup>n</sup>)</code>. The current implementation uses
* the core algorithm defined in ANSI standard X3.274-1996 with
* rounding according to the context settings. In general, the
* returned numerical value is within two ulps of the exact
@@ -2061,7 +2374,7 @@
*
* @param n power to raise this {@code BigDecimal} to.
* @param mc the context to use.
- * @return <tt>this<sup>n</sup></tt> using the ANSI standard X3.274-1996
+ * @return <code>this<sup>n</sup></code> using the ANSI standard X3.274-1996
* algorithm
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}, or {@code n} is out
@@ -2249,8 +2562,8 @@
/**
* Returns a {@code BigInteger} whose value is the <i>unscaled
- * value</i> of this {@code BigDecimal}. (Computes <tt>(this *
- * 10<sup>this.scale()</sup>)</tt>.)
+ * value</i> of this {@code BigDecimal}. (Computes <code>(this *
+ * 10<sup>this.scale()</sup>)</code>.)
*
* @return the unscaled value of this {@code BigDecimal}.
* @since 1.2
@@ -2265,15 +2578,21 @@
* Rounding mode to round away from zero. Always increments the
* digit prior to a nonzero discarded fraction. Note that this rounding
* mode never decreases the magnitude of the calculated value.
+ *
+ * @deprecated Use {@link RoundingMode#UP} instead.
*/
- public final static int ROUND_UP = 0;
+ @Deprecated(since="9")
+ public static final int ROUND_UP = 0;
/**
* Rounding mode to round towards zero. Never increments the digit
* prior to a discarded fraction (i.e., truncates). Note that this
* rounding mode never increases the magnitude of the calculated value.
+ *
+ * @deprecated Use {@link RoundingMode#DOWN} instead.
*/
- public final static int ROUND_DOWN = 1;
+ @Deprecated(since="9")
+ public static final int ROUND_DOWN = 1;
/**
* Rounding mode to round towards positive infinity. If the
@@ -2281,8 +2600,11 @@
* {@code ROUND_UP}; if negative, behaves as for
* {@code ROUND_DOWN}. Note that this rounding mode never
* decreases the calculated value.
+ *
+ * @deprecated Use {@link RoundingMode#CEILING} instead.
*/
- public final static int ROUND_CEILING = 2;
+ @Deprecated(since="9")
+ public static final int ROUND_CEILING = 2;
/**
* Rounding mode to round towards negative infinity. If the
@@ -2290,8 +2612,11 @@
* {@code ROUND_DOWN}; if negative, behave as for
* {@code ROUND_UP}. Note that this rounding mode never
* increases the calculated value.
+ *
+ * @deprecated Use {@link RoundingMode#FLOOR} instead.
*/
- public final static int ROUND_FLOOR = 3;
+ @Deprecated(since="9")
+ public static final int ROUND_FLOOR = 3;
/**
* Rounding mode to round towards {@literal "nearest neighbor"}
@@ -2300,8 +2625,11 @@
* ≥ 0.5; otherwise, behaves as for {@code ROUND_DOWN}. Note
* that this is the rounding mode that most of us were taught in
* grade school.
+ *
+ * @deprecated Use {@link RoundingMode#HALF_UP} instead.
*/
- public final static int ROUND_HALF_UP = 4;
+ @Deprecated(since="9")
+ public static final int ROUND_HALF_UP = 4;
/**
* Rounding mode to round towards {@literal "nearest neighbor"}
@@ -2309,8 +2637,11 @@
* down. Behaves as for {@code ROUND_UP} if the discarded
* fraction is {@literal >} 0.5; otherwise, behaves as for
* {@code ROUND_DOWN}.
+ *
+ * @deprecated Use {@link RoundingMode#HALF_DOWN} instead.
*/
- public final static int ROUND_HALF_DOWN = 5;
+ @Deprecated(since="9")
+ public static final int ROUND_HALF_DOWN = 5;
/**
* Rounding mode to round towards the {@literal "nearest neighbor"}
@@ -2321,16 +2652,22 @@
* {@code ROUND_HALF_DOWN} if it's even. Note that this is the
* rounding mode that minimizes cumulative error when applied
* repeatedly over a sequence of calculations.
+ *
+ * @deprecated Use {@link RoundingMode#HALF_EVEN} instead.
*/
- public final static int ROUND_HALF_EVEN = 6;
+ @Deprecated(since="9")
+ public static final int ROUND_HALF_EVEN = 6;
/**
* Rounding mode to assert that the requested operation has an exact
* result, hence no rounding is necessary. If this rounding mode is
* specified on an operation that yields an inexact result, an
* {@code ArithmeticException} is thrown.
+ *
+ * @deprecated Use {@link RoundingMode#UNNECESSARY} instead.
*/
- public final static int ROUND_UNNECESSARY = 7;
+ @Deprecated(since="9")
+ public static final int ROUND_UNNECESSARY = 7;
// Scaling/Rounding Operations
@@ -2366,10 +2703,10 @@
* in this case, the specified rounding mode is applied to the
* division.
*
- * <p>Note that since BigDecimal objects are immutable, calls of
- * this method do <i>not</i> result in the original object being
+ * @apiNote Since BigDecimal objects are immutable, calls of
+ * this method do <em>not</em> result in the original object being
* modified, contrary to the usual convention of having methods
- * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
+ * named <code>set<i>X</i></code> mutate field <i>{@code X}</i>.
* Instead, {@code setScale} returns an object with the proper
* scale; the returned object may or may not be newly allocated.
*
@@ -2399,14 +2736,14 @@
* in this case, the specified rounding mode is applied to the
* division.
*
- * <p>Note that since BigDecimal objects are immutable, calls of
- * this method do <i>not</i> result in the original object being
+ * @apiNote Since BigDecimal objects are immutable, calls of
+ * this method do <em>not</em> result in the original object being
* modified, contrary to the usual convention of having methods
- * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
+ * named <code>set<i>X</i></code> mutate field <i>{@code X}</i>.
* Instead, {@code setScale} returns an object with the proper
* scale; the returned object may or may not be newly allocated.
*
- * <p>The new {@link #setScale(int, RoundingMode)} method should
+ * @deprecated The method {@link #setScale(int, RoundingMode)} should
* be used in preference to this legacy method.
*
* @param newScale scale of the {@code BigDecimal} value to be returned.
@@ -2429,6 +2766,7 @@
* @see #ROUND_HALF_EVEN
* @see #ROUND_UNNECESSARY
*/
+ @Deprecated(since="9")
public BigDecimal setScale(int newScale, int roundingMode) {
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
@@ -2493,10 +2831,10 @@
* versions of {@code setScale}, but saves the caller the trouble
* of specifying a rounding mode in cases where it is irrelevant.
*
- * <p>Note that since {@code BigDecimal} objects are immutable,
- * calls of this method do <i>not</i> result in the original
+ * @apiNote Since {@code BigDecimal} objects are immutable,
+ * calls of this method do <em>not</em> result in the original
* object being modified, contrary to the usual convention of
- * having methods named <tt>set<i>X</i></tt> mutate field
+ * having methods named <code>set<i>X</i></code> mutate field
* <i>{@code X}</i>. Instead, {@code setScale} returns an
* object with the proper scale; the returned object may or may
* not be newly allocated.
@@ -2523,8 +2861,8 @@
* {@code n} is non-negative, the call merely adds {@code n} to
* the scale. If {@code n} is negative, the call is equivalent
* to {@code movePointRight(-n)}. The {@code BigDecimal}
- * returned by this call has value <tt>(this ×
- * 10<sup>-n</sup>)</tt> and scale {@code max(this.scale()+n,
+ * returned by this call has value <code>(this ×
+ * 10<sup>-n</sup>)</code> and scale {@code max(this.scale()+n,
* 0)}.
*
* @param n number of places to move the decimal point to the left.
@@ -2545,8 +2883,8 @@
* If {@code n} is non-negative, the call merely subtracts
* {@code n} from the scale. If {@code n} is negative, the call
* is equivalent to {@code movePointLeft(-n)}. The
- * {@code BigDecimal} returned by this call has value <tt>(this
- * × 10<sup>n</sup>)</tt> and scale {@code max(this.scale()-n,
+ * {@code BigDecimal} returned by this call has value <code>(this
+ * × 10<sup>n</sup>)</code> and scale {@code max(this.scale()-n,
* 0)}.
*
* @param n number of places to move the decimal point to the right.
@@ -2623,6 +2961,7 @@
* @return -1, 0, or 1 as this {@code BigDecimal} is numerically
* less than, equal to, or greater than {@code val}.
*/
+ @Override
public int compareTo(BigDecimal val) {
// Quick path for equal scale and non-inflated case.
if (scale == val.scale) {
@@ -2662,14 +3001,13 @@
return -1;
if (xae > yae)
return 1;
- BigInteger rb = null;
if (sdiff < 0) {
// The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
if ( sdiff > Integer.MIN_VALUE &&
(xs == INFLATED ||
(xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
ys == INFLATED) {
- rb = bigMultiplyPowerTen((int)-sdiff);
+ BigInteger rb = bigMultiplyPowerTen((int)-sdiff);
return rb.compareMagnitude(val.intVal);
}
} else { // sdiff > 0
@@ -2678,7 +3016,7 @@
(ys == INFLATED ||
(ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
xs == INFLATED) {
- rb = val.bigMultiplyPowerTen((int)sdiff);
+ BigInteger rb = val.bigMultiplyPowerTen((int)sdiff);
return this.intVal.compareMagnitude(rb);
}
}
@@ -2762,7 +3100,7 @@
/**
* Returns the hash code for this {@code BigDecimal}. Note that
* two {@code BigDecimal} objects that are numerically equal but
- * differ in scale (like 2.0 and 2.00) will generally <i>not</i>
+ * differ in scale (like 2.0 and 2.00) will generally <em>not</em>
* have the same hash code.
*
* @return hash code for this {@code BigDecimal}.
@@ -2823,12 +3161,12 @@
* adjusted exponent converted to a character form. The latter is
* in base ten, using the characters {@code '0'} through
* {@code '9'} with no leading zeros, and is always prefixed by a
- * sign character {@code '-'} (<tt>'\u002D'</tt>) if the
+ * sign character {@code '-'} (<code>'\u002D'</code>) if the
* adjusted exponent is negative, {@code '+'}
- * (<tt>'\u002B'</tt>) otherwise).
+ * (<code>'\u002B'</code>) otherwise).
*
* <p>Finally, the entire string is prefixed by a minus sign
- * character {@code '-'} (<tt>'\u002D'</tt>) if the unscaled
+ * character {@code '-'} (<code>'\u002D'</code>) if the unscaled
* value is less than zero. No sign character is prefixed if the
* unscaled value is zero or positive.
*
@@ -2883,8 +3221,9 @@
@Override
public String toString() {
String sc = stringCache;
- if (sc == null)
+ if (sc == null) {
stringCache = sc = layoutChars(true);
+ }
return sc;
}
@@ -2927,7 +3266,7 @@
* in the result.
*
* The entire string is prefixed by a minus sign character '-'
- * (<tt>'\u002D'</tt>) if the unscaled value is less than
+ * (<code>'\u002D'</code>) if the unscaled value is less than
* zero. No sign character is prefixed if the unscaled value is
* zero or positive.
*
@@ -2961,18 +3300,19 @@
if(signum()==0) {
return "0";
}
- int tailingZeros = checkScaleNonZero((-(long)scale));
+ int trailingZeros = checkScaleNonZero((-(long)scale));
StringBuilder buf;
if(intCompact!=INFLATED) {
- buf = new StringBuilder(20+tailingZeros);
+ buf = new StringBuilder(20+trailingZeros);
buf.append(intCompact);
} else {
String str = intVal.toString();
- buf = new StringBuilder(str.length()+tailingZeros);
+ buf = new StringBuilder(str.length()+trailingZeros);
buf.append(str);
}
- for (int i = 0; i < tailingZeros; i++)
+ for (int i = 0; i < trailingZeros; i++) {
buf.append('0');
+ }
return buf.toString();
}
String str ;
@@ -2999,8 +3339,9 @@
} else { /* We must insert zeros between point and intVal */
buf = new StringBuilder(3-insertionPoint + intString.length());
buf.append(signum<0 ? "-0." : "0.");
- for (int i=0; i<-insertionPoint; i++)
+ for (int i=0; i<-insertionPoint; i++) {
buf.append('0');
+ }
buf.append(intString);
}
return buf.toString();
@@ -3010,7 +3351,7 @@
* Converts this {@code BigDecimal} to a {@code BigInteger}.
* This conversion is analogous to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code long} as defined in section 5.1.3 of
+ * {@code long} as defined in
* <cite>The Java™ Language Specification</cite>:
* any fractional part of this
* {@code BigDecimal} will be discarded. Note that this
@@ -3022,6 +3363,7 @@
* {@link #toBigIntegerExact()} method.
*
* @return this {@code BigDecimal} converted to a {@code BigInteger}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public BigInteger toBigInteger() {
// force to an integer, quietly
@@ -3047,7 +3389,7 @@
* Converts this {@code BigDecimal} to a {@code long}.
* This conversion is analogous to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code short} as defined in section 5.1.3 of
+ * {@code short} as defined in
* <cite>The Java™ Language Specification</cite>:
* any fractional part of this
* {@code BigDecimal} will be discarded, and if the resulting
@@ -3058,34 +3400,13 @@
* as return a result with the opposite sign.
*
* @return this {@code BigDecimal} converted to a {@code long}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
+ @Override
public long longValue(){
- if (intCompact != INFLATED && scale == 0) {
- return intCompact;
- } else {
- // Fastpath zero and small values
- if (this.signum() == 0 || fractionOnly() ||
- // Fastpath very large-scale values that will result
- // in a truncated value of zero. If the scale is -64
- // or less, there are at least 64 powers of 10 in the
- // value of the numerical result. Since 10 = 2*5, in
- // that case there would also be 64 powers of 2 in the
- // result, meaning all 64 bits of a long will be zero.
- scale <= -64) {
- return 0;
- } else {
- return toBigInteger().longValue();
- }
- }
- }
-
- /**
- * Return true if a nonzero BigDecimal has an absolute value less
- * than one; i.e. only has fraction digits.
- */
- private boolean fractionOnly() {
- assert this.signum() != 0;
- return (this.precision() - this.scale) <= 0;
+ return (intCompact != INFLATED && scale == 0) ?
+ intCompact:
+ toBigInteger().longValue();
}
/**
@@ -3103,20 +3424,15 @@
public long longValueExact() {
if (intCompact != INFLATED && scale == 0)
return intCompact;
-
- // Fastpath zero
- if (this.signum() == 0)
- return 0;
-
- // Fastpath numbers less than 1.0 (the latter can be very slow
- // to round if very small)
- if (fractionOnly())
- throw new ArithmeticException("Rounding necessary");
-
// If more than 19 digits in integer part it cannot possibly fit
if ((precision() - scale) > 19) // [OK for negative scale too]
throw new java.lang.ArithmeticException("Overflow");
-
+ // Fastpath zero and < 1.0 numbers (the latter can be very slow
+ // to round if very small)
+ if (this.signum() == 0)
+ return 0;
+ if ((this.precision() - this.scale) <= 0)
+ throw new ArithmeticException("Rounding necessary");
// round to an integer, with Exception if decimal part non-0
BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
if (num.precision() >= 19) // need to check carefully
@@ -3143,7 +3459,7 @@
* Converts this {@code BigDecimal} to an {@code int}.
* This conversion is analogous to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code short} as defined in section 5.1.3 of
+ * {@code short} as defined in
* <cite>The Java™ Language Specification</cite>:
* any fractional part of this
* {@code BigDecimal} will be discarded, and if the resulting
@@ -3154,11 +3470,13 @@
* value as well as return a result with the opposite sign.
*
* @return this {@code BigDecimal} converted to an {@code int}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
+ @Override
public int intValue() {
return (intCompact != INFLATED && scale == 0) ?
(int)intCompact :
- (int)longValue();
+ toBigInteger().intValue();
}
/**
@@ -3225,7 +3543,7 @@
* Converts this {@code BigDecimal} to a {@code float}.
* This conversion is similar to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code float} as defined in section 5.1.3 of
+ * {@code float} as defined in
* <cite>The Java™ Language Specification</cite>:
* if this {@code BigDecimal} has too great a
* magnitude to represent as a {@code float}, it will be
@@ -3236,7 +3554,9 @@
* value.
*
* @return this {@code BigDecimal} converted to a {@code float}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
+ @Override
public float floatValue(){
if(intCompact != INFLATED) {
if (scale == 0) {
@@ -3252,10 +3572,10 @@
// Don't have too guard against
// Math.abs(MIN_VALUE) because of outer check
// against INFLATED.
- if (scale > 0 && scale < float10pow.length) {
- return (float)intCompact / float10pow[scale];
- } else if (scale < 0 && scale > -float10pow.length) {
- return (float)intCompact * float10pow[-scale];
+ if (scale > 0 && scale < FLOAT_10_POW.length) {
+ return (float)intCompact / FLOAT_10_POW[scale];
+ } else if (scale < 0 && scale > -FLOAT_10_POW.length) {
+ return (float)intCompact * FLOAT_10_POW[-scale];
}
}
}
@@ -3268,7 +3588,7 @@
* Converts this {@code BigDecimal} to a {@code double}.
* This conversion is similar to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code float} as defined in section 5.1.3 of
+ * {@code float} as defined in
* <cite>The Java™ Language Specification</cite>:
* if this {@code BigDecimal} has too great a
* magnitude represent as a {@code double}, it will be
@@ -3279,7 +3599,9 @@
* value.
*
* @return this {@code BigDecimal} converted to a {@code double}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
+ @Override
public double doubleValue(){
if(intCompact != INFLATED) {
if (scale == 0) {
@@ -3295,10 +3617,10 @@
// Don't have too guard against
// Math.abs(MIN_VALUE) because of outer check
// against INFLATED.
- if (scale > 0 && scale < double10pow.length) {
- return (double)intCompact / double10pow[scale];
- } else if (scale < 0 && scale > -double10pow.length) {
- return (double)intCompact * double10pow[-scale];
+ if (scale > 0 && scale < DOUBLE_10_POW.length) {
+ return (double)intCompact / DOUBLE_10_POW[scale];
+ } else if (scale < 0 && scale > -DOUBLE_10_POW.length) {
+ return (double)intCompact * DOUBLE_10_POW[-scale];
}
}
}
@@ -3311,7 +3633,7 @@
* Powers of 10 which can be represented exactly in {@code
* double}.
*/
- private static final double double10pow[] = {
+ private static final double DOUBLE_10_POW[] = {
1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11,
1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17,
@@ -3322,7 +3644,7 @@
* Powers of 10 which can be represented exactly in {@code
* float}.
*/
- private static final float float10pow[] = {
+ private static final float FLOAT_10_POW[] = {
1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
};
@@ -3417,7 +3739,7 @@
return charPos;
}
- final static char[] DIGIT_TENS = {
+ static final char[] DIGIT_TENS = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
@@ -3430,7 +3752,7 @@
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
};
- final static char[] DIGIT_ONES = {
+ static final char[] DIGIT_ONES = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
@@ -3535,8 +3857,9 @@
} else if (sig >= coeffLen) { // significand all in integer
buf.append(coeff, offset, coeffLen);
// may need some zeros, too
- for (int i = sig - coeffLen; i > 0; i--)
+ for (int i = sig - coeffLen; i > 0; i--) {
buf.append('0');
+ }
} else { // xx.xxE form
buf.append(coeff, offset, sig);
buf.append('.');
@@ -3590,11 +3913,13 @@
// to prevent multiple threads from expanding the same array.
if (curLen <= n) {
int newLen = curLen << 1;
- while (newLen <= n)
+ while (newLen <= n) {
newLen <<= 1;
+ }
pows = Arrays.copyOf(pows, newLen);
- for (int i = curLen; i < newLen; i++)
+ for (int i = curLen; i < newLen; i++) {
pows[i] = pows[i - 1].multiply(BigInteger.TEN);
+ }
// Based on the following facts:
// 1. pows is a private local variable;
// 2. the following store is a volatile store.
@@ -3734,9 +4059,7 @@
* {@code BigDecimal}s to be aligned.
*/
private static void matchScale(BigDecimal[] val) {
- if (val[0].scale == val[1].scale) {
- return;
- } else if (val[0].scale < val[1].scale) {
+ if (val[0].scale < val[1].scale) {
val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
} else if (val[1].scale < val[0].scale) {
val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
@@ -4240,16 +4563,16 @@
* do rounding based on the passed in roundingMode.
*/
private static BigInteger divideAndRound(BigInteger bdividend, long ldivisor, int roundingMode) {
- boolean isRemainderZero; // record remainder is zero or not
- int qsign; // quotient sign
- long r = 0; // store quotient & remainder in long
- MutableBigInteger mq = null; // store quotient
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
- mq = new MutableBigInteger();
- r = mdividend.divide(ldivisor, mq);
- isRemainderZero = (r == 0);
- qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ // store quotient
+ MutableBigInteger mq = new MutableBigInteger();
+ // store quotient & remainder in long
+ long r = mdividend.divide(ldivisor, mq);
+ // record remainder is zero or not
+ boolean isRemainderZero = (r == 0);
+ // quotient sign
+ int qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
if (!isRemainderZero) {
if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
mq.add(MutableBigInteger.ONE);
@@ -4269,16 +4592,16 @@
*/
private static BigDecimal divideAndRound(BigInteger bdividend,
long ldivisor, int scale, int roundingMode, int preferredScale) {
- boolean isRemainderZero; // record remainder is zero or not
- int qsign; // quotient sign
- long r = 0; // store quotient & remainder in long
- MutableBigInteger mq = null; // store quotient
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
- mq = new MutableBigInteger();
- r = mdividend.divide(ldivisor, mq);
- isRemainderZero = (r == 0);
- qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ // store quotient
+ MutableBigInteger mq = new MutableBigInteger();
+ // store quotient & remainder in long
+ long r = mdividend.divide(ldivisor, mq);
+ // record remainder is zero or not
+ boolean isRemainderZero = (r == 0);
+ // quotient sign
+ int qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
if (!isRemainderZero) {
if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
mq.add(MutableBigInteger.ONE);
diff --git a/ojluni/src/main/java/java/math/BigInteger.java b/ojluni/src/main/java/java/math/BigInteger.java
index 3a23c8f..9801b67e 100644
--- a/ojluni/src/main/java/java/math/BigInteger.java
+++ b/ojluni/src/main/java/java/math/BigInteger.java
@@ -34,12 +34,14 @@
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.util.Arrays;
+import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
-import libcore.math.NativeBN;
+
import jdk.internal.math.DoubleConsts;
import jdk.internal.math.FloatConsts;
+import libcore.math.NativeBN;
/**
* Immutable arbitrary-precision integers. All operations behave as if
* BigIntegers were represented in two's-complement notation (like Java's
@@ -50,19 +52,17 @@
* and a few other miscellaneous operations.
*
* <p>Semantics of arithmetic operations exactly mimic those of Java's integer
- * arithmetic operators, as defined in <i>The Java Language Specification</i>.
+ * arithmetic operators, as defined in <i>The Java™ Language Specification</i>.
* For example, division by zero throws an {@code ArithmeticException}, and
* division of a negative by a positive yields a negative (or zero) remainder.
- * All of the details in the Spec concerning overflow are ignored, as
- * BigIntegers are made as large as necessary to accommodate the results of an
- * operation.
*
* <p>Semantics of shift operations extend those of Java's shift operators
* to allow for negative shift distances. A right-shift with a negative
* shift distance results in a left shift, and vice-versa. The unsigned
- * right shift operator ({@code >>>}) is omitted, as this operation makes
- * little sense in combination with the "infinite word size" abstraction
- * provided by this class.
+ * right shift operator ({@code >>>}) is omitted since this operation
+ * only makes sense for a fixed sized word and not for a
+ * representation conceptually having an infinite number of leading
+ * virtual sign bits.
*
* <p>Semantics of bitwise logical operations exactly mimic those of Java's
* bitwise integer operators. The binary operators ({@code and},
@@ -82,8 +82,8 @@
* extended so that it contains the designated bit. None of the single-bit
* operations can produce a BigInteger with a different sign from the
* BigInteger being operated on, as they affect only a single bit, and the
- * "infinite word size" abstraction provided by this class ensures that there
- * are infinitely many "virtual sign bits" preceding each BigInteger.
+ * arbitrarily large abstraction provided by this class ensures that conceptually
+ * there are infinitely many "virtual sign bits" preceding each BigInteger.
*
* <p>For the sake of brevity and clarity, pseudo-code is used throughout the
* descriptions of BigInteger methods. The pseudo-code expression
@@ -103,33 +103,36 @@
* +2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive)
* and may support values outside of that range.
*
+ * An {@code ArithmeticException} is thrown when a BigInteger
+ * constructor or method would generate a value outside of the
+ * supported range.
+ *
* The range of probable prime values is limited and may be less than
* the full supported positive range of {@code BigInteger}.
* The range must be at least 1 to 2<sup>500000000</sup>.
*
* @implNote
- * BigInteger constructors and operations throw {@code ArithmeticException} when
- * the result is out of the supported range of
+ * In the reference implementation, BigInteger constructors and
+ * operations throw {@code ArithmeticException} when the result is out
+ * of the supported range of
* -2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive) to
* +2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive).
*
* @see BigDecimal
+ * @jls 4.2.2 Integer Operations
* @author Josh Bloch
* @author Michael McCloskey
* @author Alan Eliasen
* @author Timothy Buktu
- * @since JDK1.1
+ * @since 1.1
*/
public class BigInteger extends Number implements Comparable<BigInteger> {
-
/**
* The signum of this BigInteger: -1 for negative, 0 for zero, or
- * 1 for positive. Note that the BigInteger zero <i>must</i> have
+ * 1 for positive. Note that the BigInteger zero <em>must</em> have
* a signum of 0. This is necessary to ensures that there is exactly one
* representation for each BigInteger value.
- *
- * @serial
*/
final int signum;
@@ -144,60 +147,48 @@
*/
final int[] mag;
- // These "redundant fields" are initialized with recognizable nonsense
- // values, and cached the first time they are needed (or never, if they
- // aren't needed).
-
- /**
- * One plus the bitCount of this BigInteger. Zeros means uninitialized.
- *
- * @serial
- * @see #bitCount
- * @deprecated Deprecated since logical value is offset from stored
- * value and correction factor is applied in accessor method.
- */
- @Deprecated
- private int bitCount;
+ // The following fields are stable variables. A stable variable's value
+ // changes at most once from the default zero value to a non-zero stable
+ // value. A stable value is calculated lazily on demand.
/**
- * One plus the bitLength of this BigInteger. Zeros means uninitialized.
+ * One plus the bitCount of this BigInteger. This is a stable variable.
+ *
+ * @see #bitCount
+ */
+ private int bitCountPlusOne;
+
+ /**
+ * One plus the bitLength of this BigInteger. This is a stable variable.
* (either value is acceptable).
*
- * @serial
* @see #bitLength()
- * @deprecated Deprecated since logical value is offset from stored
- * value and correction factor is applied in accessor method.
*/
- @Deprecated
- private int bitLength;
+ private int bitLengthPlusOne;
/**
- * Two plus the lowest set bit of this BigInteger, as returned by
- * getLowestSetBit().
+ * Two plus the lowest set bit of this BigInteger. This is a stable variable.
*
- * @serial
* @see #getLowestSetBit
- * @deprecated Deprecated since logical value is offset from stored
- * value and correction factor is applied in accessor method.
*/
- @Deprecated
- private int lowestSetBit;
+ private int lowestSetBitPlusTwo;
/**
* Two plus the index of the lowest-order int in the magnitude of this
- * BigInteger that contains a nonzero int, or -2 (either value is acceptable).
- * The least significant int has int-number 0, the next int in order of
+ * BigInteger that contains a nonzero int. This is a stable variable. The
+ * least significant int has int-number 0, the next int in order of
* increasing significance has int-number 1, and so forth.
- * @deprecated Deprecated since logical value is offset from stored
- * value and correction factor is applied in accessor method.
+ *
+ * <p>Note: never used for a BigInteger with a magnitude of zero.
+ *
+ * @see #firstNonzeroIntNum()
*/
- @Deprecated
- private int firstNonzeroIntNum;
+ private int firstNonzeroIntNumPlusTwo;
/**
* This mask is used to obtain the value of an int as if it were unsigned.
*/
- final static long LONG_MASK = 0xffffffffL;
+ static final long LONG_MASK = 0xffffffffL;
/**
* This constant limits {@code mag.length} of BigIntegers to the supported
@@ -290,24 +281,41 @@
// Constructors
/**
- * Translates a byte array containing the two's-complement binary
- * representation of a BigInteger into a BigInteger. The input array is
+ * Translates a byte sub-array containing the two's-complement binary
+ * representation of a BigInteger into a BigInteger. The sub-array is
+ * specified via an offset into the array and a length. The sub-array is
* assumed to be in <i>big-endian</i> byte-order: the most significant
- * byte is in the zeroth element.
+ * byte is the element at index {@code off}. The {@code val} array is
+ * assumed to be unchanged for the duration of the constructor call.
*
- * @param val big-endian two's-complement binary representation of
- * BigInteger.
+ * An {@code IndexOutOfBoundsException} is thrown if the length of the array
+ * {@code val} is non-zero and either {@code off} is negative, {@code len}
+ * is negative, or {@code off+len} is greater than the length of
+ * {@code val}.
+ *
+ * @param val byte array containing a sub-array which is the big-endian
+ * two's-complement binary representation of a BigInteger.
+ * @param off the start offset of the binary representation.
+ * @param len the number of bytes to use.
* @throws NumberFormatException {@code val} is zero bytes long.
+ * @throws IndexOutOfBoundsException if the provided array offset and
+ * length would cause an index into the byte array to be
+ * negative or greater than or equal to the array length.
+ * @since 9
*/
- public BigInteger(byte[] val) {
- if (val.length == 0)
+ public BigInteger(byte[] val, int off, int len) {
+ if (val.length == 0) {
throw new NumberFormatException("Zero length BigInteger");
+ } else if ((off < 0) || (off >= val.length) || (len < 0) ||
+ (len > val.length - off)) { // 0 <= off < val.length
+ throw new IndexOutOfBoundsException();
+ }
- if (val[0] < 0) {
- mag = makePositive(val);
+ if (val[off] < 0) {
+ mag = makePositive(val, off, len);
signum = -1;
} else {
- mag = stripLeadingZeroBytes(val);
+ mag = stripLeadingZeroBytes(val, off, len);
signum = (mag.length == 0 ? 0 : 1);
}
if (mag.length >= MAX_MAG_LENGTH) {
@@ -316,10 +324,27 @@
}
/**
+ * Translates a byte array containing the two's-complement binary
+ * representation of a BigInteger into a BigInteger. The input array is
+ * assumed to be in <i>big-endian</i> byte-order: the most significant
+ * byte is in the zeroth element. The {@code val} array is assumed to be
+ * unchanged for the duration of the constructor call.
+ *
+ * @param val big-endian two's-complement binary representation of a
+ * BigInteger.
+ * @throws NumberFormatException {@code val} is zero bytes long.
+ */
+ public BigInteger(byte[] val) {
+ this(val, 0, val.length);
+ }
+
+ /**
* This private constructor translates an int array containing the
* two's-complement binary representation of a BigInteger into a
* BigInteger. The input array is assumed to be in <i>big-endian</i>
- * int-order: the most significant int is in the zeroth element.
+ * int-order: the most significant int is in the zeroth element. The
+ * {@code val} array is assumed to be unchanged for the duration of
+ * the constructor call.
*/
private BigInteger(int[] val) {
if (val.length == 0)
@@ -340,24 +365,44 @@
/**
* Translates the sign-magnitude representation of a BigInteger into a
* BigInteger. The sign is represented as an integer signum value: -1 for
- * negative, 0 for zero, or 1 for positive. The magnitude is a byte array
- * in <i>big-endian</i> byte-order: the most significant byte is in the
- * zeroth element. A zero-length magnitude array is permissible, and will
- * result in a BigInteger value of 0, whether signum is -1, 0 or 1.
+ * negative, 0 for zero, or 1 for positive. The magnitude is a sub-array of
+ * a byte array in <i>big-endian</i> byte-order: the most significant byte
+ * is the element at index {@code off}. A zero value of the length
+ * {@code len} is permissible, and will result in a BigInteger value of 0,
+ * whether signum is -1, 0 or 1. The {@code magnitude} array is assumed to
+ * be unchanged for the duration of the constructor call.
+ *
+ * An {@code IndexOutOfBoundsException} is thrown if the length of the array
+ * {@code magnitude} is non-zero and either {@code off} is negative,
+ * {@code len} is negative, or {@code off+len} is greater than the length of
+ * {@code magnitude}.
*
* @param signum signum of the number (-1 for negative, 0 for zero, 1
* for positive).
* @param magnitude big-endian binary representation of the magnitude of
* the number.
+ * @param off the start offset of the binary representation.
+ * @param len the number of bytes to use.
* @throws NumberFormatException {@code signum} is not one of the three
* legal values (-1, 0, and 1), or {@code signum} is 0 and
* {@code magnitude} contains one or more non-zero bytes.
+ * @throws IndexOutOfBoundsException if the provided array offset and
+ * length would cause an index into the byte array to be
+ * negative or greater than or equal to the array length.
+ * @since 9
*/
- public BigInteger(int signum, byte[] magnitude) {
- this.mag = stripLeadingZeroBytes(magnitude);
-
- if (signum < -1 || signum > 1)
+ public BigInteger(int signum, byte[] magnitude, int off, int len) {
+ if (signum < -1 || signum > 1) {
throw(new NumberFormatException("Invalid signum value"));
+ } else if ((off < 0) || (len < 0) ||
+ (len > 0 &&
+ ((off >= magnitude.length) ||
+ (len > magnitude.length - off)))) { // 0 <= off < magnitude.length
+ throw new IndexOutOfBoundsException();
+ }
+
+ // stripLeadingZeroBytes() returns a zero length array if len == 0
+ this.mag = stripLeadingZeroBytes(magnitude, off, len);
if (this.mag.length == 0) {
this.signum = 0;
@@ -372,10 +417,33 @@
}
/**
+ * Translates the sign-magnitude representation of a BigInteger into a
+ * BigInteger. The sign is represented as an integer signum value: -1 for
+ * negative, 0 for zero, or 1 for positive. The magnitude is a byte array
+ * in <i>big-endian</i> byte-order: the most significant byte is the
+ * zeroth element. A zero-length magnitude array is permissible, and will
+ * result in a BigInteger value of 0, whether signum is -1, 0 or 1. The
+ * {@code magnitude} array is assumed to be unchanged for the duration of
+ * the constructor call.
+ *
+ * @param signum signum of the number (-1 for negative, 0 for zero, 1
+ * for positive).
+ * @param magnitude big-endian binary representation of the magnitude of
+ * the number.
+ * @throws NumberFormatException {@code signum} is not one of the three
+ * legal values (-1, 0, and 1), or {@code signum} is 0 and
+ * {@code magnitude} contains one or more non-zero bytes.
+ */
+ public BigInteger(int signum, byte[] magnitude) {
+ this(signum, magnitude, 0, magnitude.length);
+ }
+
+ /**
* A constructor for internal use that translates the sign-magnitude
* representation of a BigInteger into a BigInteger. It checks the
* arguments and copies the magnitude so this constructor would be
- * safe for external use.
+ * safe for external use. The {@code magnitude} array is assumed to be
+ * unchanged for the duration of the constructor call.
*/
private BigInteger(int signum, int[] magnitude) {
this.mag = stripLeadingZeroInts(magnitude);
@@ -492,7 +560,9 @@
/*
* Constructs a new BigInteger using a char array with radix=10.
- * Sign is precalculated outside and not allowed in the val.
+ * Sign is precalculated outside and not allowed in the val. The {@code val}
+ * array is assumed to be unchanged for the duration of the constructor
+ * call.
*/
BigInteger(char[] val, int sign, int len) {
int cursor = 0, numDigits;
@@ -644,7 +714,7 @@
* Constructs a randomly generated positive BigInteger that is probably
* prime, with the specified bitLength.
*
- * <p>It is recommended that the {@link #probablePrime probablePrime}
+ * @apiNote It is recommended that the {@link #probablePrime probablePrime}
* method be used in preference to this constructor unless there
* is a compelling need to specify a certainty.
*
@@ -1060,11 +1130,12 @@
/**
* This private constructor is for internal use and assumes that its
- * arguments are correct.
+ * arguments are correct. The {@code magnitude} array is assumed to be
+ * unchanged for the duration of the constructor call.
*/
private BigInteger(byte[] magnitude, int signum) {
this.signum = (magnitude.length == 0 ? 0 : signum);
- this.mag = stripLeadingZeroBytes(magnitude);
+ this.mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length);
if (mag.length >= MAX_MAG_LENGTH) {
checkRange();
}
@@ -1090,9 +1161,11 @@
/**
* Returns a BigInteger whose value is equal to that of the
- * specified {@code long}. This "static factory method" is
- * provided in preference to a ({@code long}) constructor
- * because it allows for reuse of frequently used BigIntegers.
+ * specified {@code long}.
+ *
+ * @apiNote This static factory method is provided in preference
+ * to a ({@code long}) constructor because it allows for reuse of
+ * frequently used BigIntegers.
*
* @param val value of the BigInteger to return.
* @return a BigInteger with the specified value.
@@ -1145,7 +1218,7 @@
/**
* Initialize static constant array when class is loaded.
*/
- private final static int MAX_CONSTANT = 16;
+ private static final int MAX_CONSTANT = 16;
private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];
@@ -1163,14 +1236,6 @@
private static final double LOG_TWO = Math.log(2.0);
static {
- assert 0 < KARATSUBA_THRESHOLD
- && KARATSUBA_THRESHOLD < TOOM_COOK_THRESHOLD
- && TOOM_COOK_THRESHOLD < Integer.MAX_VALUE
- && 0 < KARATSUBA_SQUARE_THRESHOLD
- && KARATSUBA_SQUARE_THRESHOLD < TOOM_COOK_SQUARE_THRESHOLD
- && TOOM_COOK_SQUARE_THRESHOLD < Integer.MAX_VALUE :
- "Algorithm thresholds are inconsistent";
-
for (int i = 1; i <= MAX_CONSTANT; i++) {
int[] magnitude = new int[1];
magnitude[0] = i;
@@ -1207,9 +1272,11 @@
public static final BigInteger ONE = valueOf(1);
/**
- * The BigInteger constant two. (Not exported.)
+ * The BigInteger constant two.
+ *
+ * @since 9
*/
- private static final BigInteger TWO = valueOf(2);
+ public static final BigInteger TWO = valueOf(2);
/**
* The BigInteger constant -1. (Not exported.)
@@ -1492,18 +1559,6 @@
* @return {@code this * val}
*/
public BigInteger multiply(BigInteger val) {
- return multiply(val, false);
- }
-
- /**
- * Returns a BigInteger whose value is {@code (this * val)}. If
- * the invocation is recursive certain overflow checks are skipped.
- *
- * @param val value to be multiplied by this BigInteger.
- * @param isRecursion whether this is a recursive invocation
- * @return {@code this * val}
- */
- private BigInteger multiply(BigInteger val, boolean isRecursion) {
if (val.signum == 0 || signum == 0)
return ZERO;
@@ -1511,17 +1566,17 @@
// BEGIN Android-changed: Fall back to the boringssl implementation for
// large arguments.
- int ylen = val.mag.length;
-
final int BORINGSSL_MUL_THRESHOLD = 50;
+ if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD
+ && xlen < BORINGSSL_MUL_THRESHOLD) {
+ return square();
+ }
+
+ int ylen = val.mag.length;
+
int resultSign = signum == val.signum ? 1 : -1;
if ((xlen < BORINGSSL_MUL_THRESHOLD) || (ylen < BORINGSSL_MUL_THRESHOLD)) {
- if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD) {
- // Helps less than boringssl fallback; prefer that.
- return square();
- }
-
if (val.mag.length == 1) {
return multiplyByInt(mag,val.mag[0], resultSign);
}
@@ -1610,6 +1665,8 @@
return multiplyToomCook3(this, val);
}
*/
+ // END Android-changed: Fall back to the boringssl implementation for
+ // large arguments.
}
}
@@ -1682,11 +1739,19 @@
* the result into z. There will be no leading zeros in the resultant array.
*/
private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
+ multiplyToLenCheck(x, xlen);
+ multiplyToLenCheck(y, ylen);
+ return implMultiplyToLen(x, xlen, y, ylen, z);
+ }
+
+ // Android-removed: @HotSpotIntrinsicCandidate
+ // @HotSpotIntrinsicCandidate
+ private static int[] implMultiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
int xstart = xlen - 1;
int ystart = ylen - 1;
if (z == null || z.length < (xlen+ ylen))
- z = new int[xlen+ylen];
+ z = new int[xlen+ylen];
long carry = 0;
for (int j=ystart, k=ystart+1+xstart; j >= 0; j--, k--) {
@@ -1711,6 +1776,18 @@
return z;
}
+ private static void multiplyToLenCheck(int[] array, int length) {
+ if (length <= 0) {
+ return; // not an error because multiplyToLen won't execute if len <= 0
+ }
+
+ Objects.requireNonNull(array);
+
+ if (length > array.length) {
+ throw new ArrayIndexOutOfBoundsException(length - 1);
+ }
+ }
+
/**
* Multiplies two BigIntegers using the Karatsuba multiplication
* algorithm. This is a recursive divide-and-conquer algorithm which is
@@ -1808,16 +1885,16 @@
BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1;
- v0 = a0.multiply(b0, true);
+ v0 = a0.multiply(b0);
da1 = a2.add(a0);
db1 = b2.add(b0);
- vm1 = da1.subtract(a1).multiply(db1.subtract(b1), true);
+ vm1 = da1.subtract(a1).multiply(db1.subtract(b1));
da1 = da1.add(a1);
db1 = db1.add(b1);
- v1 = da1.multiply(db1, true);
+ v1 = da1.multiply(db1);
v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply(
- db1.add(b2).shiftLeft(1).subtract(b0), true);
- vinf = a2.multiply(b2, true);
+ db1.add(b2).shiftLeft(1).subtract(b0));
+ vinf = a2.multiply(b2);
// The algorithm requires two divisions by 2 and one by 3.
// All divisions are known to be exact, that is, they do not produce
@@ -1983,17 +2060,6 @@
* @return {@code this<sup>2</sup>}
*/
private BigInteger square() {
- return square(false);
- }
-
- /**
- * Returns a BigInteger whose value is {@code (this<sup>2</sup>)}. If
- * the invocation is recursive certain overflow checks are skipped.
- *
- * @param isRecursion whether this is a recursive invocation
- * @return {@code this<sup>2</sup>}
- */
- private BigInteger square(boolean isRecursion) {
if (signum == 0) {
return ZERO;
}
@@ -2006,15 +2072,6 @@
if (len < TOOM_COOK_SQUARE_THRESHOLD) {
return squareKaratsuba();
} else {
- //
- // For a discussion of overflow detection see multiply()
- //
- if (!isRecursion) {
- if (bitLength(mag, mag.length) > 16L*MAX_MAG_LENGTH) {
- reportOverflow();
- }
- }
-
return squareToomCook3();
}
}
@@ -2061,6 +2118,8 @@
/**
* Java Runtime may use intrinsic for this method.
*/
+ // Android-removed: @HotSpotIntrinsicCandidate
+ // @HotSpotIntrinsicCandidate
private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) {
/*
* The algorithm used here is adapted from Colin Plumb's C library.
@@ -2165,13 +2224,13 @@
a0 = getToomSlice(k, r, 2, len);
BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1;
- v0 = a0.square(true);
+ v0 = a0.square();
da1 = a2.add(a0);
- vm1 = da1.subtract(a1).square(true);
+ vm1 = da1.subtract(a1).square();
da1 = da1.add(a1);
- v1 = da1.square(true);
- vinf = a2.square(true);
- v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true);
+ v1 = da1.square();
+ vinf = a2.square();
+ v2 = da1.add(a2).shiftLeft(1).subtract(a0).square();
// The algorithm requires two divisions by 2 and one by 3.
// All divisions are known to be exact, that is, they do not produce
@@ -2196,7 +2255,7 @@
// Division
- // BEGIN Android-modified: Fall back to boringssl for large problems.
+ // BEGIN Android-changed: Fall back to boringssl for large problems.
private static final int BORINGSSL_DIV_THRESHOLD = 40;
private static final int BORINGSSL_DIV_OFFSET = 20;
@@ -2214,11 +2273,11 @@
mag.length - val.mag.length < BORINGSSL_DIV_OFFSET) {
return divideKnuth(val);
} else {
- return divideAndRemainder(val)[0];
// return divideBurnikelZiegler(val);
+ return divideAndRemainder(val)[0];
}
}
- // END Android-modified: Fall back to boringssl for large problems.
+ // END Android-changed: Fall back to boringssl for large problems.
/**
@@ -2250,15 +2309,19 @@
* @throws ArithmeticException if {@code val} is zero.
*/
public BigInteger[] divideAndRemainder(BigInteger val) {
- // BEGIN Android-modified: Fall back to boringssl for large problems.
-
- // if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
- // mag.length - val.mag < BURNIKEL_ZIEGLER_OFFSET) {
+ // BEGIN Android-changed: Fall back to boringssl for large problems.
+ /*
+ if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
+ mag.length - val.mag < BURNIKEL_ZIEGLER_OFFSET) {
+ */
if (val.mag.length < BORINGSSL_DIV_THRESHOLD ||
mag.length < BORINGSSL_DIV_OFFSET ||
mag.length - val.mag.length < BORINGSSL_DIV_OFFSET) {
return divideAndRemainderKnuth(val);
} else {
+ /*
+ return divideAndRemainderBurnikelZiegler(val);
+ */
int quotSign = signum == val.signum ? 1 : -1; // 0 divided doesn't get here.
long xBN = 0, yBN = 0, quotBN = 0, remBN = 0;
try {
@@ -2278,9 +2341,8 @@
NativeBN.BN_free(quotBN);
NativeBN.BN_free(remBN);
}
- // return divideAndRemainderBurnikelZiegler(val);
}
- // END Android-modified: Fall back to boringssl for large problems.
+ // END Android-changed: Fall back to boringssl for large problems.
}
/** Long division */
@@ -2304,17 +2366,19 @@
* @throws ArithmeticException if {@code val} is zero.
*/
public BigInteger remainder(BigInteger val) {
- // BEGIN Android-modified: Fall back to boringssl for large problems.
- // if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
- // mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) {
+ // BEGIN Android-changed: Fall back to boringssl for large problems.
+ /*
+ if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD ||
+ mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) {
+ */
if (val.mag.length < BORINGSSL_DIV_THRESHOLD ||
mag.length - val.mag.length < BORINGSSL_DIV_THRESHOLD) {
return remainderKnuth(val);
} else {
- return divideAndRemainder(val)[1];
// return remainderBurnikelZiegler(val);
+ return divideAndRemainder(val)[1];
}
- // END Android-modified: Fall back to boringssl for large problems.
+ // END Android-changed: Fall back to boringssl for large problems.
}
/** Long division */
@@ -2359,11 +2423,11 @@
}
/**
- * Returns a BigInteger whose value is <tt>(this<sup>exponent</sup>)</tt>.
+ * Returns a BigInteger whose value is <code>(this<sup>exponent</sup>)</code>.
* Note that {@code exponent} is an integer rather than a BigInteger.
*
* @param exponent exponent to which this BigInteger is to be raised.
- * @return <tt>this<sup>exponent</sup></tt>
+ * @return <code>this<sup>exponent</sup></code>
* @throws ArithmeticException {@code exponent} is negative. (This would
* cause the operation to yield a non-integer value.)
*/
@@ -2382,11 +2446,10 @@
// The remaining part can then be exponentiated faster. The
// powers of two will be multiplied back at the end.
int powersOfTwo = partToSquare.getLowestSetBit();
- long bitsToShiftLong = (long)powersOfTwo * exponent;
- if (bitsToShiftLong > Integer.MAX_VALUE) {
+ long bitsToShift = (long)powersOfTwo * exponent;
+ if (bitsToShift > Integer.MAX_VALUE) {
reportOverflow();
}
- int bitsToShift = (int)bitsToShiftLong;
int remainingBits;
@@ -2396,9 +2459,9 @@
remainingBits = partToSquare.bitLength();
if (remainingBits == 1) { // Nothing left but +/- 1?
if (signum < 0 && (exponent&1) == 1) {
- return NEGATIVE_ONE.shiftLeft(bitsToShift);
+ return NEGATIVE_ONE.shiftLeft(powersOfTwo*exponent);
} else {
- return ONE.shiftLeft(bitsToShift);
+ return ONE.shiftLeft(powersOfTwo*exponent);
}
}
} else {
@@ -2443,16 +2506,13 @@
if (bitsToShift + scaleFactor <= 62) { // Fits in long?
return valueOf((result << bitsToShift) * newSign);
} else {
- return valueOf(result*newSign).shiftLeft(bitsToShift);
+ return valueOf(result*newSign).shiftLeft((int) bitsToShift);
}
- } else {
+ }
+ else {
return valueOf(result*newSign);
}
} else {
- if ((long)bitLength() * exponent / Integer.SIZE > MAX_MAG_LENGTH) {
- reportOverflow();
- }
-
// Large number algorithm. This is basically identical to
// the algorithm above, but calls multiply() and square()
// which may use more efficient algorithms for large numbers.
@@ -2472,7 +2532,7 @@
// Multiply back the (exponentiated) powers of two (quickly,
// by shifting left)
if (powersOfTwo > 0) {
- answer = answer.shiftLeft(bitsToShift);
+ answer = answer.shiftLeft(powersOfTwo*exponent);
}
if (signum < 0 && (exponent&1) == 1) {
@@ -2484,6 +2544,53 @@
}
/**
+ * Returns the integer square root of this BigInteger. The integer square
+ * root of the corresponding mathematical integer {@code n} is the largest
+ * mathematical integer {@code s} such that {@code s*s <= n}. It is equal
+ * to the value of {@code floor(sqrt(n))}, where {@code sqrt(n)} denotes the
+ * real square root of {@code n} treated as a real. Note that the integer
+ * square root will be less than the real square root if the latter is not
+ * representable as an integral value.
+ *
+ * @return the integer square root of {@code this}
+ * @throws ArithmeticException if {@code this} is negative. (The square
+ * root of a negative integer {@code val} is
+ * {@code (i * sqrt(-val))} where <i>i</i> is the
+ * <i>imaginary unit</i> and is equal to
+ * {@code sqrt(-1)}.)
+ * @since 9
+ */
+ public BigInteger sqrt() {
+ if (this.signum < 0) {
+ throw new ArithmeticException("Negative BigInteger");
+ }
+
+ return new MutableBigInteger(this.mag).sqrt().toBigInteger();
+ }
+
+ /**
+ * Returns an array of two BigIntegers containing the integer square root
+ * {@code s} of {@code this} and its remainder {@code this - s*s},
+ * respectively.
+ *
+ * @return an array of two BigIntegers with the integer square root at
+ * offset 0 and the remainder at offset 1
+ * @throws ArithmeticException if {@code this} is negative. (The square
+ * root of a negative integer {@code val} is
+ * {@code (i * sqrt(-val))} where <i>i</i> is the
+ * <i>imaginary unit</i> and is equal to
+ * {@code sqrt(-1)}.)
+ * @see #sqrt()
+ * @since 9
+ */
+ public BigInteger[] sqrtAndRemainder() {
+ BigInteger s = sqrt();
+ BigInteger r = this.subtract(s.square());
+ assert r.compareTo(BigInteger.ZERO) >= 0;
+ return new BigInteger[] {s, r};
+ }
+
+ /**
* Returns a BigInteger whose value is the greatest common divisor of
* {@code abs(this)} and {@code abs(val)}. Returns 0 if
* {@code this == 0 && val == 0}.
@@ -2655,12 +2762,12 @@
/**
* Returns a BigInteger whose value is
- * <tt>(this<sup>exponent</sup> mod m)</tt>. (Unlike {@code pow}, this
+ * <code>(this<sup>exponent</sup> mod m)</code>. (Unlike {@code pow}, this
* method permits negative exponents.)
*
* @param exponent the exponent.
* @param m the modulus.
- * @return <tt>this<sup>exponent</sup> mod m</tt>
+ * @return <code>this<sup>exponent</sup> mod m</code>
* @throws ArithmeticException {@code m} ≤ 0 or the exponent is
* negative and this BigInteger is not <i>relatively
* prime</i> to {@code m}.
@@ -2814,13 +2921,17 @@
return z;
}
- // These methods are intended to be be replaced by virtual machine
+ // These methods are intended to be replaced by virtual machine
// intrinsics.
+ // Android-removed: @HotSpotIntrinsicCandidate
+ // @HotSpotIntrinsicCandidate
private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len,
long inv, int[] product) {
product = multiplyToLen(a, len, b, len, product);
return montReduce(product, n, len, (int)inv);
}
+ // Android-removed: @HotSpotIntrinsicCandidate
+ // @HotSpotIntrinsicCandidate
private static int[] implMontgomerySquare(int[] a, int[] n, int len,
long inv, int[] product) {
product = squareToLen(a, len, product);
@@ -3152,6 +3263,8 @@
/**
* Java Runtime may use intrinsic for this method.
*/
+ // Android-removed: @HotSpotIntrinsicCandidate
+ // @HotSpotIntrinsicCandidate
private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
long kLong = k & LONG_MASK;
long carry = 0;
@@ -3274,7 +3387,7 @@
* Returns a BigInteger whose value is {@code (this << n)}.
* The shift distance, {@code n}, may be negative, in which case
* this method performs a right shift.
- * (Computes <tt>floor(this * 2<sup>n</sup>)</tt>.)
+ * (Computes <code>floor(this * 2<sup>n</sup>)</code>.)
*
* @param n shift distance, in bits.
* @return {@code this << n}
@@ -3297,7 +3410,7 @@
/**
* Returns a magnitude array whose value is {@code (mag << n)}.
* The shift distance, {@code n}, is considered unnsigned.
- * (Computes <tt>this * 2<sup>n</sup></tt>.)
+ * (Computes <code>this * 2<sup>n</sup></code>.)
*
* @param mag magnitude, the most-significant int ({@code mag[0]}) must be non-zero.
* @param n unsigned shift distance, in bits.
@@ -3334,7 +3447,7 @@
* Returns a BigInteger whose value is {@code (this >> n)}. Sign
* extension is performed. The shift distance, {@code n}, may be
* negative, in which case this method performs a left shift.
- * (Computes <tt>floor(this / 2<sup>n</sup>)</tt>.)
+ * (Computes <code>floor(this / 2<sup>n</sup>)</code>.)
*
* @param n shift distance, in bits.
* @return {@code this >> n}
@@ -3357,7 +3470,7 @@
/**
* Returns a BigInteger whose value is {@code (this >> n)}. The shift
* distance, {@code n}, is considered unsigned.
- * (Computes <tt>floor(this * 2<sup>-n</sup>)</tt>.)
+ * (Computes <code>floor(this * 2<sup>-n</sup>)</code>.)
*
* @param n unsigned shift distance, in bits.
* @return {@code this >> n}
@@ -3602,7 +3715,7 @@
* @return index of the rightmost one bit in this BigInteger.
*/
public int getLowestSetBit() {
- @SuppressWarnings("deprecation") int lsb = lowestSetBit - 2;
+ int lsb = lowestSetBitPlusTwo - 2;
if (lsb == -2) { // lowestSetBit not initialized yet
lsb = 0;
if (signum == 0) {
@@ -3614,7 +3727,7 @@
;
lsb += (i << 5) + Integer.numberOfTrailingZeros(b);
}
- lowestSetBit = lsb + 2;
+ lowestSetBitPlusTwo = lsb + 2;
}
return lsb;
}
@@ -3624,16 +3737,16 @@
/**
* Returns the number of bits in the minimal two's-complement
- * representation of this BigInteger, <i>excluding</i> a sign bit.
+ * representation of this BigInteger, <em>excluding</em> a sign bit.
* For positive BigIntegers, this is equivalent to the number of bits in
- * the ordinary binary representation. (Computes
- * {@code (ceil(log2(this < 0 ? -this : this+1)))}.)
+ * the ordinary binary representation. For zero this method returns
+ * {@code 0}. (Computes {@code (ceil(log2(this < 0 ? -this : this+1)))}.)
*
* @return number of bits in the minimal two's-complement
- * representation of this BigInteger, <i>excluding</i> a sign bit.
+ * representation of this BigInteger, <em>excluding</em> a sign bit.
*/
public int bitLength() {
- @SuppressWarnings("deprecation") int n = bitLength - 1;
+ int n = bitLengthPlusOne - 1;
if (n == -1) { // bitLength not initialized yet
int[] m = mag;
int len = m.length;
@@ -3648,12 +3761,12 @@
for (int i=1; i< len && pow2; i++)
pow2 = (mag[i] == 0);
- n = (pow2 ? magBitLength - 1 : magBitLength);
+ n = (pow2 ? magBitLength -1 : magBitLength);
} else {
n = magBitLength;
}
}
- bitLength = n + 1;
+ bitLengthPlusOne = n + 1;
}
return n;
}
@@ -3667,7 +3780,7 @@
* of this BigInteger that differ from its sign bit.
*/
public int bitCount() {
- @SuppressWarnings("deprecation") int bc = bitCount - 1;
+ int bc = bitCountPlusOne - 1;
if (bc == -1) { // bitCount not initialized yet
bc = 0; // offset by one to initialize
// Count the bits in the magnitude
@@ -3681,7 +3794,7 @@
magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]);
bc += magTrailingZeroCount - 1;
}
- bitCount = bc + 1;
+ bitCountPlusOne = bc + 1;
}
return bc;
}
@@ -3973,7 +4086,7 @@
* Converts the specified BigInteger to a string and appends to
* {@code sb}. This implements the recursive Schoenhage algorithm
* for base conversions.
- * <p/>
+ * <p>
* See Knuth, Donald, _The Art of Computer Programming_, Vol. 2,
* Answers to Exercises (4.4) Question 14.
*
@@ -3984,16 +4097,16 @@
*/
private static void toString(BigInteger u, StringBuilder sb, int radix,
int digits) {
- /* If we're smaller than a certain threshold, use the smallToString
- method, padding with leading zeroes when necessary. */
+ // If we're smaller than a certain threshold, use the smallToString
+ // method, padding with leading zeroes when necessary.
if (u.mag.length <= SCHOENHAGE_BASE_CONVERSION_THRESHOLD) {
String s = u.smallToString(radix);
// Pad with internal zeros if necessary.
// Don't pad if we're at the beginning of the string.
if ((s.length() < digits) && (sb.length() > 0)) {
- for (int i=s.length(); i < digits; i++) { // May be a faster way to
- sb.append('0'); // do this?
+ for (int i=s.length(); i < digits; i++) {
+ sb.append('0');
}
}
@@ -4022,7 +4135,7 @@
/**
* Returns the value radix^(2^exponent) from the cache.
* If this value doesn't already exist in the cache, it is added.
- * <p/>
+ * <p>
* This could be changed to a more complicated caching method using
* {@code Future}.
*/
@@ -4107,7 +4220,7 @@
* Converts this BigInteger to an {@code int}. This
* conversion is analogous to a
* <i>narrowing primitive conversion</i> from {@code long} to
- * {@code int} as defined in section 5.1.3 of
+ * {@code int} as defined in
* <cite>The Java™ Language Specification</cite>:
* if this BigInteger is too big to fit in an
* {@code int}, only the low-order 32 bits are returned.
@@ -4117,6 +4230,7 @@
*
* @return this BigInteger converted to an {@code int}.
* @see #intValueExact()
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public int intValue() {
int result = 0;
@@ -4128,7 +4242,7 @@
* Converts this BigInteger to a {@code long}. This
* conversion is analogous to a
* <i>narrowing primitive conversion</i> from {@code long} to
- * {@code int} as defined in section 5.1.3 of
+ * {@code int} as defined in
* <cite>The Java™ Language Specification</cite>:
* if this BigInteger is too big to fit in a
* {@code long}, only the low-order 64 bits are returned.
@@ -4138,6 +4252,7 @@
*
* @return this BigInteger converted to a {@code long}.
* @see #longValueExact()
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public long longValue() {
long result = 0;
@@ -4151,7 +4266,7 @@
* Converts this BigInteger to a {@code float}. This
* conversion is similar to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code float} as defined in section 5.1.3 of
+ * {@code float} as defined in
* <cite>The Java™ Language Specification</cite>:
* if this BigInteger has too great a magnitude
* to represent as a {@code float}, it will be converted to
@@ -4161,6 +4276,7 @@
* information about the precision of the BigInteger value.
*
* @return this BigInteger converted to a {@code float}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public float floatValue() {
if (signum == 0) {
@@ -4235,7 +4351,7 @@
* Converts this BigInteger to a {@code double}. This
* conversion is similar to the
* <i>narrowing primitive conversion</i> from {@code double} to
- * {@code float} as defined in section 5.1.3 of
+ * {@code float} as defined in
* <cite>The Java™ Language Specification</cite>:
* if this BigInteger has too great a magnitude
* to represent as a {@code double}, it will be converted to
@@ -4245,6 +4361,7 @@
* information about the precision of the BigInteger value.
*
* @return this BigInteger converted to a {@code double}.
+ * @jls 5.1.3 Narrowing Primitive Conversion
*/
public double doubleValue() {
if (signum == 0) {
@@ -4353,18 +4470,18 @@
/**
* Returns a copy of the input array stripped of any leading zero bytes.
*/
- private static int[] stripLeadingZeroBytes(byte a[]) {
- int byteLength = a.length;
+ private static int[] stripLeadingZeroBytes(byte a[], int off, int len) {
+ int indexBound = off + len;
int keep;
// Find first nonzero byte
- for (keep = 0; keep < byteLength && a[keep] == 0; keep++)
+ for (keep = off; keep < indexBound && a[keep] == 0; keep++)
;
// Allocate new array and copy relevant part of input array
- int intLength = ((byteLength - keep) + 3) >>> 2;
+ int intLength = ((indexBound - keep) + 3) >>> 2;
int[] result = new int[intLength];
- int b = byteLength - 1;
+ int b = indexBound - 1;
for (int i = intLength-1; i >= 0; i--) {
result[i] = a[b--] & 0xff;
int bytesRemaining = b - keep + 1;
@@ -4379,27 +4496,27 @@
* Takes an array a representing a negative 2's-complement number and
* returns the minimal (no leading zero bytes) unsigned whose value is -a.
*/
- private static int[] makePositive(byte a[]) {
+ private static int[] makePositive(byte a[], int off, int len) {
int keep, k;
- int byteLength = a.length;
+ int indexBound = off + len;
// Find first non-sign (0xff) byte of input
- for (keep=0; keep < byteLength && a[keep] == -1; keep++)
+ for (keep=off; keep < indexBound && a[keep] == -1; keep++)
;
/* Allocate output array. If all non-sign bytes are 0x00, we must
* allocate space for one extra output byte. */
- for (k=keep; k < byteLength && a[k] == 0; k++)
+ for (k=keep; k < indexBound && a[k] == 0; k++)
;
- int extraByte = (k == byteLength) ? 1 : 0;
- int intLength = ((byteLength - keep + extraByte) + 3) >>> 2;
+ int extraByte = (k == indexBound) ? 1 : 0;
+ int intLength = ((indexBound - keep + extraByte) + 3) >>> 2;
int result[] = new int[intLength];
/* Copy one's complement of input into output, leaving extra
* byte (if it exists) == 0x00 */
- int b = byteLength - 1;
+ int b = indexBound - 1;
for (int i = intLength-1; i >= 0; i--) {
result[i] = a[b--] & 0xff;
int numBytesToTransfer = Math.min(3, b-keep+1);
@@ -4547,22 +4664,23 @@
}
/**
- * Returns the index of the int that contains the first nonzero int in the
- * little-endian binary representation of the magnitude (int 0 is the
- * least significant). If the magnitude is zero, return value is undefined.
- */
+ * Returns the index of the int that contains the first nonzero int in the
+ * little-endian binary representation of the magnitude (int 0 is the
+ * least significant). If the magnitude is zero, return value is undefined.
+ *
+ * <p>Note: never used for a BigInteger with a magnitude of zero.
+ * @see #getInt.
+ */
private int firstNonzeroIntNum() {
- int fn = firstNonzeroIntNum - 2;
+ int fn = firstNonzeroIntNumPlusTwo - 2;
if (fn == -2) { // firstNonzeroIntNum not initialized yet
- fn = 0;
-
// Search for the first nonzero int
int i;
int mlen = mag.length;
for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
;
fn = mlen - i - 1;
- firstNonzeroIntNum = fn + 2; // offset by two to initialize
+ firstNonzeroIntNumPlusTwo = fn + 2; // offset by two to initialize
}
return fn;
}
@@ -4574,16 +4692,17 @@
* Serializable fields for BigInteger.
*
* @serialField signum int
- * signum of this BigInteger.
- * @serialField magnitude int[]
- * magnitude array of this BigInteger.
+ * signum of this BigInteger
+ * @serialField magnitude byte[]
+ * magnitude array of this BigInteger
* @serialField bitCount int
- * number of bits in this BigInteger
+ * appears in the serialized form for backward compatibility
* @serialField bitLength int
- * the number of bits in the minimal two's-complement
- * representation of this BigInteger
+ * appears in the serialized form for backward compatibility
+ * @serialField firstNonzeroByteNum int
+ * appears in the serialized form for backward compatibility
* @serialField lowestSetBit int
- * lowest set bit in the twos complement representation
+ * appears in the serialized form for backward compatibility
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("signum", Integer.TYPE),
@@ -4600,22 +4719,14 @@
* for historical reasons, but it is converted to an array of ints
* and the byte array is discarded.
* Note:
- * The current convention is to initialize the cache fields, bitCount,
- * bitLength and lowestSetBit, to 0 rather than some other marker value.
- * Therefore, no explicit action to set these fields needs to be taken in
- * readObject because those fields already have a 0 value be default since
- * defaultReadObject is not being used.
+ * The current convention is to initialize the cache fields, bitCountPlusOne,
+ * bitLengthPlusOne and lowestSetBitPlusTwo, to 0 rather than some other
+ * marker value. Therefore, no explicit action to set these fields needs to
+ * be taken in readObject because those fields already have a 0 value by
+ * default since defaultReadObject is not being used.
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
- /*
- * In order to maintain compatibility with previous serialized forms,
- * the magnitude of a BigInteger is serialized as an array of bytes.
- * The magnitude field is used as a temporary store for the byte array
- * that is deserialized. The cached computation fields should be
- * transient but are serialized for compatibility reasons.
- */
-
// prepare to read the alternate persistent fields
ObjectInputStream.GetField fields = s.readFields();
@@ -4630,7 +4741,7 @@
message = "BigInteger: Signum not present in stream";
throw new java.io.StreamCorruptedException(message);
}
- int[] mag = stripLeadingZeroBytes(magnitude);
+ int[] mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length);
if ((mag.length == 0) != (sign == 0)) {
String message = "BigInteger: signum-magnitude mismatch";
if (fields.defaulted("magnitude"))
@@ -4679,12 +4790,14 @@
}
/**
- * Save the {@code BigInteger} instance to a stream.
- * The magnitude of a BigInteger is serialized as a byte array for
- * historical reasons.
- *
- * @serialData two necessary fields are written as well as obsolete
- * fields for compatibility with older versions.
+ * Save the {@code BigInteger} instance to a stream. The magnitude of a
+ * {@code BigInteger} is serialized as a byte array for historical reasons.
+ * To maintain compatibility with older implementations, the integers
+ * -1, -1, -2, and -2 are written as the values of the obsolete fields
+ * {@code bitCount}, {@code bitLength}, {@code lowestSetBit}, and
+ * {@code firstNonzeroByteNum}, respectively. These values are compatible
+ * with older implementations, but will be ignored by current
+ * implementations.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
// set the values of the Serializable fields
@@ -4694,15 +4807,17 @@
// The values written for cached fields are compatible with older
// versions, but are ignored in readObject so don't otherwise matter.
// BEGIN Android-changed: Don't include the following fields.
- // fields.put("bitCount", -1);
- // fields.put("bitLength", -1);
- // fields.put("lowestSetBit", -2);
- // fields.put("firstNonzeroByteNum", -2);
- // END Android-changed
+ /*
+ fields.put("bitCount", -1);
+ fields.put("bitLength", -1);
+ fields.put("lowestSetBit", -2);
+ fields.put("firstNonzeroByteNum", -2);
+ */
+ // END Android-changed: Don't include the following fields.
// save them
s.writeFields();
-}
+ }
/**
* Returns the mag array as an array of bytes.
@@ -4755,7 +4870,7 @@
*
* @return this {@code BigInteger} converted to an {@code int}.
* @throws ArithmeticException if the value of {@code this} will
- * not exactly fit in a {@code int}.
+ * not exactly fit in an {@code int}.
* @see BigInteger#intValue
* @since 1.8
*/
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java
index 0de212d..d389df3 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.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,7 +26,14 @@
package java.nio.channels.spi;
import java.io.IOException;
-import java.nio.channels.*;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.IllegalSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
/**
@@ -67,8 +74,8 @@
// Lock for registration and configureBlocking operations
private final Object regLock = new Object();
- // Blocking mode, protected by regLock
- boolean blocking = true;
+ // True when non-blocking, need regLock to change;
+ private volatile boolean nonBlocking;
/**
* Initializes a new instance of this class.
@@ -101,7 +108,7 @@
if (keys[i] == null)
break;
} else if (keys == null) {
- keys = new SelectionKey[3];
+ keys = new SelectionKey[2];
} else {
// Grow key array
int n = keys.length * 2;
@@ -116,14 +123,14 @@
}
private SelectionKey findKey(Selector sel) {
- synchronized (keyLock) {
- if (keys == null)
- return null;
- for (int i = 0; i < keys.length; i++)
- if ((keys[i] != null) && (keys[i].selector() == sel))
- return keys[i];
+ assert Thread.holdsLock(keyLock);
+ if (keys == null)
return null;
- }
+ for (int i = 0; i < keys.length; i++)
+ if ((keys[i] != null) && (keys[i].selector() == sel))
+ return keys[i];
+ return null;
+
}
void removeKey(SelectionKey k) { // package-private
@@ -159,7 +166,9 @@
}
public final SelectionKey keyFor(Selector sel) {
- return findKey(sel);
+ synchronized (keyLock) {
+ return findKey(sel);
+ }
}
/**
@@ -188,32 +197,31 @@
*
* @throws IllegalArgumentException {@inheritDoc}
*/
- public final SelectionKey register(Selector sel, int ops,
- Object att)
+ public final SelectionKey register(Selector sel, int ops, Object att)
throws ClosedChannelException
{
+ if ((ops & ~validOps()) != 0)
+ throw new IllegalArgumentException();
+ if (!isOpen())
+ throw new ClosedChannelException();
synchronized (regLock) {
- if (!isOpen())
- throw new ClosedChannelException();
- if ((ops & ~validOps()) != 0)
- throw new IllegalArgumentException();
- if (blocking)
+ if (isBlocking())
throw new IllegalBlockingModeException();
- SelectionKey k = findKey(sel);
- if (k != null) {
- k.interestOps(ops);
- k.attach(att);
- }
- if (k == null) {
- // New registration
- synchronized (keyLock) {
- if (!isOpen())
- throw new ClosedChannelException();
+ synchronized (keyLock) {
+ // re-check if channel has been closed
+ if (!isOpen())
+ throw new ClosedChannelException();
+ SelectionKey k = findKey(sel);
+ if (k != null) {
+ k.attach(att);
+ k.interestOps(ops);
+ } else {
+ // New registration
k = ((AbstractSelector)sel).register(this, ops, att);
addKey(k);
}
+ return k;
}
- return k;
}
}
@@ -232,12 +240,20 @@
*/
protected final void implCloseChannel() throws IOException {
implCloseSelectableChannel();
+
+ // clone keys to avoid calling cancel when holding keyLock
+ SelectionKey[] copyOfKeys = null;
synchronized (keyLock) {
- int count = (keys == null) ? 0 : keys.length;
- for (int i = 0; i < count; i++) {
- SelectionKey k = keys[i];
- if (k != null)
- k.cancel();
+ if (keys != null) {
+ copyOfKeys = keys.clone();
+ }
+ }
+
+ if (copyOfKeys != null) {
+ for (SelectionKey k : copyOfKeys) {
+ if (k != null) {
+ k.cancel(); // invalidate and adds key to cancelledKey set
+ }
}
}
}
@@ -264,9 +280,7 @@
// -- Blocking --
public final boolean isBlocking() {
- synchronized (regLock) {
- return blocking;
- }
+ return !nonBlocking;
}
public final Object blockingLock() {
@@ -287,12 +301,13 @@
synchronized (regLock) {
if (!isOpen())
throw new ClosedChannelException();
- if (blocking == block)
- return this;
- if (block && haveValidKeys())
- throw new IllegalBlockingModeException();
- implConfigureBlocking(block);
- blocking = block;
+ boolean blocking = !nonBlocking;
+ if (block != blocking) {
+ if (block && haveValidKeys())
+ throw new IllegalBlockingModeException();
+ implConfigureBlocking(block);
+ nonBlocking = !block;
+ }
}
return this;
}
@@ -305,8 +320,8 @@
* changing the blocking mode. This method is only invoked if the new mode
* is different from the current mode. </p>
*
- * @param block If <tt>true</tt> then this channel will be placed in
- * blocking mode; if <tt>false</tt> then it will be placed
+ * @param block If {@code true} then this channel will be placed in
+ * blocking mode; if {@code false} then it will be placed
* non-blocking mode
*
* @throws IOException
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java
index 09e3b61..9aab22f 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -43,9 +43,9 @@
* after, respectively, invoking an I/O operation that might block
* indefinitely. In order to ensure that the {@link #end end} method is always
* invoked, these methods should be used within a
- * <tt>try</tt> ... <tt>finally</tt> block:
+ * {@code try} ... {@code finally} block:
*
- * <blockquote><pre>
+ * <blockquote><pre id="be">
* try {
* begin();
* // Perform blocking I/O operation here
@@ -70,7 +70,7 @@
extends Selector
{
- private AtomicBoolean selectorOpen = new AtomicBoolean(true);
+ private final AtomicBoolean selectorOpen = new AtomicBoolean(true);
// The provider that created this selector
private final SelectorProvider provider;
@@ -197,7 +197,7 @@
* Marks the beginning of an I/O operation that might block indefinitely.
*
* <p> This method should be invoked in tandem with the {@link #end end}
- * method, using a <tt>try</tt> ... <tt>finally</tt> block as
+ * method, using a {@code try} ... {@code finally} block as
* shown <a href="#be">above</a>, in order to implement interruption for
* this selector.
*
@@ -223,7 +223,7 @@
* Marks the end of an I/O operation that might block indefinitely.
*
* <p> This method should be invoked in tandem with the {@link #begin begin}
- * method, using a <tt>try</tt> ... <tt>finally</tt> block as
+ * method, using a {@code try} ... {@code finally} block as
* shown <a href="#be">above</a>, in order to implement interruption for
* this selector. </p>
*/
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java b/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
index 464b4fc..6a77d3d 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
@@ -64,7 +64,7 @@
*
* @throws SecurityException
* If a security manager has been installed and it denies
- * {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt>
+ * {@link RuntimePermission}{@code ("asynchronousChannelProvider")}
*/
protected AsynchronousChannelProvider() {
this(checkPermission());
@@ -76,7 +76,7 @@
private static AsynchronousChannelProvider load() {
return AccessController
- .doPrivileged(new PrivilegedAction<AsynchronousChannelProvider>() {
+ .doPrivileged(new PrivilegedAction<>() {
public AsynchronousChannelProvider run() {
AsynchronousChannelProvider p;
p = loadProviderFromProperty();
@@ -94,9 +94,10 @@
if (cn == null)
return null;
try {
- Class<?> c = Class.forName(cn, true,
- ClassLoader.getSystemClassLoader());
- return (AsynchronousChannelProvider)c.newInstance();
+ @SuppressWarnings("deprecation")
+ Object tmp = Class.forName(cn, true,
+ ClassLoader.getSystemClassLoader()).newInstance();
+ return (AsynchronousChannelProvider)tmp;
} catch (ClassNotFoundException x) {
throw new ServiceConfigurationError(null, x);
} catch (IllegalAccessException x) {
@@ -137,7 +138,7 @@
* <ol>
*
* <li><p> If the system property
- * <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> is defined
+ * {@code java.nio.channels.spi.AsynchronousChannelProvider} is defined
* then it is taken to be the fully-qualified name of a concrete provider class.
* The class is loaded and instantiated; if this process fails then an
* unspecified error is thrown. </p></li>
@@ -145,8 +146,8 @@
* <li><p> If a provider class has been installed in a jar file that is
* visible to the system class loader, and that jar file contains a
* provider-configuration file named
- * <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> in the resource
- * directory <tt>META-INF/services</tt>, then the first class name
+ * {@code java.nio.channels.spi.AsynchronousChannelProvider} in the resource
+ * directory {@code META-INF/services}, then the first class name
* specified in that file is taken. The class is loaded and
* instantiated; if this process fails then an unspecified error is
* thrown. </p></li>
diff --git a/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java b/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java
index 2dbef05..c162eed 100644
--- a/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java
+++ b/ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java
@@ -46,7 +46,7 @@
* #provider() provider} method. The first invocation of that method will locate
* the default provider as specified below.
*
- * <p> The system-wide default provider is used by the static <tt>open</tt>
+ * <p> The system-wide default provider is used by the static {@code open}
* methods of the {@link java.nio.channels.DatagramChannel#open
* DatagramChannel}, {@link java.nio.channels.Pipe#open Pipe}, {@link
* java.nio.channels.Selector#open Selector}, {@link
@@ -54,7 +54,7 @@
* java.nio.channels.SocketChannel#open SocketChannel} classes. It is also
* used by the {@link java.lang.System#inheritedChannel System.inheritedChannel()}
* method. A program may make use of a provider other than the default provider
- * by instantiating that provider and then directly invoking the <tt>open</tt>
+ * by instantiating that provider and then directly invoking the {@code open}
* methods defined in this class.
*
* <p> All of the methods in this class are safe for use by multiple concurrent
@@ -71,17 +71,23 @@
private static final Object lock = new Object();
private static SelectorProvider provider = null;
+ private static Void checkPermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new RuntimePermission("selectorProvider"));
+ return null;
+ }
+ private SelectorProvider(Void ignore) { }
+
/**
* Initializes a new instance of this class.
*
* @throws SecurityException
* If a security manager has been installed and it denies
- * {@link RuntimePermission}<tt>("selectorProvider")</tt>
+ * {@link RuntimePermission}{@code ("selectorProvider")}
*/
protected SelectorProvider() {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkPermission(new RuntimePermission("selectorProvider"));
+ this(checkPermission());
}
private static boolean loadProviderFromProperty() {
@@ -89,9 +95,10 @@
if (cn == null)
return false;
try {
- Class<?> c = Class.forName(cn, true,
- ClassLoader.getSystemClassLoader());
- provider = (SelectorProvider)c.newInstance();
+ @SuppressWarnings("deprecation")
+ Object tmp = Class.forName(cn, true,
+ ClassLoader.getSystemClassLoader()).newInstance();
+ provider = (SelectorProvider)tmp;
return true;
} catch (ClassNotFoundException x) {
throw new ServiceConfigurationError(null, x);
@@ -136,7 +143,7 @@
* <ol>
*
* <li><p> If the system property
- * <tt>java.nio.channels.spi.SelectorProvider</tt> is defined then it is
+ * {@code java.nio.channels.spi.SelectorProvider} is defined then it is
* taken to be the fully-qualified name of a concrete provider class.
* The class is loaded and instantiated; if this process fails then an
* unspecified error is thrown. </p></li>
@@ -144,8 +151,8 @@
* <li><p> If a provider class has been installed in a jar file that is
* visible to the system class loader, and that jar file contains a
* provider-configuration file named
- * <tt>java.nio.channels.spi.SelectorProvider</tt> in the resource
- * directory <tt>META-INF/services</tt>, then the first class name
+ * {@code java.nio.channels.spi.SelectorProvider} in the resource
+ * directory {@code META-INF/services}, then the first class name
* specified in that file is taken. The class is loaded and
* instantiated; if this process fails then an unspecified error is
* thrown. </p></li>
@@ -166,7 +173,7 @@
if (provider != null)
return provider;
return AccessController.doPrivileged(
- new PrivilegedAction<SelectorProvider>() {
+ new PrivilegedAction<>() {
public SelectorProvider run() {
if (loadProviderFromProperty())
return provider;
@@ -299,14 +306,14 @@
* returned. Subsequent invocations of this method return the same
* channel. </p>
*
- * @return The inherited channel, if any, otherwise <tt>null</tt>.
+ * @return The inherited channel, if any, otherwise {@code null}.
*
* @throws IOException
* If an I/O error occurs
*
* @throws SecurityException
* If a security manager has been installed and it denies
- * {@link RuntimePermission}<tt>("inheritedChannel")</tt>
+ * {@link RuntimePermission}{@code ("inheritedChannel")}
*
* @since 1.5
*/
diff --git a/ojluni/src/main/java/java/nio/file/FileStore.java b/ojluni/src/main/java/java/nio/file/FileStore.java
index 2b14a4b..06d4f11 100644
--- a/ojluni/src/main/java/java/nio/file/FileStore.java
+++ b/ojluni/src/main/java/java/nio/file/FileStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -112,6 +112,31 @@
public abstract long getUsableSpace() throws IOException;
/**
+ * Returns the number of bytes per block in this file store.
+ *
+ * <p> File storage is typically organized into discrete sequences of bytes
+ * called <i>blocks</i>. A block is the smallest storage unit of a file store.
+ * Every read and write operation is performed on a multiple of blocks.
+ *
+ * @implSpec The implementation in this class throws an
+ * {@code UnsupportedOperationException}.
+ *
+ * @return a positive value representing the block size of this file store,
+ * in bytes
+ *
+ * @throws IOException
+ * if an I/O error occurs
+ *
+ * @throws UnsupportedOperationException
+ * if the operation is not supported
+ *
+ * @since 10
+ */
+ public long getBlockSize() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Returns the number of unallocated bytes in the file store.
*
* <p> The returned number of unallocated bytes is a hint, but not a
@@ -208,7 +233,7 @@
* @param attribute
* the attribute to read
- * @return the attribute value; {@code null} may be a valid valid for some
+ * @return the attribute value; {@code null} may be valid for some
* attributes
*
* @throws UnsupportedOperationException
diff --git a/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java b/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java
new file mode 100644
index 0000000..d8b0548
--- /dev/null
+++ b/ojluni/src/main/java/java/security/cert/URICertStoreParameters.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 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
+ * 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.security.cert;
+
+import java.net.URI;
+
+/**
+ * Parameters used as input for {@code CertStore} algorithms which use
+ * information contained in a URI to retrieve certificates and CRLs.
+ * <p>
+ * This class is used to provide necessary configuration parameters
+ * through a URI as defined in RFC 5280 to implementations of
+ * {@code CertStore} algorithms.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @since 9
+ * @see CertStore
+ * @see java.net.URI
+ */
+public final class URICertStoreParameters implements CertStoreParameters {
+
+ /**
+ * The uri, cannot be null
+ */
+ private final URI uri;
+
+ /*
+ * Hash code for this parameters.
+ */
+ private int myhash = -1;
+
+ /**
+ * Creates an instance of {@code URICertStoreParameters} with the
+ * specified URI.
+ *
+ * @param uri the URI which contains configuration information.
+ * @throws NullPointerException if {@code uri} is null
+ */
+ public URICertStoreParameters(URI uri) {
+ if (uri == null) {
+ throw new NullPointerException();
+ }
+ this.uri = uri;
+ }
+
+ /**
+ * Returns the URI used to construct this
+ * {@code URICertStoreParameters} object.
+ *
+ * @return the URI.
+ */
+ public URI getURI() {
+ return uri;
+ }
+
+ /**
+ * Returns a copy of this object. Changes to the copy will not affect
+ * the original and vice versa.
+ *
+ * @return the copy
+ */
+ @Override
+ public URICertStoreParameters clone() {
+ try {
+ return new URICertStoreParameters(uri);
+ } catch (NullPointerException e) {
+ /* Cannot happen */
+ throw new InternalError(e.toString(), e);
+ }
+ }
+
+ /**
+ * Returns a hash code value for this parameters object.
+ * The hash code is generated using the URI supplied at construction.
+ *
+ * @return a hash code value for this parameters.
+ */
+ @Override
+ public int hashCode() {
+ if (myhash == -1) {
+ myhash = uri.hashCode()*7;
+ }
+ return myhash;
+ }
+
+ /**
+ * Compares the specified object with this parameters object for equality.
+ * Two URICertStoreParameters are considered equal if the URIs used
+ * to construct them are equal.
+ *
+ * @param p the object to test for equality with this parameters.
+ *
+ * @return true if the specified object is equal to this parameters object.
+ */
+ @Override
+ public boolean equals(Object p) {
+ if (p == null || (!(p instanceof URICertStoreParameters))) {
+ return false;
+ }
+
+ if (p == this) {
+ return true;
+ }
+
+ URICertStoreParameters other = (URICertStoreParameters)p;
+ return uri.equals(other.getURI());
+ }
+
+ /**
+ * Returns a formatted string describing the parameters
+ * including the URI used to construct this object.
+ *
+ * @return a formatted string describing the parameters
+ */
+ @Override
+ public String toString() {
+ return "URICertStoreParameters: " + uri.toString();
+ }
+}
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index 8cd8aaf..05a0893 100644
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/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, 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,9 @@
package java.util;
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.util.ArraysSupport;
+
import java.lang.reflect.Array;
import java.util.concurrent.ForkJoinPool;
import java.util.function.BinaryOperator;
@@ -53,7 +56,7 @@
* if the specified array reference is null, except where noted.
*
* <p>The documentation for the methods contained in this class includes
- * briefs description of the <i>implementations</i>. Such descriptions should
+ * brief descriptions of the <i>implementations</i>. Such descriptions should
* be regarded as <i>implementation notes</i>, rather than parts of the
* <i>specification</i>. Implementors should feel free to substitute other
* algorithms, so long as the specification itself is adhered to. (For
@@ -61,7 +64,7 @@
* a MergeSort, but it does have to be <i>stable</i>.)
*
* <p>This class is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
* Java Collections Framework</a>.
*
* @author Josh Bloch
@@ -111,7 +114,7 @@
* 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) {
+ static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException(
"fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
@@ -1007,7 +1010,7 @@
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0);
else
- new ArraysParallelSortHelpers.FJObject.Sorter<T>
+ 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 +1069,7 @@
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0);
else
- new ArraysParallelSortHelpers.FJObject.Sorter<T>
+ 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 +1118,7 @@
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
TimSort.sort(a, 0, n, cmp, null, 0, 0);
else
- new ArraysParallelSortHelpers.FJObject.Sorter<T>
+ 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 +1179,7 @@
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
else
- new ArraysParallelSortHelpers.FJObject.Sorter<T>
+ new ArraysParallelSortHelpers.FJObject.Sorter<>
(null, a,
(T[])Array.newInstance(a.getClass().getComponentType(), n),
fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
@@ -1213,7 +1216,7 @@
*
* <p>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.
*
@@ -1269,7 +1272,7 @@
*
* <p>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.
*
@@ -1392,7 +1395,7 @@
*
* <p>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.
*
@@ -1452,7 +1455,7 @@
*
* <p>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.
*
@@ -1696,10 +1699,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +1729,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +1780,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +1810,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +1861,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +1891,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +1942,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +1972,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +2023,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +2053,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +2105,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +2136,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +2196,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +2227,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +2293,10 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +2331,11 @@
* @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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +2391,13 @@
* @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
- * <tt>null</tt> 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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>a.length</tt> 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 +2430,15 @@
* @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
- * <tt>null</tt> 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, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+ * otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
* <i>insertion point</i> 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 <tt>toIndex</tt> 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 +2484,16 @@
// Equality Testing
/**
- * Returns <tt>true</tt> if the two specified arrays of longs are
+ * Returns {@code true} if the two specified arrays of longs are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> 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)
@@ -2502,24 +2505,67 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (a[i] != a2[i])
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of ints are
+ * Returns true if the two specified arrays of longs, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * @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 fro 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(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex,
+ aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of ints are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> 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)
@@ -2531,24 +2577,67 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (a[i] != a2[i])
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of shorts are
+ * Returns true if the two specified arrays of ints, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * @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 fro 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(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex,
+ aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of shorts are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> 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)
@@ -2560,25 +2649,69 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (a[i] != a2[i])
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of chars are
+ * Returns true if the two specified arrays of shorts, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * @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 fro 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(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex,
+ aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of chars are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> if the two arrays are equal
+ * @return {@code true} if the two arrays are equal
*/
+ @HotSpotIntrinsicCandidate
public static boolean equals(char[] a, char[] a2) {
if (a==a2)
return true;
@@ -2589,25 +2722,69 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (a[i] != a2[i])
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of bytes are
+ * Returns true if the two specified arrays of chars, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * @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 fro 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(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex,
+ aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of bytes are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> if the two arrays are equal
+ * @return {@code true} if the two arrays are equal
*/
+ @HotSpotIntrinsicCandidate
public static boolean equals(byte[] a, byte[] a2) {
if (a==a2)
return true;
@@ -2618,24 +2795,67 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (a[i] != a2[i])
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of booleans are
+ * Returns true if the two specified arrays of bytes, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * @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 fro 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(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex,
+ aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of booleans are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> 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)
@@ -2647,29 +2867,72 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (a[i] != a2[i])
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of doubles are
+ * Returns true if the two specified arrays of booleans, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * @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 fro 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(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex,
+ aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of doubles are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * two array references are considered equal if both are {@code null}.
*
- * Two doubles <tt>d1</tt> and <tt>d2</tt> are considered equal if:
- * <pre> <tt>new Double(d1).equals(new Double(d2))</tt></pre>
- * (Unlike the <tt>==</tt> operator, this method considers
- * <tt>NaN</tt> equals to itself, and 0.0d unequal to -0.0d.)
+ * Two doubles {@code d1} and {@code d2} are considered equal if:
+ * <pre> {@code new Double(d1).equals(new Double(d2))}</pre>
+ * (Unlike the {@code ==} operator, this method considers
+ * {@code NaN} equals 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 <tt>true</tt> 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) {
@@ -2682,29 +2945,77 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i]))
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of floats are
+ * Returns true if the two specified arrays of doubles, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * <p>Two doubles {@code d1} and {@code d2} are considered equal if:
+ * <pre> {@code new Double(d1).equals(new Double(d2))}</pre>
+ * (Unlike the {@code ==} operator, this method considers
+ * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.)
+ *
+ * @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 fro 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}
+ * @see Double#equals(Object)
+ * @since 9
+ */
+ public static boolean equals(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex, aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of floats are
* <i>equal</i> 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 <tt>null</tt>.<p>
+ * two array references are considered equal if both are {@code null}.
*
- * Two floats <tt>f1</tt> and <tt>f2</tt> are considered equal if:
- * <pre> <tt>new Float(f1).equals(new Float(f2))</tt></pre>
- * (Unlike the <tt>==</tt> operator, this method considers
- * <tt>NaN</tt> equals to itself, and 0.0f unequal to -0.0f.)
+ * Two floats {@code f1} and {@code f2} are considered equal if:
+ * <pre> {@code new Float(f1).equals(new Float(f2))}</pre>
+ * (Unlike the {@code ==} operator, this method considers
+ * {@code NaN} equals 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 <tt>true</tt> 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) {
@@ -2717,26 +3028,75 @@
if (a2.length != length)
return false;
- for (int i=0; i<length; i++)
- if (Float.floatToIntBits(a[i])!=Float.floatToIntBits(a2[i]))
- return false;
-
- return true;
+ return ArraysSupport.mismatch(a, a2, length) < 0;
}
/**
- * Returns <tt>true</tt> if the two specified arrays of Objects are
+ * Returns true if the two specified arrays of floats, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * <p>Two floats {@code f1} and {@code f2} are considered equal if:
+ * <pre> {@code new Float(f1).equals(new Float(f2))}</pre>
+ * (Unlike the {@code ==} operator, this method considers
+ * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.)
+ *
+ * @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 fro 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}
+ * @see Float#equals(Object)
+ * @since 9
+ */
+ public static boolean equals(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;
+ if (aLength != bLength)
+ return false;
+
+ return ArraysSupport.mismatch(a, aFromIndex,
+ b, bFromIndex, aLength) < 0;
+ }
+
+ /**
+ * Returns {@code true} if the two specified arrays of Objects are
* <i>equal</i> 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 <tt>e1</tt>
- * and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
- * : e1.equals(e2))</tt>. 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 <i>equal</i> 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 <tt>null</tt>.<p>
+ * 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 <tt>true</tt> 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 +3109,157 @@
return false;
for (int i=0; i<length; i++) {
- Object o1 = a[i];
- Object o2 = a2[i];
- if (!(o1==null ? o2==null : o1.equals(o2)))
+ if (!Objects.equals(a[i], a2[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the two specified arrays of Objects, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> 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 fro 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
+ * <i>equal</i> to one another.
+ *
+ * <p>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}.
+ *
+ * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> 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 <T> 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 <T> boolean equals(T[] a, T[] a2, Comparator<? super T> 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; i<length; i++) {
+ if (cmp.compare(a[i], a2[i]) != 0)
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the two specified arrays of Objects, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>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.
+ *
+ * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> 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 fro 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 <T> 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 <T> boolean equals(T[] a, int aFromIndex, int aToIndex,
+ T[] b, int bFromIndex, int bToIndex,
+ Comparator<? super T> 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 +3283,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3293,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3318,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3328,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3353,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3363,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3388,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3398,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3423,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3433,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3458,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3468,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3494,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3504,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3529,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3539,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3566,8 @@
/**
* 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 <tt>fromIndex</tt>, inclusive, to index
- * <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, 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 +3576,9 @@
* @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 <tt>fromIndex > toIndex</tt>
- * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
- * <tt>toIndex > a.length</tt>
+ * @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 +3595,7 @@
* 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 <tt>null</tt>.
+ * 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 +3605,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> is null
+ * @throws NegativeArraySizeException if {@code newLength} is negative
+ * @throws NullPointerException if {@code original} is null
* @since 1.6
*/
@SuppressWarnings("unchecked")
@@ -3111,10 +3619,10 @@
* 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 <tt>null</tt>.
+ * 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 <tt>newType</tt>.
+ * The resulting array is of the class {@code newType}.
*
* @param <U> the class of the objects in the original array
* @param <T> the class of the objects in the returned array
@@ -3123,13 +3631,14 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> is null
+ * @throws NegativeArraySizeException if {@code newLength} is negative
+ * @throws NullPointerException if {@code original} is null
* @throws ArrayStoreException if an element copied from
- * <tt>original</tt> is not of a runtime type that can be stored in
- * an array of class <tt>newType</tt>
+ * {@code original} is not of a runtime type that can be stored in
+ * an array of class {@code newType}
* @since 1.6
*/
+ @HotSpotIntrinsicCandidate
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
@@ -3145,7 +3654,7 @@
* 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 <tt>(byte)0</tt>.
+ * 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 +3662,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3678,7 @@
* 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 <tt>(short)0</tt>.
+ * 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 +3686,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3702,7 @@
* 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 <tt>0</tt>.
+ * 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 +3710,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3726,7 @@
* 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 <tt>0L</tt>.
+ * 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 +3734,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3750,7 @@
* 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 <tt>'\\u000'</tt>. Such indices
+ * the original, the copy will contain {@code '\\u000'}. Such indices
* will exist if and only if the specified length is greater than that of
* the original array.
*
@@ -3249,8 +3758,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3774,7 @@
* 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 <tt>0f</tt>.
+ * 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 +3782,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3798,7 @@
* 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 <tt>0d</tt>.
+ * 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 +3806,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3818,11 @@
}
/**
- * Copies the specified array, truncating or padding with <tt>false</tt> (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 <tt>false</tt>.
+ * 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 +3830,8 @@
* @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 <tt>newLength</tt> is negative
- * @throws NullPointerException if <tt>original</tt> 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 +3843,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>null</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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}.
* <p>
* The resulting array is of exactly the same class as the original array.
*
@@ -3357,8 +3866,8 @@
* truncated or padded with nulls to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> is null
+ * @throws IllegalArgumentException if {@code from > to}
+ * @throws NullPointerException if {@code original} is null
* @since 1.6
*/
@SuppressWarnings("unchecked")
@@ -3368,18 +3877,18 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>null</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
- * The resulting array is of the class <tt>newType</tt>.
+ * ({@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 <U> the class of the objects in the original array
* @param <T> the class of the objects in the returned array
@@ -3392,13 +3901,14 @@
* truncated or padded with nulls to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> is null
+ * @throws IllegalArgumentException if {@code from > to}
+ * @throws NullPointerException if {@code original} is null
* @throws ArrayStoreException if an element copied from
- * <tt>original</tt> is not of a runtime type that can be stored in
- * an array of class <tt>newType</tt>.
+ * {@code original} is not of a runtime type that can be stored in
+ * an array of class {@code newType}.
* @since 1.6
*/
+ @HotSpotIntrinsicCandidate
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
int newLength = to - from;
if (newLength < 0)
@@ -3414,17 +3924,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>(byte)0</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +3944,8 @@
* truncated or padded with zeros to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +3960,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>(short)0</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +3980,8 @@
* truncated or padded with zeros to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +3996,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>0</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +4016,8 @@
* truncated or padded with zeros to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +4032,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>0L</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +4052,8 @@
* truncated or padded with zeros to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +4068,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>'\\u000'</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@code to}), which must be greater than or equal to {@code from},
+ * may be greater than {@code original.length}, in which case
+ * {@code '\\u000'} 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 +4088,8 @@
* 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 <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +4104,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>0f</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +4124,8 @@
* truncated or padded with zeros to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +4140,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>0d</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +4160,8 @@
* truncated or padded with zeros to obtain the required length
* @throws ArrayIndexOutOfBoundsException if {@code from < 0}
* or {@code from > original.length}
- * @throws IllegalArgumentException if <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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 +4176,17 @@
/**
* Copies the specified range of the specified array into a new array.
- * The initial index of the range (<tt>from</tt>) must lie between zero
- * and <tt>original.length</tt>, inclusive. The value at
- * <tt>original[from]</tt> is placed into the initial element of the copy
- * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+ * 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
- * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
- * may be greater than <tt>original.length</tt>, in which case
- * <tt>false</tt> is placed in all elements of the copy whose index is
- * greater than or equal to <tt>original.length - from</tt>. The length
- * of the returned array will be <tt>to - from</tt>.
+ * ({@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 +4196,8 @@
* 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 <tt>from > to</tt>
- * @throws NullPointerException if <tt>original</tt> 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) {
@@ -3745,7 +4255,7 @@
@Override
public Object[] toArray() {
- return a.clone();
+ return Arrays.copyOf(a, a.length, Object[].class);
}
@Override
@@ -3790,7 +4300,7 @@
@Override
public boolean contains(Object o) {
- return indexOf(o) != -1;
+ return indexOf(o) >= 0;
}
@Override
@@ -3819,22 +4329,51 @@
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
+
+ @Override
+ public Iterator<E> iterator() {
+ return new ArrayItr<>(a);
+ }
+ }
+
+ private static class ArrayItr<E> implements Iterator<E> {
+ 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 <tt>long</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Long}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(long a[]) {
@@ -3852,18 +4391,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two non-null <tt>int</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Integer}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(int a[]) {
@@ -3879,18 +4418,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two <tt>short</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Short}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(short a[]) {
@@ -3906,18 +4445,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two <tt>char</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Character}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(char a[]) {
@@ -3933,18 +4472,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two <tt>byte</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Byte}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(byte a[]) {
@@ -3960,18 +4499,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two <tt>boolean</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Boolean}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(boolean a[]) {
@@ -3987,18 +4526,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two <tt>float</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Float}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(float a[]) {
@@ -4014,18 +4553,18 @@
/**
* Returns a hash code based on the contents of the specified array.
- * For any two <tt>double</tt> arrays <tt>a</tt> and <tt>b</tt>
- * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * 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)}.
*
* <p>The value returned by this method is the same value that would be
- * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+ * obtained by invoking the {@link List#hashCode() hashCode}
* method on a {@link List} containing a sequence of {@link Double}
- * instances representing the elements of <tt>a</tt> in the same order.
- * If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @since 1.5
*/
public static int hashCode(double a[]) {
@@ -4048,16 +4587,16 @@
* element, either directly or indirectly through one or more levels of
* arrays.
*
- * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
- * <tt>Arrays.equals(a, b)</tt>, it is also the case that
- * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+ * <p>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)}.
*
* <p>The value returned by this method is equal to the value that would
- * be returned by <tt>Arrays.asList(a).hashCode()</tt>, unless <tt>a</tt>
- * is <tt>null</tt>, in which case <tt>0</tt> 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 <tt>a</tt>
+ * @return a content-based hash code for {@code a}
* @see #deepHashCode(Object[])
* @since 1.5
*/
@@ -4082,23 +4621,23 @@
* one or more levels of arrays. The behavior of such an invocation is
* undefined.
*
- * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
- * <tt>Arrays.deepEquals(a, b)</tt>, it is also the case that
- * <tt>Arrays.deepHashCode(a) == Arrays.deepHashCode(b)</tt>.
+ * <p>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)}.
*
* <p>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 <tt>a</tt> in the same order, with one
- * difference: If an element <tt>e</tt> of <tt>a</tt> is itself an array,
- * its hash code is computed not by calling <tt>e.hashCode()</tt>, but as
- * by calling the appropriate overloading of <tt>Arrays.hashCode(e)</tt>
- * if <tt>e</tt> is an array of a primitive type, or as by calling
- * <tt>Arrays.deepHashCode(e)</tt> recursively if <tt>e</tt> is an array
- * of a reference type. If <tt>a</tt> is <tt>null</tt>, 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 <tt>a</tt>
+ * @return a deep-content-based hash code for {@code a}
* @see #hashCode(Object[])
* @since 1.5
*/
@@ -4109,63 +4648,60 @@
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 <tt>true</tt> if the two specified arrays are <i>deeply
+ * Returns {@code true} if the two specified arrays are <i>deeply
* equal</i> to one another. Unlike the {@link #equals(Object[],Object[])}
* method, this method is appropriate for use with nested arrays of
* arbitrary depth.
*
* <p>Two array references are considered deeply equal if both
- * are <tt>null</tt>, 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.
*
- * <p>Two possibly <tt>null</tt> elements <tt>e1</tt> and <tt>e2</tt> are
+ * <p>Two possibly {@code null} elements {@code e1} and {@code e2} are
* deeply equal if any of the following conditions hold:
* <ul>
- * <li> <tt>e1</tt> and <tt>e2</tt> are both arrays of object reference
- * types, and <tt>Arrays.deepEquals(e1, e2) would return true</tt>
- * <li> <tt>e1</tt> and <tt>e2</tt> are arrays of the same primitive
+ * <li> {@code e1} and {@code e2} are both arrays of object reference
+ * types, and {@code Arrays.deepEquals(e1, e2) would return true}
+ * <li> {@code e1} and {@code e2} are arrays of the same primitive
* type, and the appropriate overloading of
- * <tt>Arrays.equals(e1, e2)</tt> would return true.
- * <li> <tt>e1 == e2</tt>
- * <li> <tt>e1.equals(e2)</tt> would return true.
+ * {@code Arrays.equals(e1, e2)} would return true.
+ * <li> {@code e1 == e2}
+ * <li> {@code e1.equals(e2)} would return true.
* </ul>
- * Note that this definition permits <tt>null</tt> elements at any depth.
+ * Note that this definition permits {@code null} elements at any depth.
*
* <p>If either of the specified arrays contain themselves as elements
* either directly or indirectly through one or more levels of arrays,
@@ -4173,7 +4709,7 @@
*
* @param a1 one array to be tested for equality
* @param a2 the other array to be tested for equality
- * @return <tt>true</tt> 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 +4770,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(long)</tt>. Returns <tt>"null"</tt> if <tt>a</tt>
- * is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(long[] a) {
@@ -4264,14 +4800,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(int)</tt>. Returns <tt>"null"</tt> if <tt>a</tt> is
- * <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(int[] a) {
@@ -4294,14 +4830,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(short)</tt>. Returns <tt>"null"</tt> if <tt>a</tt>
- * is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(short[] a) {
@@ -4324,14 +4860,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(char)</tt>. Returns <tt>"null"</tt> if <tt>a</tt>
- * is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(char[] a) {
@@ -4354,14 +4890,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements
- * are separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(byte)</tt>. Returns <tt>"null"</tt> if
- * <tt>a</tt> is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(byte[] a) {
@@ -4384,14 +4920,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(boolean)</tt>. Returns <tt>"null"</tt> if
- * <tt>a</tt> is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(boolean[] a) {
@@ -4414,14 +4950,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(float)</tt>. Returns <tt>"null"</tt> if <tt>a</tt>
- * is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(float[] a) {
@@ -4445,14 +4981,14 @@
/**
* 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 (<tt>"[]"</tt>). Adjacent elements are
- * separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(double)</tt>. Returns <tt>"null"</tt> if <tt>a</tt>
- * is <tt>null</tt>.
+ * {@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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @since 1.5
*/
public static String toString(double[] a) {
@@ -4476,15 +5012,15 @@
* 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
- * <tt>Object</tt>, which describes their <i>identities</i> rather than
+ * {@code Object}, which describes their <i>identities</i> rather than
* their contents.
*
* <p>The value returned by this method is equal to the value that would
- * be returned by <tt>Arrays.asList(a).toString()</tt>, unless <tt>a</tt>
- * is <tt>null</tt>, in which case <tt>"null"</tt> 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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @see #deepToString(Object[])
* @since 1.5
*/
@@ -4513,29 +5049,29 @@
* designed for converting multidimensional arrays to strings.
*
* <p>The string representation consists of a list of the array's
- * elements, enclosed in square brackets (<tt>"[]"</tt>). Adjacent
- * elements are separated by the characters <tt>", "</tt> (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
- * <tt>String.valueOf(Object)</tt>, unless they are themselves
+ * {@code String.valueOf(Object)}, unless they are themselves
* arrays.
*
- * <p>If an element <tt>e</tt> is an array of a primitive type, it is
+ * <p>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
- * <tt>Arrays.toString(e)</tt>. If an element <tt>e</tt> 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.
*
* <p>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
- * <tt>"[...]"</tt>. For example, an array containing only a reference
- * to itself would be rendered as <tt>"[[...]]"</tt>.
+ * {@code "[...]"}. For example, an array containing only a reference
+ * to itself would be rendered as {@code "[[...]]"}.
*
- * <p>This method returns <tt>"null"</tt> if the specified array
- * is <tt>null</tt>.
+ * <p>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 <tt>a</tt>
+ * @return a string representation of {@code a}
* @see #toString(Object[])
* @since 1.5
*/
@@ -4547,7 +5083,7 @@
if (a.length != 0 && bufLen <= 0)
bufLen = Integer.MAX_VALUE;
StringBuilder buf = new StringBuilder(bufLen);
- deepToString(a, buf, new HashSet<Object[]>());
+ deepToString(a, buf, new HashSet<>());
return buf.toString();
}
@@ -4616,6 +5152,14 @@
* <p>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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .forEach(i -> array[i] = generator.apply(i));
+ * }</pre>
+ *
* @param <T> 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 +5181,15 @@
* 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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .parallel()
+ * .forEach(i -> array[i] = generator.apply(i));
+ * }</pre>
+ *
* @param <T> 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 +5209,14 @@
* <p>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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .forEach(i -> array[i] = generator.applyAsInt(i));
+ * }</pre>
+ *
* @param array array to be initialized
* @param generator a function accepting an index and producing the desired
* value for that position
@@ -4676,6 +5237,15 @@
* 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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .parallel()
+ * .forEach(i -> array[i] = generator.applyAsInt(i));
+ * }</pre>
+ *
* @param array array to be initialized
* @param generator a function accepting an index and producing the desired
* value for that position
@@ -4694,6 +5264,14 @@
* <p>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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .forEach(i -> array[i] = generator.applyAsLong(i));
+ * }</pre>
+ *
* @param array array to be initialized
* @param generator a function accepting an index and producing the desired
* value for that position
@@ -4714,6 +5292,15 @@
* 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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .parallel()
+ * .forEach(i -> array[i] = generator.applyAsLong(i));
+ * }</pre>
+ *
* @param array array to be initialized
* @param generator a function accepting an index and producing the desired
* value for that position
@@ -4732,6 +5319,14 @@
* <p>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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .forEach(i -> array[i] = generator.applyAsDouble(i));
+ * }</pre>
+ *
* @param array array to be initialized
* @param generator a function accepting an index and producing the desired
* value for that position
@@ -4752,6 +5347,15 @@
* 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:
+ * <pre>{@code
+ * IntStream.range(startInclusive, endExclusive)
+ * .parallel()
+ * .forEach(i -> array[i] = generator.applyAsDouble(i));
+ * }</pre>
+ *
* @param array array to be initialized
* @param generator a function accepting an index and producing the desired
* value for that position
@@ -5043,4 +5647,3185 @@
public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
}
+
+
+ // Comparison methods
+
+ // Compare boolean
+
+ /**
+ * Compares two {@code boolean} arrays lexicographically.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(boolean[], boolean[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(byte[], byte[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(short[], short[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(char[], char[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(int[], int[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(long[], long[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(float[], float[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>A {@code null} array reference is considered lexicographically less
+ * than a non-{@code null} array reference. Two {@code null} array
+ * references are considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(double[], double[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if:
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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:
+ * <pre>{@code
+ * Comparator.nullsFirst(Comparator.<T>naturalOrder()).
+ * compare(a[i], b[i])
+ * }</pre>
+ * 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.)
+ *
+ * <p>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 than a
+ * non-{@code null} array element. Two {@code null} array elements are
+ * considered equal.
+ *
+ * <p>The comparison is consistent with {@link #equals(Object[], Object[]) equals},
+ * more specifically the following holds for arrays {@code a} and {@code b}:
+ * <pre>{@code
+ * Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array references
+ * and elements):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @param a the first array to compare
+ * @param b the second array to compare
+ * @param <T> 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 <T extends Comparable<? super T>> 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.
+ *
+ * <p>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:
+ * <pre>{@code
+ * Comparator.nullsFirst(Comparator.<T>naturalOrder()).
+ * compare(a[aFromIndex + i, b[bFromIndex + i])
+ * }</pre>
+ * 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.)
+ *
+ * <p>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:
+ * <pre>{@code
+ * Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+ * (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+ * }</pre>
+ *
+ * @apiNote
+ * <p>This method behaves as if (for non-{@code null} array elements):
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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 <T> 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 <T extends Comparable<? super T>> 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.
+ *
+ * <p>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.)
+ *
+ * <p>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
+ * <p>This method behaves as if (for non-{@code null} array references):
+ * <pre>{@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;
+ * }</pre>
+ *
+ * @param a the first array to compare
+ * @param b the second array to compare
+ * @param cmp the comparator to compare array elements
+ * @param <T> 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 <T> int compare(T[] a, T[] b,
+ Comparator<? super T> 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.
+ *
+ * <p>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
+ * <p>This method behaves as if (for non-{@code null} array elements):
+ * <pre>{@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);
+ * }</pre>
+ *
+ * @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 <T> 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 <T> int compare(
+ T[] a, int aFromIndex, int aToIndex,
+ T[] b, int bFromIndex, int bToIndex,
+ Comparator<? super T> 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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * a[pl] != b[pl]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * a[pl] != b[pl]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * a[pl] != b[pl]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * a[pl] != b[pl]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * a[pl] != b[pl]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * a[pl] != b[pl]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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]
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@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
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@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
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@code
+ * pl >= 0 &&
+ * pl < Math.min(a.length, b.length) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl) &&
+ * !Objects.equals(a[pl], b[pl])
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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])
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+ * }</pre>
+ *
+ * @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.
+ *
+ * <p>The specified comparator is used to determine if two array elements
+ * from the each array are not equal.
+ *
+ * <p>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.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+ * prefix of length {@code pl} if the following expression is true:
+ * <pre>{@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
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+ * prefix if the following expression is true:
+ * <pre>{@code
+ * a.length != b.length &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length),
+ * cmp)
+ * }</pre>
+ *
+ * @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 <T> 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 <T> int mismatch(T[] a, T[] b, Comparator<? super T> 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.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ * <pre>{@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
+ * }</pre>
+ * Note that a common prefix length of {@code 0} indicates that the first
+ * elements from each array mismatch.
+ *
+ * <p>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
+ * if the following expression is true:
+ * <pre>{@code
+ * (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * cmp)
+ * }</pre>
+ *
+ * @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 <T> 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 <T> int mismatch(
+ T[] a, int aFromIndex, int aToIndex,
+ T[] b, int bFromIndex, int bToIndex,
+ Comparator<? super T> 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/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
index e4d2235..a206867 100644
--- a/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -245,8 +245,7 @@
Future<T> f = futures.get(i);
if (!f.isDone()) {
try { f.get(); }
- catch (CancellationException ignore) {}
- catch (ExecutionException ignore) {}
+ catch (CancellationException | ExecutionException ignore) {}
}
}
return futures;
@@ -283,8 +282,7 @@
Future<T> f = futures.get(j);
if (!f.isDone()) {
try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
- catch (CancellationException ignore) {}
- catch (ExecutionException ignore) {}
+ catch (CancellationException | ExecutionException ignore) {}
catch (TimeoutException timedOut) {
break timedOut;
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index 96a60b3..dced5a4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -46,10 +46,8 @@
import java.util.Spliterators;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* A bounded {@linkplain BlockingQueue blocking queue} backed by an
@@ -74,17 +72,24 @@
* generally decreases throughput but reduces variability and avoids
* starvation.
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
*
- * @since 1.5
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @author Doug Lea
* @param <E> the type of elements held in this queue
*/
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
+ /*
+ * Much of the implementation mechanics, especially the unusual
+ * nested loops, are shared and co-maintained with ArrayDeque.
+ */
+
/**
* Serialization ID. This class relies on default serialization
* even for the items array, which is default-serialized, even if
@@ -129,10 +134,21 @@
// Internal helper methods
/**
- * Circularly decrements array index i.
+ * Increments i, mod modulus.
+ * Precondition and postcondition: 0 <= i < modulus.
*/
- final int dec(int i) {
- return ((i == 0) ? items.length : i) - 1;
+ static final int inc(int i, int modulus) {
+ if (++i >= modulus) i = 0;
+ return i;
+ }
+
+ /**
+ * Decrements i, mod modulus.
+ * Precondition and postcondition: 0 <= i < modulus.
+ */
+ static final int dec(int i, int modulus) {
+ if (--i < 0) i = modulus - 1;
+ return i;
}
/**
@@ -144,14 +160,24 @@
}
/**
+ * Returns element at array index i.
+ * This is a slight abuse of generics, accepted by javac.
+ */
+ @SuppressWarnings("unchecked")
+ static <E> E itemAt(Object[] items, int i) {
+ return (E) items[i];
+ }
+
+ /**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
- private void enqueue(E x) {
+ private void enqueue(E e) {
+ // assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
- items[putIndex] = x;
+ items[putIndex] = e;
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
@@ -162,18 +188,19 @@
* Call only when holding lock.
*/
private E dequeue() {
+ // assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
- E x = (E) items[takeIndex];
+ E e = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
- return x;
+ return e;
}
/**
@@ -182,6 +209,7 @@
* Call only when holding lock.
*/
void removeAt(final int removeIndex) {
+ // assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[removeIndex] != null;
// assert removeIndex >= 0 && removeIndex < items.length;
@@ -267,6 +295,7 @@
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
+ final Object[] items = this.items;
int i = 0;
try {
for (E e : c)
@@ -481,15 +510,16 @@
try {
if (count > 0) {
final Object[] items = this.items;
- final int putIndex = this.putIndex;
- int i = takeIndex;
- do {
- if (o.equals(items[i])) {
- removeAt(i);
- return true;
- }
- if (++i == items.length) i = 0;
- } while (i != putIndex);
+ for (int i = takeIndex, end = putIndex,
+ to = (i < end) ? end : items.length;
+ ; i = 0, to = end) {
+ for (; i < to; i++)
+ if (o.equals(items[i])) {
+ removeAt(i);
+ return true;
+ }
+ if (to == end) break;
+ }
}
return false;
} finally {
@@ -512,13 +542,14 @@
try {
if (count > 0) {
final Object[] items = this.items;
- final int putIndex = this.putIndex;
- int i = takeIndex;
- do {
- if (o.equals(items[i]))
- return true;
- if (++i == items.length) i = 0;
- } while (i != putIndex);
+ for (int i = takeIndex, end = putIndex,
+ to = (i < end) ? end : items.length;
+ ; i = 0, to = end) {
+ for (; i < to; i++)
+ if (o.equals(items[i]))
+ return true;
+ if (to == end) break;
+ }
}
return false;
} finally {
@@ -625,15 +656,9 @@
final ReentrantLock lock = this.lock;
lock.lock();
try {
- int k = count;
- if (k > 0) {
- final Object[] items = this.items;
- final int putIndex = this.putIndex;
- int i = takeIndex;
- do {
- items[i] = null;
- if (++i == items.length) i = 0;
- } while (i != putIndex);
+ int k;
+ if ((k = count) > 0) {
+ circularClear(items, takeIndex, putIndex);
takeIndex = putIndex;
count = 0;
if (itrs != null)
@@ -647,6 +672,20 @@
}
/**
+ * Nulls out slots starting at array index i, upto index end.
+ * Condition i == end means "full" - the entire array is cleared.
+ */
+ private static void circularClear(Object[] items, int i, int end) {
+ // assert 0 <= i && i < items.length;
+ // assert 0 <= end && end < items.length;
+ for (int to = (i < end) ? end : items.length;
+ ; i = 0, to = end) {
+ for (; i < to; i++) items[i] = null;
+ if (to == end) break;
+ }
+ }
+
+ /**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
@@ -678,8 +717,8 @@
try {
while (i < n) {
@SuppressWarnings("unchecked")
- E x = (E) items[take];
- c.add(x);
+ E e = (E) items[take];
+ c.add(e);
items[take] = null;
if (++take == items.length) take = 0;
i++;
@@ -808,7 +847,7 @@
* there is known to be at least one iterator to collect
*/
void doSomeSweeping(boolean tryHarder) {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
// assert head != null;
int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
Node o, p;
@@ -864,7 +903,7 @@
* Adds a new iterator to the linked list of tracked iterators.
*/
void register(Itr itr) {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
head = new Node(itr, head);
}
@@ -874,7 +913,7 @@
* Notifies all iterators, and expunges any that are now stale.
*/
void takeIndexWrapped() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
cycles++;
for (Node o = null, p = head; p != null;) {
final Itr it = p.get();
@@ -931,7 +970,7 @@
* clears all weak refs, and unlinks the itrs datastructure.
*/
void queueIsEmpty() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
for (Node p = head; p != null; p = p.next) {
Itr it = p.get();
if (it != null) {
@@ -947,7 +986,7 @@
* Called whenever an element has been dequeued (at takeIndex).
*/
void elementDequeued() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
if (count == 0)
queueIsEmpty();
else if (takeIndex == 0)
@@ -972,6 +1011,11 @@
* expected element to remove, in lastItem. Yes, we may fail to
* remove lastItem from the queue if it moved due to an interleaved
* interior remove while in detached mode.
+ *
+ * Method forEachRemaining, added in Java 8, is treated similarly
+ * to hasNext returning false, in that we switch to detached mode,
+ * but we regard it as an even stronger request to "close" this
+ * iteration, and don't bother supporting subsequent remove().
*/
private class Itr implements Iterator<E> {
/** Index to look for new nextItem; NONE at end */
@@ -1008,7 +1052,6 @@
private static final int DETACHED = -3;
Itr() {
- // assert lock.getHoldCount() == 0;
lastRet = NONE;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
@@ -1041,12 +1084,12 @@
}
boolean isDetached() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
return prevTakeIndex < 0;
}
private int incCursor(int index) {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
if (++index == items.length) index = 0;
if (index == putIndex) index = NONE;
return index;
@@ -1071,7 +1114,7 @@
* operation on this iterator. Call only from iterating thread.
*/
private void incorporateDequeues() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
// assert itrs != null;
// assert !isDetached();
// assert count > 0;
@@ -1085,7 +1128,7 @@
final int len = items.length;
// how far takeIndex has advanced since the previous
// operation of this iterator
- long dequeues = (cycles - prevCycles) * len
+ long dequeues = (long) (cycles - prevCycles) * len
+ (takeIndex - prevTakeIndex);
// Check indices for invalidation
@@ -1114,7 +1157,7 @@
*/
private void detach() {
// Switch to detached mode
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
// assert cursor == NONE;
// assert nextIndex < 0;
// assert lastRet < 0 || nextItem == null;
@@ -1134,7 +1177,6 @@
* triggered by queue modifications.
*/
public boolean hasNext() {
- // assert lock.getHoldCount() == 0;
if (nextItem != null)
return true;
noNext();
@@ -1164,9 +1206,8 @@
}
public E next() {
- // assert lock.getHoldCount() == 0;
- final E x = nextItem;
- if (x == null)
+ final E e = nextItem;
+ if (e == null)
throw new NoSuchElementException();
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
@@ -1184,17 +1225,48 @@
} else {
nextIndex = NONE;
nextItem = null;
+ if (lastRet == REMOVED) detach();
}
} finally {
lock.unlock();
}
- return x;
+ return e;
+ }
+
+ public void forEachRemaining(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+ lock.lock();
+ try {
+ final E e = nextItem;
+ if (e == null) return;
+ if (!isDetached())
+ incorporateDequeues();
+ action.accept(e);
+ if (isDetached() || cursor < 0) return;
+ final Object[] items = ArrayBlockingQueue.this.items;
+ for (int i = cursor, end = putIndex,
+ to = (i < end) ? end : items.length;
+ ; i = 0, to = end) {
+ for (; i < to; i++)
+ action.accept(itemAt(items, i));
+ if (to == end) break;
+ }
+ } finally {
+ // Calling forEachRemaining is a strong hint that this
+ // iteration is surely over; supporting remove() after
+ // forEachRemaining() is more trouble than it's worth
+ cursor = nextIndex = lastRet = NONE;
+ nextItem = lastItem = null;
+ detach();
+ lock.unlock();
+ }
}
public void remove() {
- // assert lock.getHoldCount() == 0;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
+ // assert lock.getHoldCount() == 1;
try {
if (!isDetached())
incorporateDequeues(); // might update lastRet or detach
@@ -1232,7 +1304,7 @@
* from next(), as promised by returning true from hasNext().
*/
void shutdown() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
cursor = NONE;
if (nextIndex >= 0)
nextIndex = REMOVED;
@@ -1260,7 +1332,7 @@
* @return true if this iterator should be unlinked from itrs
*/
boolean removedAt(int removedIndex) {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
if (isDetached())
return true;
@@ -1285,7 +1357,7 @@
}
else if (x > removedDistance) {
// assert cursor != prevTakeIndex;
- this.cursor = cursor = dec(cursor);
+ this.cursor = cursor = dec(cursor, len);
}
}
int lastRet = this.lastRet;
@@ -1294,7 +1366,7 @@
if (x == removedDistance)
this.lastRet = lastRet = REMOVED;
else if (x > removedDistance)
- this.lastRet = lastRet = dec(lastRet);
+ this.lastRet = lastRet = dec(lastRet, len);
}
int nextIndex = this.nextIndex;
if (nextIndex >= 0) {
@@ -1302,7 +1374,7 @@
if (x == removedDistance)
this.nextIndex = nextIndex = REMOVED;
else if (x > removedDistance)
- this.nextIndex = nextIndex = dec(nextIndex);
+ this.nextIndex = nextIndex = dec(nextIndex, len);
}
if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
this.prevTakeIndex = DETACHED;
@@ -1317,7 +1389,7 @@
* @return true if this iterator should be unlinked from itrs
*/
boolean takeIndexWrapped() {
- // assert lock.getHoldCount() == 1;
+ // assert lock.isHeldByCurrentThread();
if (isDetached())
return true;
if (itrs.cycles - prevCycles > 1) {
@@ -1366,4 +1438,197 @@
Spliterator.CONCURRENT));
}
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ if (count > 0) {
+ final Object[] items = this.items;
+ for (int i = takeIndex, end = putIndex,
+ to = (i < end) ? end : items.length;
+ ; i = 0, to = end) {
+ for (; i < to; i++)
+ action.accept(itemAt(items, i));
+ if (to == end) break;
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> 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));
+ }
+
+ /** Implementation of bulk remove methods. */
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ if (itrs == null) { // check for active iterators
+ if (count > 0) {
+ final Object[] items = this.items;
+ // Optimize for initial run of survivors
+ for (int i = takeIndex, end = putIndex,
+ to = (i < end) ? end : items.length;
+ ; i = 0, to = end) {
+ for (; i < to; i++)
+ if (filter.test(itemAt(items, i)))
+ return bulkRemoveModified(filter, i);
+ if (to == end) break;
+ }
+ }
+ return false;
+ }
+ } finally {
+ lock.unlock();
+ }
+ // Active iterators are too hairy!
+ // Punting (for now) to the slow n^2 algorithm ...
+ return super.removeIf(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;
+ }
+
+ /**
+ * Returns circular distance from i to j, disambiguating i == j to
+ * items.length; never returns 0.
+ */
+ private int distanceNonEmpty(int i, int j) {
+ if ((j -= i) <= 0) j += items.length;
+ return j;
+ }
+
+ /**
+ * Helper for bulkRemove, in case of at least one deletion.
+ * Tolerate predicates that reentrantly access the collection for
+ * read (but not write), so traverse once to find elements to
+ * delete, a second pass to physically expunge.
+ *
+ * @param beg valid index of first element to be deleted
+ */
+ private boolean bulkRemoveModified(
+ Predicate<? super E> filter, final int beg) {
+ final Object[] es = items;
+ final int capacity = items.length;
+ final int end = putIndex;
+ final long[] deathRow = nBits(distanceNonEmpty(beg, putIndex));
+ deathRow[0] = 1L; // set bit 0
+ for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+ ; i = 0, to = end, k -= capacity) {
+ for (; i < to; i++)
+ if (filter.test(itemAt(es, i)))
+ setBit(deathRow, i - k);
+ if (to == end) break;
+ }
+ // a two-finger traversal, with hare i reading, tortoise w writing
+ int w = beg;
+ for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+ ; w = 0) { // w rejoins i on second leg
+ // In this loop, i and w are on the same leg, with i > w
+ for (; i < to; i++)
+ if (isClear(deathRow, i - k))
+ es[w++] = es[i];
+ if (to == end) break;
+ // In this loop, w is on the first leg, i on the second
+ for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+ if (isClear(deathRow, i - k))
+ es[w++] = es[i];
+ if (i >= to) {
+ if (w == capacity) w = 0; // "corner" case
+ break;
+ }
+ }
+ count -= distanceNonEmpty(w, end);
+ circularClear(es, putIndex = w, end);
+ return true;
+ }
+
+ /** debugging */
+ void checkInvariants() {
+ // meta-assertions
+ // assert lock.isHeldByCurrentThread();
+ if (!invariantsSatisfied()) {
+ String detail = String.format(
+ "takeIndex=%d putIndex=%d count=%d capacity=%d items=%s",
+ takeIndex, putIndex, count, items.length,
+ Arrays.toString(items));
+ System.err.println(detail);
+ throw new AssertionError(detail);
+ }
+ }
+
+ private boolean invariantsSatisfied() {
+ // Unlike ArrayDeque, we have a count field but no spare slot.
+ // We prefer ArrayDeque's strategy (and the names of its fields!),
+ // but our field layout is baked into the serial form, and so is
+ // too annoying to change.
+ //
+ // putIndex == takeIndex must be disambiguated by checking count.
+ int capacity = items.length;
+ return capacity > 0
+ && items.getClass() == Object[].class
+ && (takeIndex | putIndex | count) >= 0
+ && takeIndex < capacity
+ && putIndex < capacity
+ && count <= capacity
+ && (putIndex - takeIndex - count) % capacity == 0
+ && (count == 0 || items[takeIndex] != null)
+ && (count == capacity || items[putIndex] == null)
+ && (count == 0 || items[dec(putIndex, capacity)] != null);
+ }
+
+ /**
+ * Reconstitutes this queue 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.InvalidObjectException if invariants are violated
+ * @throws java.io.IOException if an I/O error occurs
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+
+ // Read in items array and various fields
+ s.defaultReadObject();
+
+ if (!invariantsSatisfied())
+ throw new java.io.InvalidObjectException("invariants violated");
+ }
}
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
index 290fee1..8043510 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -39,10 +39,6 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
-// BEGIN android-note
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
/**
* A {@link Deque} that additionally supports blocking operations that wait
* for the deque to become non-empty when retrieving an element, and wait for
@@ -57,69 +53,69 @@
* and the fourth blocks for only a given maximum time limit before giving
* up. These methods are summarized in the following table:
*
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
* <caption>Summary of BlockingDeque methods</caption>
* <tr>
- * <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
+ * <th id="First" colspan="5"> First Element (Head)</th>
* </tr>
* <tr>
* <td></td>
- * <td ALIGN=CENTER><em>Throws exception</em></td>
- * <td ALIGN=CENTER><em>Special value</em></td>
- * <td ALIGN=CENTER><em>Blocks</em></td>
- * <td ALIGN=CENTER><em>Times out</em></td>
+ * <th id="FThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
+ * <th id="FValue" style="font-weight:normal; font-style: italic">Special value</th>
+ * <th id="FBlock" style="font-weight:normal; font-style: italic">Blocks</th>
+ * <th id="FTimes" style="font-weight:normal; font-style: italic">Times out</th>
* </tr>
* <tr>
- * <td><b>Insert</b></td>
- * <td>{@link #addFirst addFirst(e)}</td>
- * <td>{@link #offerFirst(Object) offerFirst(e)}</td>
- * <td>{@link #putFirst putFirst(e)}</td>
- * <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ * <th id="FInsert" style="text-align:left">Insert</th>
+ * <td headers="First FInsert FThrow">{@link #addFirst(Object) addFirst(e)}</td>
+ * <td headers="First FInsert FValue">{@link #offerFirst(Object) offerFirst(e)}</td>
+ * <td headers="First FInsert FBlock">{@link #putFirst(Object) putFirst(e)}</td>
+ * <td headers="First FInsert FTimes">{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
* </tr>
* <tr>
- * <td><b>Remove</b></td>
- * <td>{@link #removeFirst removeFirst()}</td>
- * <td>{@link #pollFirst pollFirst()}</td>
- * <td>{@link #takeFirst takeFirst()}</td>
- * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ * <th id="FRemove" style="text-align:left">Remove</th>
+ * <td headers="First FRemove FThrow">{@link #removeFirst() removeFirst()}</td>
+ * <td headers="First FRemove FValue">{@link #pollFirst() pollFirst()}</td>
+ * <td headers="First FRemove FBlock">{@link #takeFirst() takeFirst()}</td>
+ * <td headers="First FRemove FTimes">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
* </tr>
* <tr>
- * <td><b>Examine</b></td>
- * <td>{@link #getFirst getFirst()}</td>
- * <td>{@link #peekFirst peekFirst()}</td>
- * <td><em>not applicable</em></td>
- * <td><em>not applicable</em></td>
+ * <th id="FExamine" style="text-align:left">Examine</th>
+ * <td headers="First FExamine FThrow">{@link #getFirst() getFirst()}</td>
+ * <td headers="First FExamine FValue">{@link #peekFirst() peekFirst()}</td>
+ * <td headers="First FExamine FBlock" style="font-style:italic">not applicable</td>
+ * <td headers="First FExamine FTimes" style="font-style:italic">not applicable</td>
* </tr>
* <tr>
- * <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
+ * <th id="Last" colspan="5"> Last Element (Tail)</th>
* </tr>
* <tr>
* <td></td>
- * <td ALIGN=CENTER><em>Throws exception</em></td>
- * <td ALIGN=CENTER><em>Special value</em></td>
- * <td ALIGN=CENTER><em>Blocks</em></td>
- * <td ALIGN=CENTER><em>Times out</em></td>
+ * <th id="LThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
+ * <th id="LValue" style="font-weight:normal; font-style: italic">Special value</th>
+ * <th id="LBlock" style="font-weight:normal; font-style: italic">Blocks</th>
+ * <th id="LTimes" style="font-weight:normal; font-style: italic">Times out</th>
* </tr>
* <tr>
- * <td><b>Insert</b></td>
- * <td>{@link #addLast addLast(e)}</td>
- * <td>{@link #offerLast(Object) offerLast(e)}</td>
- * <td>{@link #putLast putLast(e)}</td>
- * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ * <th id="LInsert" style="text-align:left">Insert</th>
+ * <td headers="Last LInsert LThrow">{@link #addLast(Object) addLast(e)}</td>
+ * <td headers="Last LInsert LValue">{@link #offerLast(Object) offerLast(e)}</td>
+ * <td headers="Last LInsert LBlock">{@link #putLast(Object) putLast(e)}</td>
+ * <td headers="Last LInsert LTimes">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
* </tr>
* <tr>
- * <td><b>Remove</b></td>
- * <td>{@link #removeLast() removeLast()}</td>
- * <td>{@link #pollLast() pollLast()}</td>
- * <td>{@link #takeLast takeLast()}</td>
- * <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ * <th id="LRemove" style="text-align:left">Remove</th>
+ * <td headers="Last LRemove LThrow">{@link #removeLast() removeLast()}</td>
+ * <td headers="Last LRemove LValue">{@link #pollLast() pollLast()}</td>
+ * <td headers="Last LRemove LBlock">{@link #takeLast() takeLast()}</td>
+ * <td headers="Last LRemove LTimes">{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
* </tr>
* <tr>
- * <td><b>Examine</b></td>
- * <td>{@link #getLast getLast()}</td>
- * <td>{@link #peekLast peekLast()}</td>
- * <td><em>not applicable</em></td>
- * <td><em>not applicable</em></td>
+ * <th id="LExamine" style="text-align:left">Examine</th>
+ * <td headers="Last LExamine LThrow">{@link #getLast() getLast()}</td>
+ * <td headers="Last LExamine LValue">{@link #peekLast() peekLast()}</td>
+ * <td headers="Last LExamine LBlock" style="font-style:italic">not applicable</td>
+ * <td headers="Last LExamine LTimes" style="font-style:italic">not applicable</td>
* </tr>
* </table>
*
@@ -132,60 +128,55 @@
* {@code BlockingQueue} interface are precisely equivalent to
* {@code BlockingDeque} methods as indicated in the following table:
*
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
* <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
* <tr>
- * <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
- * <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
+ * <td></td>
+ * <th id="BQueue"> {@code BlockingQueue} Method</th>
+ * <th id="BDeque"> Equivalent {@code BlockingDeque} Method</th>
* </tr>
* <tr>
- * <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
+ * <th id="Insert" rowspan="4" style="text-align:left; vertical-align:top">Insert</th>
+ * <th id="add" style="font-weight:normal; text-align:left">{@link #add(Object) add(e)}</th>
+ * <td headers="Insert BDeque add">{@link #addLast(Object) addLast(e)}</td>
* </tr>
* <tr>
- * <td>{@link #add(Object) add(e)}</td>
- * <td>{@link #addLast(Object) addLast(e)}</td>
+ * <th id="offer1" style="font-weight:normal; text-align:left">{@link #offer(Object) offer(e)}</th>
+ * <td headers="Insert BDeque offer1">{@link #offerLast(Object) offerLast(e)}</td>
* </tr>
* <tr>
- * <td>{@link #offer(Object) offer(e)}</td>
- * <td>{@link #offerLast(Object) offerLast(e)}</td>
+ * <th id="put" style="font-weight:normal; text-align:left">{@link #put(Object) put(e)}</th>
+ * <td headers="Insert BDeque put">{@link #putLast(Object) putLast(e)}</td>
* </tr>
* <tr>
- * <td>{@link #put(Object) put(e)}</td>
- * <td>{@link #putLast(Object) putLast(e)}</td>
+ * <th id="offer2" style="font-weight:normal; text-align:left">{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</th>
+ * <td headers="Insert BDeque offer2">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
* </tr>
* <tr>
- * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
- * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ * <th id="Remove" rowspan="4" style="text-align:left; vertical-align:top">Remove</th>
+ * <th id="remove" style="font-weight:normal; text-align:left">{@link #remove() remove()}</th>
+ * <td headers="Remove BDeque remove">{@link #removeFirst() removeFirst()}</td>
* </tr>
* <tr>
- * <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
+ * <th id="poll1" style="font-weight:normal; text-align:left">{@link #poll() poll()}</th>
+ * <td headers="Remove BDeque poll1">{@link #pollFirst() pollFirst()}</td>
* </tr>
* <tr>
- * <td>{@link #remove() remove()}</td>
- * <td>{@link #removeFirst() removeFirst()}</td>
+ * <th id="take" style="font-weight:normal; text-align:left">{@link #take() take()}</th>
+ * <td headers="Remove BDeque take">{@link #takeFirst() takeFirst()}</td>
* </tr>
* <tr>
- * <td>{@link #poll() poll()}</td>
- * <td>{@link #pollFirst() pollFirst()}</td>
+ * <th id="poll2" style="font-weight:normal; text-align:left">{@link #poll(long, TimeUnit) poll(time, unit)}</th>
+ * <td headers="Remove BDeque poll2">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
* </tr>
* <tr>
- * <td>{@link #take() take()}</td>
- * <td>{@link #takeFirst() takeFirst()}</td>
+ * <th id="Examine" rowspan="2" style="text-align:left; vertical-align:top">Examine</th>
+ * <th id="element" style="font-weight:normal; text-align:left">{@link #element() element()}</th>
+ * <td headers="Examine BDeque element">{@link #getFirst() getFirst()}</td>
* </tr>
* <tr>
- * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
- * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
- * </tr>
- * <tr>
- * <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
- * </tr>
- * <tr>
- * <td>{@link #element() element()}</td>
- * <td>{@link #getFirst() getFirst()}</td>
- * </tr>
- * <tr>
- * <td>{@link #peek() peek()}</td>
- * <td>{@link #peekFirst() peekFirst()}</td>
+ * <th id="peek" style="font-weight:normal; text-align:left">{@link #peek() peek()}</th>
+ * <td headers="Examine BDeque peek">{@link #peekFirst() peekFirst()}</td>
* </tr>
* </table>
*
@@ -197,7 +188,7 @@
* the {@code BlockingDeque} in another thread.
*
* <p>This interface is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
* Java Collections Framework</a>.
*
* @since 1.6
@@ -408,9 +399,9 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean removeFirstOccurrence(Object o);
@@ -426,9 +417,9 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean removeLastOccurrence(Object o);
@@ -516,7 +507,7 @@
/**
* Retrieves and removes the head of the queue represented by this deque
* (in other words, the first element of this deque).
- * This method differs from {@link #poll poll} only in that it
+ * This method differs from {@link #poll() poll()} only in that it
* throws an exception if this deque is empty.
*
* <p>This method is equivalent to {@link #removeFirst() removeFirst}.
@@ -567,7 +558,7 @@
/**
* Retrieves, but does not remove, the head of the queue represented by
* this deque (in other words, the first element of this deque).
- * This method differs from {@link #peek peek} only in that it throws an
+ * This method differs from {@link #peek() peek} only in that it throws an
* exception if this deque is empty.
*
* <p>This method is equivalent to {@link #getFirst() getFirst}.
@@ -603,9 +594,9 @@
* @return {@code true} if this deque changed as a result of the call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
@@ -618,9 +609,9 @@
* @return {@code true} if this deque contains the specified element
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean contains(Object o);
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
index 6f01b77..6fecc27 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -38,16 +38,10 @@
import java.util.Collection;
import java.util.Queue;
-// BEGIN android-note
-// removed link to collections framework docs from header
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
/**
- * A {@link java.util.Queue} that additionally supports operations
- * that wait for the queue to become non-empty when retrieving an
- * element, and wait for space to become available in the queue when
- * storing an element.
+ * A {@link Queue} that additionally supports operations that wait for
+ * the queue to become non-empty when retrieving an element, and wait
+ * for space to become available in the queue when storing an element.
*
* <p>{@code BlockingQueue} methods come in four forms, with different ways
* of handling operations that cannot be satisfied immediately, but may be
@@ -58,35 +52,35 @@
* and the fourth blocks for only a given maximum time limit before giving
* up. These methods are summarized in the following table:
*
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
* <caption>Summary of BlockingQueue methods</caption>
* <tr>
* <td></td>
- * <td ALIGN=CENTER><em>Throws exception</em></td>
- * <td ALIGN=CENTER><em>Special value</em></td>
- * <td ALIGN=CENTER><em>Blocks</em></td>
- * <td ALIGN=CENTER><em>Times out</em></td>
+ * <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
+ * <th scope="col" style="font-weight:normal; font-style:italic">Special value</th>
+ * <th scope="col" style="font-weight:normal; font-style:italic">Blocks</th>
+ * <th scope="col" style="font-weight:normal; font-style:italic">Times out</th>
* </tr>
* <tr>
- * <td><b>Insert</b></td>
- * <td>{@link #add add(e)}</td>
- * <td>{@link #offer offer(e)}</td>
- * <td>{@link #put put(e)}</td>
+ * <th scope="row" style="text-align:left">Insert</th>
+ * <td>{@link #add(Object) add(e)}</td>
+ * <td>{@link #offer(Object) offer(e)}</td>
+ * <td>{@link #put(Object) put(e)}</td>
* <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
* </tr>
* <tr>
- * <td><b>Remove</b></td>
- * <td>{@link #remove remove()}</td>
- * <td>{@link #poll poll()}</td>
- * <td>{@link #take take()}</td>
+ * <th scope="row" style="text-align:left">Remove</th>
+ * <td>{@link #remove() remove()}</td>
+ * <td>{@link #poll() poll()}</td>
+ * <td>{@link #take() take()}</td>
* <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
* </tr>
* <tr>
- * <td><b>Examine</b></td>
- * <td>{@link #element element()}</td>
- * <td>{@link #peek peek()}</td>
- * <td><em>not applicable</em></td>
- * <td><em>not applicable</em></td>
+ * <th scope="row" style="text-align:left">Examine</th>
+ * <td>{@link #element() element()}</td>
+ * <td>{@link #peek() peek()}</td>
+ * <td style="font-style: italic">not applicable</td>
+ * <td style="font-style: italic">not applicable</td>
* </tr>
* </table>
*
@@ -104,7 +98,7 @@
*
* <p>{@code BlockingQueue} implementations are designed to be used
* primarily for producer-consumer queues, but additionally support
- * the {@link java.util.Collection} interface. So, for example, it is
+ * the {@link Collection} interface. So, for example, it is
* possible to remove an arbitrary element from a queue using
* {@code remove(x)}. However, such operations are in general
* <em>not</em> performed very efficiently, and are intended for only
@@ -174,7 +168,10 @@
* actions subsequent to the access or removal of that element from
* the {@code BlockingQueue} in another thread.
*
- * @since 1.5
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @author Doug Lea
* @param <E> the type of elements held in this queue
*/
@@ -304,9 +301,9 @@
* @return {@code true} if this queue changed as a result of the call
* @throws ClassCastException if the class of the specified element
* is incompatible with this queue
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
@@ -319,9 +316,9 @@
* @return {@code true} if this queue contains the specified element
* @throws ClassCastException if the class of the specified element
* is incompatible with this queue
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean contains(Object o);
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java b/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
index e98e1be..936ffc3 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletableFuture.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@@ -110,9 +112,9 @@
* in a {@link NullPointerException} being thrown.
*
* @author Doug Lea
- * @since 1.8
* @param <T> The result type returned by this future's {@code join}
* and {@code get} methods
+ * @since 1.8
*/
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
@@ -125,26 +127,29 @@
* applies across normal vs exceptional outcomes, sync vs async
* actions, binary triggers, and various forms of completions.
*
- * Non-nullness of field result (set via CAS) indicates done. An
- * AltResult is used to box null as a result, as well as to hold
- * exceptions. Using a single field makes completion simple to
- * detect and trigger. Encoding and decoding is straightforward
- * but adds to the sprawl of trapping and associating exceptions
- * with targets. Minor simplifications rely on (static) NIL (to
- * box null results) being the only AltResult with a null
- * exception field, so we don't usually need explicit comparisons.
- * Even though some of the generics casts are unchecked (see
- * SuppressWarnings annotations), they are placed to be
- * appropriate even if checked.
+ * Non-nullness of volatile field "result" indicates done. It may
+ * be set directly if known to be thread-confined, else via CAS.
+ * An AltResult is used to box null as a result, as well as to
+ * hold exceptions. Using a single field makes completion simple
+ * to detect and trigger. Result encoding and decoding is
+ * straightforward but tedious and adds to the sprawl of trapping
+ * and associating exceptions with targets. Minor simplifications
+ * rely on (static) NIL (to box null results) being the only
+ * AltResult with a null exception field, so we don't usually need
+ * explicit comparisons. Even though some of the generics casts
+ * are unchecked (see SuppressWarnings annotations), they are
+ * placed to be appropriate even if checked.
*
* Dependent actions are represented by Completion objects linked
* as Treiber stacks headed by field "stack". There are Completion
- * classes for each kind of action, grouped into single-input
- * (UniCompletion), two-input (BiCompletion), projected
- * (BiCompletions using either (not both) of two inputs), shared
- * (CoCompletion, used by the second of two sources), zero-input
- * source actions, and Signallers that unblock waiters. Class
- * Completion extends ForkJoinTask to enable async execution
+ * classes for each kind of action, grouped into:
+ * - single-input (UniCompletion),
+ * - two-input (BiCompletion),
+ * - projected (BiCompletions using exactly one of two inputs),
+ * - shared (CoCompletion, used by the second of two sources),
+ * - zero-input source actions,
+ * - Signallers that unblock waiters.
+ * Class Completion extends ForkJoinTask to enable async execution
* (adding no space overhead because we exploit its "tag" methods
* to maintain claims). It is also declared as Runnable to allow
* usage with arbitrary executors.
@@ -160,7 +165,7 @@
* encounter layers of adapters in common usages.
*
* * Boolean CompletableFuture method x(...) (for example
- * uniApply) takes all of the arguments needed to check that an
+ * biApply) takes all of the arguments needed to check that an
* action is triggerable, and then either runs the action or
* arranges its async execution by executing its Completion
* argument, if present. The method returns true if known to be
@@ -170,24 +175,32 @@
* method with its held arguments, and on success cleans up.
* The mode argument allows tryFire to be called twice (SYNC,
* then ASYNC); the first to screen and trap exceptions while
- * arranging to execute, and the second when called from a
- * task. (A few classes are not used async so take slightly
- * different forms.) The claim() callback suppresses function
- * invocation if already claimed by another thread.
+ * arranging to execute, and the second when called from a task.
+ * (A few classes are not used async so take slightly different
+ * forms.) The claim() callback suppresses function invocation
+ * if already claimed by another thread.
+ *
+ * * Some classes (for example UniApply) have separate handling
+ * code for when known to be thread-confined ("now" methods) and
+ * for when shared (in tryFire), for efficiency.
*
* * CompletableFuture method xStage(...) is called from a public
- * stage method of CompletableFuture x. It screens user
+ * stage method of CompletableFuture f. It screens user
* arguments and invokes and/or creates the stage object. If
- * not async and x is already complete, the action is run
- * immediately. Otherwise a Completion c is created, pushed to
- * x's stack (unless done), and started or triggered via
- * c.tryFire. This also covers races possible if x completes
- * while pushing. Classes with two inputs (for example BiApply)
- * deal with races across both while pushing actions. The
- * second completion is a CoCompletion pointing to the first,
- * shared so that at most one performs the action. The
- * multiple-arity methods allOf and anyOf do this pairwise to
- * form trees of completions.
+ * not async and already triggerable, the action is run
+ * immediately. Otherwise a Completion c is created, and
+ * submitted to the executor if triggerable, or pushed onto f's
+ * stack if not. Completion actions are started via c.tryFire.
+ * We recheck after pushing to a source future's stack to cover
+ * possible races if the source completes while pushing.
+ * Classes with two inputs (for example BiApply) deal with races
+ * across both while pushing actions. The second completion is
+ * a CoCompletion pointing to the first, shared so that at most
+ * one performs the action. The multiple-arity methods allOf
+ * does this pairwise to form trees of completions. Method
+ * anyOf is handled differently from allOf because completion of
+ * any source should trigger a cleanStack of other sources.
+ * Each AnyOf completion can reach others via a shared array.
*
* Note that the generic type parameters of methods vary according
* to whether "this" is a source, dependent, or completion.
@@ -212,29 +225,30 @@
* pointing back to its sources. So we null out fields as soon as
* possible. The screening checks needed anyway harmlessly ignore
* null arguments that may have been obtained during races with
- * threads nulling out fields. We also try to unlink fired
- * Completions from stacks that might never be popped (see method
- * postFire). Completion fields need not be declared as final or
- * volatile because they are only visible to other threads upon
- * safe publication.
+ * threads nulling out fields. We also try to unlink non-isLive
+ * (fired or cancelled) Completions from stacks that might
+ * otherwise never be popped: Method cleanStack always unlinks non
+ * isLive completions from the head of stack; others may
+ * occasionally remain if racing with other cancellations or
+ * removals.
+ *
+ * Completion fields need not be declared as final or volatile
+ * because they are only visible to other threads upon safe
+ * publication.
*/
volatile Object result; // Either the result or boxed AltResult
volatile Completion stack; // Top of Treiber stack of dependent actions
final boolean internalComplete(Object r) { // CAS from null to r
- return U.compareAndSwapObject(this, RESULT, null, r);
- }
-
- final boolean casStack(Completion cmp, Completion val) {
- return U.compareAndSwapObject(this, STACK, cmp, val);
+ return RESULT.compareAndSet(this, null, r);
}
/** Returns true if successfully pushed c onto stack. */
final boolean tryPushStack(Completion c) {
Completion h = stack;
- lazySetNext(c, h);
- return U.compareAndSwapObject(this, STACK, h, c);
+ NEXT.set(c, h); // CAS piggyback
+ return STACK.compareAndSet(this, h, c);
}
/** Unconditionally pushes c onto stack, retrying if necessary. */
@@ -254,8 +268,7 @@
/** Completes with the null value, unless already completed. */
final boolean completeNull() {
- return U.compareAndSwapObject(this, RESULT, null,
- NIL);
+ return RESULT.compareAndSet(this, null, NIL);
}
/** Returns the encoding of the given non-exceptional value. */
@@ -265,8 +278,7 @@
/** Completes with a non-exceptional result, unless already completed. */
final boolean completeValue(T t) {
- return U.compareAndSwapObject(this, RESULT, null,
- (t == null) ? NIL : t);
+ return RESULT.compareAndSet(this, null, (t == null) ? NIL : t);
}
/**
@@ -280,8 +292,7 @@
/** Completes with an exceptional result, unless already completed. */
final boolean completeThrowable(Throwable x) {
- return U.compareAndSwapObject(this, RESULT, null,
- encodeThrowable(x));
+ return RESULT.compareAndSet(this, null, encodeThrowable(x));
}
/**
@@ -308,8 +319,7 @@
* existing CompletionException.
*/
final boolean completeThrowable(Throwable x, Object r) {
- return U.compareAndSwapObject(this, RESULT, null,
- encodeThrowable(x, r));
+ return RESULT.compareAndSet(this, null, encodeThrowable(x, r));
}
/**
@@ -327,10 +337,11 @@
*/
static Object encodeRelay(Object r) {
Throwable x;
- return (((r instanceof AltResult) &&
- (x = ((AltResult)r).ex) != null &&
- !(x instanceof CompletionException)) ?
- new AltResult(new CompletionException(x)) : r);
+ if (r instanceof AltResult
+ && (x = ((AltResult)r).ex) != null
+ && !(x instanceof CompletionException))
+ r = new AltResult(new CompletionException(x));
+ return r;
}
/**
@@ -338,14 +349,13 @@
* If exceptional, r is first coerced to a CompletionException.
*/
final boolean completeRelay(Object r) {
- return U.compareAndSwapObject(this, RESULT, null,
- encodeRelay(r));
+ return RESULT.compareAndSet(this, null, encodeRelay(r));
}
/**
* Reports result using Future.get conventions.
*/
- private static <T> T reportGet(Object r)
+ private static Object reportGet(Object r)
throws InterruptedException, ExecutionException {
if (r == null) // by convention below, null means interrupted
throw new InterruptedException();
@@ -360,14 +370,13 @@
x = cause;
throw new ExecutionException(x);
}
- @SuppressWarnings("unchecked") T t = (T) r;
- return t;
+ return r;
}
/**
* Decodes outcome to return result or throw unchecked exception.
*/
- private static <T> T reportJoin(Object r) {
+ private static Object reportJoin(Object r) {
if (r instanceof AltResult) {
Throwable x;
if ((x = ((AltResult)r).ex) == null)
@@ -378,8 +387,7 @@
throw (CompletionException)x;
throw new CompletionException(x);
}
- @SuppressWarnings("unchecked") T t = (T) r;
- return t;
+ return r;
}
/* ------------- Async task preliminaries -------------- */
@@ -425,12 +433,6 @@
static final int ASYNC = 1;
static final int NESTED = -1;
- /**
- * Spins before blocking in waitingGet
- */
- static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ?
- 1 << 8 : 0);
-
/* ------------- Base Completion classes and operations -------------- */
@SuppressWarnings("serial")
@@ -455,10 +457,6 @@
public final void setRawResult(Void v) {}
}
- static void lazySetNext(Completion c, Completion next) {
- U.putOrderedObject(c, NEXT, next);
- }
-
/**
* Pops and tries to trigger all reachable dependents. Call only
* when known to be done.
@@ -473,40 +471,47 @@
while ((h = f.stack) != null ||
(f != this && (h = (f = this).stack) != null)) {
CompletableFuture<?> d; Completion t;
- if (f.casStack(h, t = h.next)) {
+ if (STACK.compareAndSet(f, h, t = h.next)) {
if (t != null) {
if (f != this) {
pushStack(h);
continue;
}
- h.next = null; // detach
+ NEXT.compareAndSet(h, t, null); // try to detach
}
f = (d = h.tryFire(NESTED)) == null ? this : d;
}
}
}
- /** Traverses stack and unlinks dead Completions. */
+ /** Traverses stack and unlinks one or more dead Completions, if found. */
final void cleanStack() {
- for (Completion p = null, q = stack; q != null;) {
+ Completion p = stack;
+ // ensure head of stack live
+ for (boolean unlinked = false;;) {
+ if (p == null)
+ return;
+ else if (p.isLive()) {
+ if (unlinked)
+ return;
+ else
+ break;
+ }
+ else if (STACK.weakCompareAndSet(this, p, (p = p.next)))
+ unlinked = true;
+ else
+ p = stack;
+ }
+ // try to unlink first non-live
+ for (Completion q = p.next; q != null;) {
Completion s = q.next;
if (q.isLive()) {
p = q;
q = s;
- }
- else if (p == null) {
- casStack(q, s);
- q = stack;
- }
- else {
- p.next = s;
- if (p.isLive())
- q = s;
- else {
- p = null; // restart
- q = stack;
- }
- }
+ } else if (NEXT.weakCompareAndSet(p, q, s))
+ break;
+ else
+ q = p.next;
}
}
@@ -544,24 +549,34 @@
final boolean isLive() { return dep != null; }
}
- /** Pushes the given completion (if it exists) unless done. */
- final void push(UniCompletion<?,?> c) {
+ /**
+ * Pushes the given completion unless it completes while trying.
+ * Caller should first check that result is null.
+ */
+ final void unipush(Completion c) {
if (c != null) {
- while (result == null && !tryPushStack(c))
- lazySetNext(c, null); // clear on failure
+ while (!tryPushStack(c)) {
+ if (result != null) {
+ NEXT.set(c, null);
+ break;
+ }
+ }
+ if (result != null)
+ c.tryFire(SYNC);
}
}
/**
- * Post-processing by dependent after successful UniCompletion
- * tryFire. Tries to clean stack of source a, and then either runs
- * postComplete or returns this to caller, depending on mode.
+ * Post-processing by dependent after successful UniCompletion tryFire.
+ * Tries to clean stack of source a, and then either runs postComplete
+ * or returns this to caller, depending on mode.
*/
final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
if (a != null && a.stack != null) {
- if (mode < 0 || a.result == null)
+ Object r;
+ if ((r = a.result) == null)
a.cleanStack();
- else
+ if (mode >= 0 && (r != null || a.result != null))
a.postComplete();
}
if (result != null && stack != null) {
@@ -583,48 +598,65 @@
}
final CompletableFuture<V> tryFire(int mode) {
CompletableFuture<V> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniApply(a = src, fn, mode > 0 ? null : this))
+ Object r; Throwable x; Function<? super T,? extends V> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null)
return null;
+ tryComplete: if (d.result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ else {
+ @SuppressWarnings("unchecked") T t = (T) r;
+ d.completeValue(f.apply(t));
+ }
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final <S> boolean uniApply(CompletableFuture<S> a,
- Function<? super S,? extends T> f,
- UniApply<S,T> c) {
- Object r; Throwable x;
- if (a == null || (r = a.result) == null || f == null)
- return false;
- tryComplete: if (result == null) {
- if (r instanceof AltResult) {
- if ((x = ((AltResult)r).ex) != null) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- try {
- if (c != null && !c.claim())
- return false;
- @SuppressWarnings("unchecked") S s = (S) r;
- completeValue(f.apply(s));
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private <V> CompletableFuture<V> uniApplyStage(
Executor e, Function<? super T,? extends V> f) {
if (f == null) throw new NullPointerException();
+ Object r;
+ if ((r = result) != null)
+ return uniApplyNow(r, e, f);
CompletableFuture<V> d = newIncompleteFuture();
- if (e != null || !d.uniApply(this, f, null)) {
- UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
+ unipush(new UniApply<T,V>(e, d, this, f));
+ return d;
+ }
+
+ private <V> CompletableFuture<V> uniApplyNow(
+ Object r, Executor e, Function<? super T,? extends V> f) {
+ Throwable x;
+ CompletableFuture<V> d = newIncompleteFuture();
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.result = encodeThrowable(x, r);
+ return d;
+ }
+ r = null;
+ }
+ try {
+ if (e != null) {
+ e.execute(new UniApply<T,V>(null, d, this, f));
+ } else {
+ @SuppressWarnings("unchecked") T t = (T) r;
+ d.result = d.encodeValue(f.apply(t));
+ }
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
}
return d;
}
@@ -638,48 +670,67 @@
}
final CompletableFuture<Void> tryFire(int mode) {
CompletableFuture<Void> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+ Object r; Throwable x; Consumer<? super T> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null)
return null;
+ tryComplete: if (d.result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ else {
+ @SuppressWarnings("unchecked") T t = (T) r;
+ f.accept(t);
+ d.completeNull();
+ }
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final <S> boolean uniAccept(CompletableFuture<S> a,
- Consumer<? super S> f, UniAccept<S> c) {
- Object r; Throwable x;
- if (a == null || (r = a.result) == null || f == null)
- return false;
- tryComplete: if (result == null) {
- if (r instanceof AltResult) {
- if ((x = ((AltResult)r).ex) != null) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- try {
- if (c != null && !c.claim())
- return false;
- @SuppressWarnings("unchecked") S s = (S) r;
- f.accept(s);
- completeNull();
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private CompletableFuture<Void> uniAcceptStage(Executor e,
Consumer<? super T> f) {
if (f == null) throw new NullPointerException();
+ Object r;
+ if ((r = result) != null)
+ return uniAcceptNow(r, e, f);
CompletableFuture<Void> d = newIncompleteFuture();
- if (e != null || !d.uniAccept(this, f, null)) {
- UniAccept<T> c = new UniAccept<T>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
+ unipush(new UniAccept<T>(e, d, this, f));
+ return d;
+ }
+
+ private CompletableFuture<Void> uniAcceptNow(
+ Object r, Executor e, Consumer<? super T> f) {
+ Throwable x;
+ CompletableFuture<Void> d = newIncompleteFuture();
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.result = encodeThrowable(x, r);
+ return d;
+ }
+ r = null;
+ }
+ try {
+ if (e != null) {
+ e.execute(new UniAccept<T>(null, d, this, f));
+ } else {
+ @SuppressWarnings("unchecked") T t = (T) r;
+ f.accept(t);
+ d.result = NIL;
+ }
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
}
return d;
}
@@ -693,42 +744,56 @@
}
final CompletableFuture<Void> tryFire(int mode) {
CompletableFuture<Void> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniRun(a = src, fn, mode > 0 ? null : this))
+ Object r; Throwable x; Runnable f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null)
return null;
+ if (d.result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ d.completeThrowable(x, r);
+ else
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ else {
+ f.run();
+ d.completeNull();
+ }
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
- Object r; Throwable x;
- if (a == null || (r = a.result) == null || f == null)
- return false;
- if (result == null) {
- if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
- completeThrowable(x, r);
- else
- try {
- if (c != null && !c.claim())
- return false;
- f.run();
- completeNull();
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
if (f == null) throw new NullPointerException();
+ Object r;
+ if ((r = result) != null)
+ return uniRunNow(r, e, f);
CompletableFuture<Void> d = newIncompleteFuture();
- if (e != null || !d.uniRun(this, f, null)) {
- UniRun<T> c = new UniRun<T>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
- }
+ unipush(new UniRun<T>(e, d, this, f));
+ return d;
+ }
+
+ private CompletableFuture<Void> uniRunNow(Object r, Executor e, Runnable f) {
+ Throwable x;
+ CompletableFuture<Void> d = newIncompleteFuture();
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ d.result = encodeThrowable(x, r);
+ else
+ try {
+ if (e != null) {
+ e.execute(new UniRun<T>(null, d, this, f));
+ } else {
+ f.run();
+ d.result = NIL;
+ }
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
return d;
}
@@ -742,20 +807,20 @@
}
final CompletableFuture<T> tryFire(int mode) {
CompletableFuture<T> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+ Object r; BiConsumer<? super T, ? super Throwable> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null
+ || !d.uniWhenComplete(r, f, mode > 0 ? null : this))
return null;
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final boolean uniWhenComplete(CompletableFuture<T> a,
+ final boolean uniWhenComplete(Object r,
BiConsumer<? super T,? super Throwable> f,
UniWhenComplete<T> c) {
- Object r; T t; Throwable x = null;
- if (a == null || (r = a.result) == null || f == null)
- return false;
+ T t; Throwable x = null;
if (result == null) {
try {
if (c != null && !c.claim())
@@ -787,10 +852,17 @@
Executor e, BiConsumer<? super T, ? super Throwable> f) {
if (f == null) throw new NullPointerException();
CompletableFuture<T> d = newIncompleteFuture();
- if (e != null || !d.uniWhenComplete(this, f, null)) {
- UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
+ Object r;
+ if ((r = result) == null)
+ unipush(new UniWhenComplete<T>(e, d, this, f));
+ else if (e == null)
+ d.uniWhenComplete(r, f, null);
+ else {
+ try {
+ e.execute(new UniWhenComplete<T>(null, d, this, f));
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
}
return d;
}
@@ -805,20 +877,20 @@
}
final CompletableFuture<V> tryFire(int mode) {
CompletableFuture<V> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+ Object r; BiFunction<? super T, Throwable, ? extends V> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null
+ || !d.uniHandle(r, f, mode > 0 ? null : this))
return null;
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final <S> boolean uniHandle(CompletableFuture<S> a,
+ final <S> boolean uniHandle(Object r,
BiFunction<? super S, Throwable, ? extends T> f,
UniHandle<S,T> c) {
- Object r; S s; Throwable x;
- if (a == null || (r = a.result) == null || f == null)
- return false;
+ S s; Throwable x;
if (result == null) {
try {
if (c != null && !c.claim())
@@ -843,10 +915,17 @@
Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
if (f == null) throw new NullPointerException();
CompletableFuture<V> d = newIncompleteFuture();
- if (e != null || !d.uniHandle(this, f, null)) {
- UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
+ Object r;
+ if ((r = result) == null)
+ unipush(new UniHandle<T,V>(e, d, this, f));
+ else if (e == null)
+ d.uniHandle(r, f, null);
+ else {
+ try {
+ e.execute(new UniHandle<T,V>(null, d, this, f));
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
}
return d;
}
@@ -861,19 +940,20 @@
final CompletableFuture<T> tryFire(int mode) { // never ASYNC
// assert mode != ASYNC;
CompletableFuture<T> d; CompletableFuture<T> a;
- if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+ Object r; Function<? super Throwable, ? extends T> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null
+ || !d.uniExceptionally(r, f, this))
return null;
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final boolean uniExceptionally(CompletableFuture<T> a,
+ final boolean uniExceptionally(Object r,
Function<? super Throwable, ? extends T> f,
UniExceptionally<T> c) {
- Object r; Throwable x;
- if (a == null || (r = a.result) == null || f == null)
- return false;
+ Throwable x;
if (result == null) {
try {
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
@@ -893,47 +973,39 @@
Function<Throwable, ? extends T> f) {
if (f == null) throw new NullPointerException();
CompletableFuture<T> d = newIncompleteFuture();
- if (!d.uniExceptionally(this, f, null)) {
- UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
- push(c);
- c.tryFire(SYNC);
- }
+ Object r;
+ if ((r = result) == null)
+ unipush(new UniExceptionally<T>(d, this, f));
+ else
+ d.uniExceptionally(r, f, null);
return d;
}
@SuppressWarnings("serial")
- static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
- UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+ static final class UniRelay<U, T extends U> extends UniCompletion<T,U> {
+ UniRelay(CompletableFuture<U> dep, CompletableFuture<T> src) {
super(null, dep, src);
}
- final CompletableFuture<T> tryFire(int mode) {
- CompletableFuture<T> d; CompletableFuture<T> a;
- if ((d = dep) == null || !d.uniRelay(a = src))
+ final CompletableFuture<U> tryFire(int mode) {
+ CompletableFuture<U> d; CompletableFuture<T> a; Object r;
+ if ((d = dep) == null
+ || (a = src) == null || (r = a.result) == null)
return null;
+ if (d.result == null)
+ d.completeRelay(r);
src = null; dep = null;
return d.postFire(a, mode);
}
}
- final boolean uniRelay(CompletableFuture<T> a) {
+ private static <U, T extends U> CompletableFuture<U> uniCopyStage(
+ CompletableFuture<T> src) {
Object r;
- if (a == null || (r = a.result) == null)
- return false;
- if (result == null) // no need to claim
- completeRelay(r);
- return true;
- }
-
- private CompletableFuture<T> uniCopyStage() {
- Object r;
- CompletableFuture<T> d = newIncompleteFuture();
- if ((r = result) != null)
- d.completeRelay(r);
- else {
- UniRelay<T> c = new UniRelay<T>(d, this);
- push(c);
- c.tryFire(SYNC);
- }
+ CompletableFuture<U> d = src.newIncompleteFuture();
+ if ((r = src.result) != null)
+ d.result = encodeRelay(r);
+ else
+ src.unipush(new UniRelay<U,T>(d, src));
return d;
}
@@ -942,9 +1014,7 @@
if ((r = result) != null)
return new MinimalStage<T>(encodeRelay(r));
MinimalStage<T> d = new MinimalStage<T>();
- UniRelay<T> c = new UniRelay<T>(d, this);
- push(c);
- c.tryFire(SYNC);
+ unipush(new UniRelay<T,T>(d, this));
return d;
}
@@ -958,54 +1028,48 @@
}
final CompletableFuture<V> tryFire(int mode) {
CompletableFuture<V> d; CompletableFuture<T> a;
- if ((d = dep) == null ||
- !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+ Function<? super T, ? extends CompletionStage<V>> f;
+ Object r; Throwable x;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null)
return null;
+ tryComplete: if (d.result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ @SuppressWarnings("unchecked") T t = (T) r;
+ CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+ if ((r = g.result) != null)
+ d.completeRelay(r);
+ else {
+ g.unipush(new UniRelay<V,V>(d, g));
+ if (d.result == null)
+ return null;
+ }
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; fn = null;
return d.postFire(a, mode);
}
}
- final <S> boolean uniCompose(
- CompletableFuture<S> a,
- Function<? super S, ? extends CompletionStage<T>> f,
- UniCompose<S,T> c) {
- Object r; Throwable x;
- if (a == null || (r = a.result) == null || f == null)
- return false;
- tryComplete: if (result == null) {
- if (r instanceof AltResult) {
- if ((x = ((AltResult)r).ex) != null) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- try {
- if (c != null && !c.claim())
- return false;
- @SuppressWarnings("unchecked") S s = (S) r;
- CompletableFuture<T> g = f.apply(s).toCompletableFuture();
- if (g.result == null || !uniRelay(g)) {
- UniRelay<T> copy = new UniRelay<T>(this, g);
- g.push(copy);
- copy.tryFire(SYNC);
- if (result == null)
- return false;
- }
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private <V> CompletableFuture<V> uniComposeStage(
Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
if (f == null) throw new NullPointerException();
- Object r, s; Throwable x;
CompletableFuture<V> d = newIncompleteFuture();
- if (e == null && (r = result) != null) {
+ Object r, s; Throwable x;
+ if ((r = result) == null)
+ unipush(new UniCompose<T,V>(e, d, this, f));
+ else if (e == null) {
if (r instanceof AltResult) {
if ((x = ((AltResult)r).ex) != null) {
d.result = encodeThrowable(x, r);
@@ -1017,21 +1081,20 @@
@SuppressWarnings("unchecked") T t = (T) r;
CompletableFuture<V> g = f.apply(t).toCompletableFuture();
if ((s = g.result) != null)
- d.completeRelay(s);
+ d.result = encodeRelay(s);
else {
- UniRelay<V> c = new UniRelay<V>(d, g);
- g.push(c);
- c.tryFire(SYNC);
+ g.unipush(new UniRelay<V,V>(d, g));
}
- return d;
} catch (Throwable ex) {
d.result = encodeThrowable(ex);
- return d;
}
}
- UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
- push(c);
- c.tryFire(SYNC);
+ else
+ try {
+ e.execute(new UniCompose<T,V>(null, d, this, f));
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
return d;
}
@@ -1061,21 +1124,28 @@
}
final boolean isLive() {
BiCompletion<?,?,?> c;
- return (c = base) != null && c.dep != null;
+ return (c = base) != null
+ // && c.isLive()
+ && c.dep != null;
}
}
- /** Pushes completion to this and b unless both done. */
+ /**
+ * Pushes completion to this and b unless both done.
+ * Caller should first check that either result or b.result is null.
+ */
final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
if (c != null) {
- Object r;
- while ((r = result) == null && !tryPushStack(c))
- lazySetNext(c, null); // clear on failure
- if (b != null && b != this && b.result == null) {
- Completion q = (r != null) ? c : new CoCompletion(c);
- while (b.result == null && !b.tryPushStack(q))
- lazySetNext(q, null); // clear on failure
+ while (result == null) {
+ if (tryPushStack(c)) {
+ if (b.result == null)
+ b.unipush(new CoCompletion(c));
+ else if (result != null)
+ c.tryFire(SYNC);
+ return;
+ }
}
+ b.unipush(c);
}
}
@@ -1083,9 +1153,10 @@
final CompletableFuture<T> postFire(CompletableFuture<?> a,
CompletableFuture<?> b, int mode) {
if (b != null && b.stack != null) { // clean second source
- if (mode < 0 || b.result == null)
+ Object r;
+ if ((r = b.result) == null)
b.cleanStack();
- else
+ if (mode >= 0 && (r != null || b.result != null))
b.postComplete();
}
return postFire(a, mode);
@@ -1103,22 +1174,21 @@
CompletableFuture<V> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+ Object r, s; BiFunction<? super T,? super U,? extends V> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null
+ || (b = snd) == null || (s = b.result) == null
+ || !d.biApply(r, s, f, mode > 0 ? null : this))
return null;
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
}
- final <R,S> boolean biApply(CompletableFuture<R> a,
- CompletableFuture<S> b,
+ final <R,S> boolean biApply(Object r, Object s,
BiFunction<? super R,? super S,? extends T> f,
BiApply<R,S,T> c) {
- Object r, s; Throwable x;
- if (a == null || (r = a.result) == null ||
- b == null || (s = b.result) == null || f == null)
- return false;
+ Throwable x;
tryComplete: if (result == null) {
if (r instanceof AltResult) {
if ((x = ((AltResult)r).ex) != null) {
@@ -1150,15 +1220,20 @@
private <U,V> CompletableFuture<V> biApplyStage(
Executor e, CompletionStage<U> o,
BiFunction<? super T,? super U,? extends V> f) {
- CompletableFuture<U> b;
+ CompletableFuture<U> b; Object r, s;
if (f == null || (b = o.toCompletableFuture()) == null)
throw new NullPointerException();
CompletableFuture<V> d = newIncompleteFuture();
- if (e != null || !d.biApply(this, b, f, null)) {
- BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
- bipush(b, c);
- c.tryFire(SYNC);
- }
+ if ((r = result) == null || (s = b.result) == null)
+ bipush(b, new BiApply<T,U,V>(e, d, this, b, f));
+ else if (e == null)
+ d.biApply(r, s, f, null);
+ else
+ try {
+ e.execute(new BiApply<T,U,V>(null, d, this, b, f));
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
return d;
}
@@ -1174,22 +1249,21 @@
CompletableFuture<Void> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+ Object r, s; BiConsumer<? super T,? super U> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null
+ || (b = snd) == null || (s = b.result) == null
+ || !d.biAccept(r, s, f, mode > 0 ? null : this))
return null;
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
}
- final <R,S> boolean biAccept(CompletableFuture<R> a,
- CompletableFuture<S> b,
+ final <R,S> boolean biAccept(Object r, Object s,
BiConsumer<? super R,? super S> f,
BiAccept<R,S> c) {
- Object r, s; Throwable x;
- if (a == null || (r = a.result) == null ||
- b == null || (s = b.result) == null || f == null)
- return false;
+ Throwable x;
tryComplete: if (result == null) {
if (r instanceof AltResult) {
if ((x = ((AltResult)r).ex) != null) {
@@ -1222,15 +1296,20 @@
private <U> CompletableFuture<Void> biAcceptStage(
Executor e, CompletionStage<U> o,
BiConsumer<? super T,? super U> f) {
- CompletableFuture<U> b;
+ CompletableFuture<U> b; Object r, s;
if (f == null || (b = o.toCompletableFuture()) == null)
throw new NullPointerException();
CompletableFuture<Void> d = newIncompleteFuture();
- if (e != null || !d.biAccept(this, b, f, null)) {
- BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
- bipush(b, c);
- c.tryFire(SYNC);
- }
+ if ((r = result) == null || (s = b.result) == null)
+ bipush(b, new BiAccept<T,U>(e, d, this, b, f));
+ else if (e == null)
+ d.biAccept(r, s, f, null);
+ else
+ try {
+ e.execute(new BiAccept<T,U>(null, d, this, b, f));
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
return d;
}
@@ -1238,8 +1317,7 @@
static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
Runnable fn;
BiRun(Executor executor, CompletableFuture<Void> dep,
- CompletableFuture<T> src,
- CompletableFuture<U> snd,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
Runnable fn) {
super(executor, dep, src, snd); this.fn = fn;
}
@@ -1247,25 +1325,25 @@
CompletableFuture<Void> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+ Object r, s; Runnable f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (r = a.result) == null
+ || (b = snd) == null || (s = b.result) == null
+ || !d.biRun(r, s, f, mode > 0 ? null : this))
return null;
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
}
- final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
- Runnable f, BiRun<?,?> c) {
- Object r, s; Throwable x;
- if (a == null || (r = a.result) == null ||
- b == null || (s = b.result) == null || f == null)
- return false;
+ final boolean biRun(Object r, Object s, Runnable f, BiRun<?,?> c) {
+ Throwable x; Object z;
if (result == null) {
- if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
- completeThrowable(x, r);
- else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
- completeThrowable(x, s);
+ if ((r instanceof AltResult
+ && (x = ((AltResult)(z = r)).ex) != null) ||
+ (s instanceof AltResult
+ && (x = ((AltResult)(z = s)).ex) != null))
+ completeThrowable(x, z);
else
try {
if (c != null && !c.claim())
@@ -1281,52 +1359,52 @@
private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
Runnable f) {
- CompletableFuture<?> b;
+ CompletableFuture<?> b; Object r, s;
if (f == null || (b = o.toCompletableFuture()) == null)
throw new NullPointerException();
CompletableFuture<Void> d = newIncompleteFuture();
- if (e != null || !d.biRun(this, b, f, null)) {
- BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
- bipush(b, c);
- c.tryFire(SYNC);
- }
+ if ((r = result) == null || (s = b.result) == null)
+ bipush(b, new BiRun<>(e, d, this, b, f));
+ else if (e == null)
+ d.biRun(r, s, f, null);
+ else
+ try {
+ e.execute(new BiRun<>(null, d, this, b, f));
+ } catch (Throwable ex) {
+ d.result = encodeThrowable(ex);
+ }
return d;
}
@SuppressWarnings("serial")
static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
BiRelay(CompletableFuture<Void> dep,
- CompletableFuture<T> src,
- CompletableFuture<U> snd) {
+ CompletableFuture<T> src, CompletableFuture<U> snd) {
super(null, dep, src, snd);
}
final CompletableFuture<Void> tryFire(int mode) {
CompletableFuture<Void> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+ Object r, s, z; Throwable x;
+ if ((d = dep) == null
+ || (a = src) == null || (r = a.result) == null
+ || (b = snd) == null || (s = b.result) == null)
return null;
+ if (d.result == null) {
+ if ((r instanceof AltResult
+ && (x = ((AltResult)(z = r)).ex) != null) ||
+ (s instanceof AltResult
+ && (x = ((AltResult)(z = s)).ex) != null))
+ d.completeThrowable(x, z);
+ else
+ d.completeNull();
+ }
src = null; snd = null; dep = null;
return d.postFire(a, b, mode);
}
}
- boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
- Object r, s; Throwable x;
- if (a == null || (r = a.result) == null ||
- b == null || (s = b.result) == null)
- return false;
- if (result == null) {
- if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
- completeThrowable(x, r);
- else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
- completeThrowable(x, s);
- else
- completeNull();
- }
- return true;
- }
-
/** Recursively constructs a tree of completions. */
static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
int lo, int hi) {
@@ -1334,39 +1412,44 @@
if (lo > hi) // empty
d.result = NIL;
else {
- CompletableFuture<?> a, b;
+ CompletableFuture<?> a, b; Object r, s, z; Throwable x;
int mid = (lo + hi) >>> 1;
if ((a = (lo == mid ? cfs[lo] :
andTree(cfs, lo, mid))) == null ||
(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
andTree(cfs, mid+1, hi))) == null)
throw new NullPointerException();
- if (!d.biRelay(a, b)) {
- BiRelay<?,?> c = new BiRelay<>(d, a, b);
- a.bipush(b, c);
- c.tryFire(SYNC);
- }
+ if ((r = a.result) == null || (s = b.result) == null)
+ a.bipush(b, new BiRelay<>(d, a, b));
+ else if ((r instanceof AltResult
+ && (x = ((AltResult)(z = r)).ex) != null) ||
+ (s instanceof AltResult
+ && (x = ((AltResult)(z = s)).ex) != null))
+ d.result = encodeThrowable(x, z);
+ else
+ d.result = NIL;
}
return d;
}
/* ------------- Projected (Ored) BiCompletions -------------- */
- /** Pushes completion to this and b unless either done. */
+ /**
+ * Pushes completion to this and b unless either done.
+ * Caller should first check that result and b.result are both null.
+ */
final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
if (c != null) {
- while ((b == null || b.result == null) && result == null) {
- if (tryPushStack(c)) {
- if (b != null && b != this && b.result == null) {
- Completion q = new CoCompletion(c);
- while (result == null && b.result == null &&
- !b.tryPushStack(q))
- lazySetNext(q, null); // clear on failure
- }
+ while (!tryPushStack(c)) {
+ if (result != null) {
+ NEXT.set(c, null);
break;
}
- lazySetNext(c, null); // clear on failure
}
+ if (result != null)
+ c.tryFire(SYNC);
+ else
+ b.unipush(new CoCompletion(c));
}
}
@@ -1374,8 +1457,7 @@
static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
Function<? super T,? extends V> fn;
OrApply(Executor executor, CompletableFuture<V> dep,
- CompletableFuture<T> src,
- CompletableFuture<U> snd,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
Function<? super T,? extends V> fn) {
super(executor, dep, src, snd); this.fn = fn;
}
@@ -1383,54 +1465,46 @@
CompletableFuture<V> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+ Object r; Throwable x; Function<? super T,? extends V> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (b = snd) == null
+ || ((r = a.result) == null && (r = b.result) == null))
return null;
+ tryComplete: if (d.result == null) {
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ @SuppressWarnings("unchecked") T t = (T) r;
+ d.completeValue(f.apply(t));
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
}
- final <R,S extends R> boolean orApply(CompletableFuture<R> a,
- CompletableFuture<S> b,
- Function<? super R, ? extends T> f,
- OrApply<R,S,T> c) {
- Object r; Throwable x;
- if (a == null || b == null ||
- ((r = a.result) == null && (r = b.result) == null) || f == null)
- return false;
- tryComplete: if (result == null) {
- try {
- if (c != null && !c.claim())
- return false;
- if (r instanceof AltResult) {
- if ((x = ((AltResult)r).ex) != null) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- @SuppressWarnings("unchecked") R rr = (R) r;
- completeValue(f.apply(rr));
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private <U extends T,V> CompletableFuture<V> orApplyStage(
- Executor e, CompletionStage<U> o,
- Function<? super T, ? extends V> f) {
+ Executor e, CompletionStage<U> o, Function<? super T, ? extends V> f) {
CompletableFuture<U> b;
if (f == null || (b = o.toCompletableFuture()) == null)
throw new NullPointerException();
+
+ Object r; CompletableFuture<? extends T> z;
+ if ((r = (z = this).result) != null ||
+ (r = (z = b).result) != null)
+ return z.uniApplyNow(r, e, f);
+
CompletableFuture<V> d = newIncompleteFuture();
- if (e != null || !d.orApply(this, b, f, null)) {
- OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
- orpush(b, c);
- c.tryFire(SYNC);
- }
+ orpush(b, new OrApply<T,U,V>(e, d, this, b, f));
return d;
}
@@ -1438,8 +1512,7 @@
static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
Consumer<? super T> fn;
OrAccept(Executor executor, CompletableFuture<Void> dep,
- CompletableFuture<T> src,
- CompletableFuture<U> snd,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
Consumer<? super T> fn) {
super(executor, dep, src, snd); this.fn = fn;
}
@@ -1447,54 +1520,47 @@
CompletableFuture<Void> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+ Object r; Throwable x; Consumer<? super T> f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (b = snd) == null
+ || ((r = a.result) == null && (r = b.result) == null))
return null;
+ tryComplete: if (d.result == null) {
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ d.completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ @SuppressWarnings("unchecked") T t = (T) r;
+ f.accept(t);
+ d.completeNull();
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
}
- final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
- CompletableFuture<S> b,
- Consumer<? super R> f,
- OrAccept<R,S> c) {
- Object r; Throwable x;
- if (a == null || b == null ||
- ((r = a.result) == null && (r = b.result) == null) || f == null)
- return false;
- tryComplete: if (result == null) {
- try {
- if (c != null && !c.claim())
- return false;
- if (r instanceof AltResult) {
- if ((x = ((AltResult)r).ex) != null) {
- completeThrowable(x, r);
- break tryComplete;
- }
- r = null;
- }
- @SuppressWarnings("unchecked") R rr = (R) r;
- f.accept(rr);
- completeNull();
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private <U extends T> CompletableFuture<Void> orAcceptStage(
Executor e, CompletionStage<U> o, Consumer<? super T> f) {
CompletableFuture<U> b;
if (f == null || (b = o.toCompletableFuture()) == null)
throw new NullPointerException();
+
+ Object r; CompletableFuture<? extends T> z;
+ if ((r = (z = this).result) != null ||
+ (r = (z = b).result) != null)
+ return z.uniAcceptNow(r, e, f);
+
CompletableFuture<Void> d = newIncompleteFuture();
- if (e != null || !d.orAccept(this, b, f, null)) {
- OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
- orpush(b, c);
- c.tryFire(SYNC);
- }
+ orpush(b, new OrAccept<T,U>(e, d, this, b, f));
return d;
}
@@ -1502,8 +1568,7 @@
static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
Runnable fn;
OrRun(Executor executor, CompletableFuture<Void> dep,
- CompletableFuture<T> src,
- CompletableFuture<U> snd,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
Runnable fn) {
super(executor, dep, src, snd); this.fn = fn;
}
@@ -1511,97 +1576,81 @@
CompletableFuture<Void> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
- if ((d = dep) == null ||
- !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+ Object r; Throwable x; Runnable f;
+ if ((d = dep) == null || (f = fn) == null
+ || (a = src) == null || (b = snd) == null
+ || ((r = a.result) == null && (r = b.result) == null))
return null;
+ if (d.result == null) {
+ try {
+ if (mode <= 0 && !claim())
+ return null;
+ else if (r instanceof AltResult
+ && (x = ((AltResult)r).ex) != null)
+ d.completeThrowable(x, r);
+ else {
+ f.run();
+ d.completeNull();
+ }
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
}
- final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
- Runnable f, OrRun<?,?> c) {
- Object r; Throwable x;
- if (a == null || b == null ||
- ((r = a.result) == null && (r = b.result) == null) || f == null)
- return false;
- if (result == null) {
- try {
- if (c != null && !c.claim())
- return false;
- if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
- completeThrowable(x, r);
- else {
- f.run();
- completeNull();
- }
- } catch (Throwable ex) {
- completeThrowable(ex);
- }
- }
- return true;
- }
-
private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
Runnable f) {
CompletableFuture<?> b;
if (f == null || (b = o.toCompletableFuture()) == null)
throw new NullPointerException();
+
+ Object r; CompletableFuture<?> z;
+ if ((r = (z = this).result) != null ||
+ (r = (z = b).result) != null)
+ return z.uniRunNow(r, e, f);
+
CompletableFuture<Void> d = newIncompleteFuture();
- if (e != null || !d.orRun(this, b, f, null)) {
- OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
- orpush(b, c);
- c.tryFire(SYNC);
- }
+ orpush(b, new OrRun<>(e, d, this, b, f));
return d;
}
+ /** Completion for an anyOf input future. */
@SuppressWarnings("serial")
- static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
- OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
- CompletableFuture<U> snd) {
- super(null, dep, src, snd);
+ static class AnyOf extends Completion {
+ CompletableFuture<Object> dep; CompletableFuture<?> src;
+ CompletableFuture<?>[] srcs;
+ AnyOf(CompletableFuture<Object> dep, CompletableFuture<?> src,
+ CompletableFuture<?>[] srcs) {
+ this.dep = dep; this.src = src; this.srcs = srcs;
}
final CompletableFuture<Object> tryFire(int mode) {
- CompletableFuture<Object> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
- if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+ // assert mode != ASYNC;
+ CompletableFuture<Object> d; CompletableFuture<?> a;
+ CompletableFuture<?>[] as;
+ Object r;
+ if ((d = dep) == null
+ || (a = src) == null || (r = a.result) == null
+ || (as = srcs) == null)
return null;
- src = null; snd = null; dep = null;
- return d.postFire(a, b, mode);
- }
- }
-
- final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
- Object r;
- if (a == null || b == null ||
- ((r = a.result) == null && (r = b.result) == null))
- return false;
- if (result == null)
- completeRelay(r);
- return true;
- }
-
- /** Recursively constructs a tree of completions. */
- static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
- int lo, int hi) {
- CompletableFuture<Object> d = new CompletableFuture<Object>();
- if (lo <= hi) {
- CompletableFuture<?> a, b;
- int mid = (lo + hi) >>> 1;
- if ((a = (lo == mid ? cfs[lo] :
- orTree(cfs, lo, mid))) == null ||
- (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
- orTree(cfs, mid+1, hi))) == null)
- throw new NullPointerException();
- if (!d.orRelay(a, b)) {
- OrRelay<?,?> c = new OrRelay<>(d, a, b);
- a.orpush(b, c);
- c.tryFire(SYNC);
+ dep = null; src = null; srcs = null;
+ if (d.completeRelay(r)) {
+ for (CompletableFuture<?> b : as)
+ if (b != a)
+ b.cleanStack();
+ if (mode < 0)
+ return d;
+ else
+ d.postComplete();
}
+ return null;
}
- return d;
+ final boolean isLive() {
+ CompletableFuture<Object> d;
+ return (d = dep) != null && d.result == null;
+ }
}
/* ------------- Zero-input Async forms -------------- */
@@ -1616,7 +1665,7 @@
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) {}
- public final boolean exec() { run(); return true; }
+ public final boolean exec() { run(); return false; }
public void run() {
CompletableFuture<T> d; Supplier<? extends T> f;
@@ -1652,7 +1701,7 @@
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) {}
- public final boolean exec() { run(); return true; }
+ public final boolean exec() { run(); return false; }
public void run() {
CompletableFuture<Void> d; Runnable f;
@@ -1736,15 +1785,13 @@
private Object waitingGet(boolean interruptible) {
Signaller q = null;
boolean queued = false;
- int spins = SPINS;
Object r;
while ((r = result) == null) {
- if (spins > 0) {
- if (ThreadLocalRandom.nextSecondarySeed() >= 0)
- --spins;
- }
- else if (q == null)
+ if (q == null) {
q = new Signaller(interruptible, 0L, 0L);
+ if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+ ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+ }
else if (!queued)
queued = tryPushStack(q);
else {
@@ -1757,16 +1804,14 @@
break;
}
}
- if (q != null) {
+ if (q != null && queued) {
q.thread = null;
- if (q.interrupted) {
- if (interruptible)
- cleanStack();
- else
- Thread.currentThread().interrupt();
- }
+ if (!interruptible && q.interrupted)
+ Thread.currentThread().interrupt();
+ if (r == null)
+ cleanStack();
}
- if (r != null)
+ if (r != null || (r = result) != null)
postComplete();
return r;
}
@@ -1784,9 +1829,12 @@
Signaller q = null;
boolean queued = false;
Object r;
- while ((r = result) == null) { // similar to untimed, without spins
- if (q == null)
+ while ((r = result) == null) { // similar to untimed
+ if (q == null) {
q = new Signaller(true, nanos, deadline);
+ if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+ ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+ }
else if (!queued)
queued = tryPushStack(q);
else if (q.nanos <= 0L)
@@ -1801,12 +1849,13 @@
break;
}
}
- if (q != null)
+ if (q != null && queued) {
q.thread = null;
- if (r != null)
+ if (r == null)
+ cleanStack();
+ }
+ if (r != null || (r = result) != null)
postComplete();
- else
- cleanStack();
if (r != null || (q != null && q.interrupted))
return r;
}
@@ -1918,9 +1967,12 @@
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
+ @SuppressWarnings("unchecked")
public T get() throws InterruptedException, ExecutionException {
Object r;
- return reportGet((r = result) == null ? waitingGet(true) : r);
+ if ((r = result) == null)
+ r = waitingGet(true);
+ return (T) reportGet(r);
}
/**
@@ -1936,11 +1988,14 @@
* while waiting
* @throws TimeoutException if the wait timed out
*/
+ @SuppressWarnings("unchecked")
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- Object r;
long nanos = unit.toNanos(timeout);
- return reportGet((r = result) == null ? timedGet(nanos) : r);
+ Object r;
+ if ((r = result) == null)
+ r = timedGet(nanos);
+ return (T) reportGet(r);
}
/**
@@ -1957,9 +2012,12 @@
* @throws CompletionException if this future completed
* exceptionally or a completion computation threw an exception
*/
+ @SuppressWarnings("unchecked")
public T join() {
Object r;
- return reportJoin((r = result) == null ? waitingGet(false) : r);
+ if ((r = result) == null)
+ r = waitingGet(false);
+ return (T) reportJoin(r);
}
/**
@@ -1972,9 +2030,10 @@
* @throws CompletionException if this future completed
* exceptionally or a completion computation threw an exception
*/
+ @SuppressWarnings("unchecked")
public T getNow(T valueIfAbsent) {
Object r;
- return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
+ return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r);
}
/**
@@ -2270,7 +2329,28 @@
* {@code null}
*/
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
- return orTree(cfs, 0, cfs.length - 1);
+ int n; Object r;
+ if ((n = cfs.length) <= 1)
+ return (n == 0)
+ ? new CompletableFuture<Object>()
+ : uniCopyStage(cfs[0]);
+ for (CompletableFuture<?> cf : cfs)
+ if ((r = cf.result) != null)
+ return new CompletableFuture<Object>(encodeRelay(r));
+ cfs = cfs.clone();
+ CompletableFuture<Object> d = new CompletableFuture<>();
+ for (CompletableFuture<?> cf : cfs)
+ cf.unipush(new AnyOf(d, cf, cfs));
+ // If d was completed while we were adding completions, we should
+ // clean the stack of any sources that may have had completions
+ // pushed on their stack after d was completed.
+ if (d.result != null)
+ for (int i = 0, len = cfs.length; i < len; i++)
+ if (cfs[i].result != null)
+ for (i++; i < len; i++)
+ if (cfs[i].result == null)
+ cfs[i].cleanStack();
+ return d;
}
/* ------------- Control and status methods -------------- */
@@ -2386,13 +2466,13 @@
for (Completion p = stack; p != null; p = p.next)
++count;
return super.toString() +
- ((r == null) ?
- ((count == 0) ?
- "[Not completed]" :
- "[Not completed, " + count + " dependents]") :
- (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
- "[Completed exceptionally]" :
- "[Completed normally]"));
+ ((r == null)
+ ? ((count == 0)
+ ? "[Not completed]"
+ : "[Not completed, " + count + " dependents]")
+ : (((r instanceof AltResult) && ((AltResult)r).ex != null)
+ ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
+ : "[Completed normally]"));
}
// jdk9 additions
@@ -2442,7 +2522,7 @@
* @since 9
*/
public CompletableFuture<T> copy() {
- return uniCopyStage();
+ return uniCopyStage(this);
}
/**
@@ -2455,6 +2535,13 @@
* exceptionally with a CompletionException with this exception as
* cause.
*
+ * <p>Unless overridden by a subclass, a new non-minimal
+ * CompletableFuture with all methods available can be obtained from
+ * a minimal CompletionStage via {@link #toCompletableFuture()}.
+ * For example, completion of a minimal stage can be awaited by
+ *
+ * <pre> {@code minimalStage.toCompletableFuture().join(); }</pre>
+ *
* @return the new CompletionStage
* @since 9
*/
@@ -2749,23 +2836,30 @@
@Override public CompletableFuture<T> completeOnTimeout
(T value, long timeout, TimeUnit unit) {
throw new UnsupportedOperationException(); }
+ @Override public CompletableFuture<T> toCompletableFuture() {
+ Object r;
+ if ((r = result) != null)
+ return new CompletableFuture<T>(encodeRelay(r));
+ else {
+ CompletableFuture<T> d = new CompletableFuture<>();
+ unipush(new UniRelay<T,T>(d, this));
+ return d;
+ }
+ }
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long RESULT;
- private static final long STACK;
- private static final long NEXT;
+ // VarHandle mechanics
+ private static final VarHandle RESULT;
+ private static final VarHandle STACK;
+ private static final VarHandle NEXT;
static {
try {
- RESULT = U.objectFieldOffset
- (CompletableFuture.class.getDeclaredField("result"));
- STACK = U.objectFieldOffset
- (CompletableFuture.class.getDeclaredField("stack"));
- NEXT = U.objectFieldOffset
- (Completion.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ RESULT = l.findVarHandle(CompletableFuture.class, "result", Object.class);
+ STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
+ NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletionService.java b/ojluni/src/main/java/java/util/concurrent/CompletionService.java
index f647e21..5e5232e 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletionService.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletionService.java
@@ -57,6 +57,8 @@
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
* actions taken by that task, which in turn <i>happen-before</i>
* actions following a successful return from the corresponding {@code take()}.
+ *
+ * @since 1.5
*/
public interface CompletionService<V> {
/**
diff --git a/ojluni/src/main/java/java/util/concurrent/CompletionStage.java b/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
index d855945..70b601a 100644
--- a/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
+++ b/ojluni/src/main/java/java/util/concurrent/CompletionStage.java
@@ -856,13 +856,9 @@
* CompletableFuture, this method may return this stage itself.
* Otherwise, invocation of this method may be equivalent in
* effect to {@code thenApply(x -> x)}, but returning an instance
- * of type {@code CompletableFuture}. A CompletionStage
- * implementation that does not choose to interoperate with others
- * may throw {@code UnsupportedOperationException}.
+ * of type {@code CompletableFuture}.
*
* @return the CompletableFuture
- * @throws UnsupportedOperationException if this implementation
- * does not interoperate with CompletableFuture
*/
public CompletableFuture<T> toCompletableFuture();
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index 5407963..e43eb7d 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -68,10 +68,7 @@
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import jdk.internal.misc.Unsafe;
/**
* A hash table supporting full concurrency of retrievals and
@@ -162,8 +159,7 @@
* ordering, or on any other objects or values that may transiently
* change while computation is in progress; and except for forEach
* actions, should ideally be side-effect-free. Bulk operations on
- * {@link java.util.Map.Entry} objects do not support method {@code
- * setValue}.
+ * {@link Map.Entry} objects do not support method {@code setValue}.
*
* <ul>
* <li>forEach: Performs a given action on each element.
@@ -256,6 +252,10 @@
*
* <p>All arguments to all task methods must be non-null.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.5
* @author Doug Lea
* @param <K> the type of keys maintained by this map
@@ -297,7 +297,7 @@
* Table accesses require volatile/atomic reads, writes, and
* CASes. Because there is no other way to arrange this without
* adding further indirections, we use intrinsics
- * (sun.misc.Unsafe) operations.
+ * (jdk.internal.misc.Unsafe) operations.
*
* We use the top (sign) bit of Node hash fields for control
* purposes -- it is available anyway because of addressing
@@ -628,10 +628,14 @@
volatile V val;
volatile Node<K,V> next;
- Node(int hash, K key, V val, Node<K,V> next) {
+ Node(int hash, K key, V val) {
this.hash = hash;
this.key = key;
this.val = val;
+ }
+
+ Node(int hash, K key, V val, Node<K,V> next) {
+ this(hash, key, val);
this.next = next;
}
@@ -698,12 +702,7 @@
* See Hackers Delight, sec 3.2
*/
private static final int tableSizeFor(int c) {
- int n = c - 1;
- n |= n >>> 1;
- n |= n >>> 2;
- n |= n >>> 4;
- n |= n >>> 8;
- n |= n >>> 16;
+ int n = -1 >>> Integer.numberOfLeadingZeros(c - 1);
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
@@ -713,12 +712,12 @@
*/
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) &&
+ for (Type t : ts) {
+ if ((t instanceof ParameterizedType) &&
((p = (ParameterizedType)t).getRawType() ==
Comparable.class) &&
(as = p.getActualTypeArguments()) != null &&
@@ -743,7 +742,7 @@
/* ---------------- Table element access -------------- */
/*
- * Volatile access methods are used for table elements as well as
+ * Atomic access methods are used for table elements as well as
* elements of in-progress next table while resizing. All uses of
* the tab arguments must be null checked by callers. All callers
* also paranoically precheck that tab's length is not zero (or an
@@ -753,23 +752,21 @@
* errors by users, these checks must operate on local variables,
* which accounts for some odd-looking inline assignments below.
* Note that calls to setTabAt always occur within locked regions,
- * and so in principle require only release ordering, not
- * full volatile semantics, but are currently coded as volatile
- * writes to be conservative.
+ * and so require only release ordering.
*/
@SuppressWarnings("unchecked")
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
- return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+ return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
}
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
- return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+ return U.compareAndSetObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
- U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+ U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
}
/* ---------------- Fields -------------- */
@@ -842,12 +839,7 @@
* elements is negative
*/
public ConcurrentHashMap(int initialCapacity) {
- if (initialCapacity < 0)
- throw new IllegalArgumentException();
- int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
- MAXIMUM_CAPACITY :
- tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
- this.sizeCtl = cap;
+ this(initialCapacity, LOAD_FACTOR, 1);
}
/**
@@ -881,8 +873,8 @@
/**
* Creates a new, empty map with an initial table size based on
- * the given number of elements ({@code initialCapacity}), table
- * density ({@code loadFactor}), and number of concurrently
+ * the given number of elements ({@code initialCapacity}), initial
+ * table density ({@code loadFactor}), and number of concurrently
* updating threads ({@code concurrencyLevel}).
*
* @param initialCapacity the initial capacity. The implementation
@@ -1020,16 +1012,20 @@
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
- Node<K,V> f; int n, i, fh;
+ Node<K,V> f; int n, i, fh; K fk; V fv;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
- if (casTabAt(tab, i, null,
- new Node<K,V>(hash, key, value, null)))
+ if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
+ else if (onlyIfAbsent // check first node without acquiring lock
+ && fh == hash
+ && ((fk = f.key) == key || (fk != null && key.equals(fk)))
+ && (fv = f.val) != null)
+ return fv;
else {
V oldVal = null;
synchronized (f) {
@@ -1048,8 +1044,7 @@
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
- pred.next = new Node<K,V>(hash, key,
- value, null);
+ pred.next = new Node<K,V>(hash, key, value);
break;
}
}
@@ -1245,7 +1240,8 @@
@dalvik.annotation.codegen.CovariantReturnType(returnType = KeySetView.class, presentAfter = 28)
public Set<K> keySet() {
KeySetView<K,V> ks;
- return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
+ if ((ks = keySet) != null) return ks;
+ return keySet = new KeySetView<K,V>(this, null);
}
/**
@@ -1268,7 +1264,8 @@
*/
public Collection<V> values() {
ValuesView<K,V> vs;
- return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
+ if ((vs = values) != null) return vs;
+ return values = new ValuesView<K,V>(this);
}
/**
@@ -1290,7 +1287,8 @@
*/
public Set<Map.Entry<K,V>> entrySet() {
EntrySetView<K,V> es;
- return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
+ if ((es = entrySet) != null) return es;
+ return entrySet = new EntrySetView<K,V>(this);
}
/**
@@ -1391,8 +1389,8 @@
}
/**
- * Saves the state of the {@code ConcurrentHashMap} instance to a
- * stream (i.e., serializes it).
+ * Saves this map to a stream (that is, serializes it).
+ *
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData
@@ -1436,7 +1434,7 @@
}
/**
- * Reconstitutes the instance from a stream (that is, deserializes it).
+ * Reconstitutes this map from a stream (that is, deserializes it).
* @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
@@ -1470,13 +1468,9 @@
if (size == 0L)
sizeCtl = 0;
else {
- int n;
- if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
- n = MAXIMUM_CAPACITY;
- else {
- int sz = (int)size;
- n = tableSizeFor(sz + (sz >>> 1) + 1);
- }
+ long ts = (long)(1.0 + size / LOAD_FACTOR);
+ int n = (ts >= (long)MAXIMUM_CAPACITY) ?
+ MAXIMUM_CAPACITY : tableSizeFor((int)ts);
@SuppressWarnings("unchecked")
Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
int mask = n - 1;
@@ -1703,7 +1697,7 @@
V val = null;
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
- Node<K,V> f; int n, i, fh;
+ Node<K,V> f; int n, i, fh; K fk; V fv;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
@@ -1714,7 +1708,7 @@
Node<K,V> node = null;
try {
if ((val = mappingFunction.apply(key)) != null)
- node = new Node<K,V>(h, key, val, null);
+ node = new Node<K,V>(h, key, val);
} finally {
setTabAt(tab, i, node);
}
@@ -1725,6 +1719,10 @@
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
+ else if (fh == h // check first node without acquiring lock
+ && ((fk = f.key) == key || (fk != null && key.equals(fk)))
+ && (fv = f.val) != null)
+ return fv;
else {
boolean added = false;
synchronized (f) {
@@ -1745,7 +1743,7 @@
if (pred.next != null)
throw new IllegalStateException("Recursive update");
added = true;
- pred.next = new Node<K,V>(h, key, val, null);
+ pred.next = new Node<K,V>(h, key, val);
}
break;
}
@@ -1914,7 +1912,7 @@
try {
if ((val = remappingFunction.apply(key, null)) != null) {
delta = 1;
- node = new Node<K,V>(h, key, val, null);
+ node = new Node<K,V>(h, key, val);
}
} finally {
setTabAt(tab, i, node);
@@ -1956,8 +1954,7 @@
if (pred.next != null)
throw new IllegalStateException("Recursive update");
delta = 1;
- pred.next =
- new Node<K,V>(h, key, val, null);
+ pred.next = new Node<K,V>(h, key, val);
}
break;
}
@@ -2035,7 +2032,7 @@
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
- if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
+ if (casTabAt(tab, i, null, new Node<K,V>(h, key, value))) {
delta = 1;
val = value;
break;
@@ -2070,8 +2067,7 @@
if ((e = e.next) == null) {
delta = 1;
val = value;
- pred.next =
- new Node<K,V>(h, key, val, null);
+ pred.next = new Node<K,V>(h, key, val);
break;
}
}
@@ -2232,7 +2228,7 @@
static final class ForwardingNode<K,V> extends Node<K,V> {
final Node<K,V>[] nextTable;
ForwardingNode(Node<K,V>[] tab) {
- super(MOVED, null, null, null);
+ super(MOVED, null, null);
this.nextTable = tab;
}
@@ -2268,7 +2264,7 @@
*/
static final class ReservationNode<K,V> extends Node<K,V> {
ReservationNode() {
- super(RESERVED, null, null, null);
+ super(RESERVED, null, null);
}
Node<K,V> find(int h, Object k) {
@@ -2294,7 +2290,7 @@
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
- else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+ else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@@ -2323,15 +2319,15 @@
* @param check if <0, don't check resize, if <= 1 only check if uncontended
*/
private final void addCount(long x, int check) {
- CounterCell[] as; long b, s;
- if ((as = counterCells) != null ||
- !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
- CounterCell a; long v; int m;
+ CounterCell[] cs; long b, s;
+ if ((cs = counterCells) != null ||
+ !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+ CounterCell c; long v; int m;
boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
+ if (cs == null || (m = cs.length - 1) < 0 ||
+ (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
!(uncontended =
- U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+ U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
fullAddCount(x, uncontended);
return;
}
@@ -2349,10 +2345,10 @@
sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
transferIndex <= 0)
break;
- if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
+ if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
transfer(tab, nt);
}
- else if (U.compareAndSwapInt(this, SIZECTL, sc,
+ else if (U.compareAndSetInt(this, SIZECTL, sc,
(rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
s = sumCount();
@@ -2373,7 +2369,7 @@
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
sc == rs + MAX_RESIZERS || transferIndex <= 0)
break;
- if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
+ if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
transfer(tab, nextTab);
break;
}
@@ -2396,7 +2392,7 @@
Node<K,V>[] tab = table; int n;
if (tab == null || (n = tab.length) == 0) {
n = (sc > c) ? sc : c;
- if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+ if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
try {
if (table == tab) {
@SuppressWarnings("unchecked")
@@ -2413,7 +2409,7 @@
break;
else if (tab == table) {
int rs = resizeStamp(n);
- if (U.compareAndSwapInt(this, SIZECTL, sc,
+ if (U.compareAndSetInt(this, SIZECTL, sc,
(rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
}
@@ -2454,7 +2450,7 @@
i = -1;
advance = false;
}
- else if (U.compareAndSwapInt
+ else if (U.compareAndSetInt
(this, TRANSFERINDEX, nextIndex,
nextBound = (nextIndex > stride ?
nextIndex - stride : 0))) {
@@ -2471,7 +2467,7 @@
sizeCtl = (n << 1) - (n >>> 1);
return;
}
- if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+ if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
return;
finishing = advance = true;
@@ -2563,21 +2559,19 @@
* A padded cell for distributing counts. Adapted from LongAdder
* and Striped64. See their internal docs for explanation.
*/
- // Android-removed: @Contended, this hint is not used by the Android runtime.
- //@jdk.internal.vm.annotation.Contended
+ @jdk.internal.vm.annotation.Contended
static final class CounterCell {
volatile long value;
CounterCell(long x) { value = x; }
}
final long sumCount() {
- CounterCell[] as = counterCells; CounterCell a;
+ CounterCell[] cs = counterCells;
long sum = baseCount;
- if (as != null) {
- for (int i = 0; i < as.length; ++i) {
- if ((a = as[i]) != null)
- sum += a.value;
- }
+ if (cs != null) {
+ for (CounterCell c : cs)
+ if (c != null)
+ sum += c.value;
}
return sum;
}
@@ -2592,13 +2586,13 @@
}
boolean collide = false; // True if last slot nonempty
for (;;) {
- CounterCell[] as; CounterCell a; int n; long v;
- if ((as = counterCells) != null && (n = as.length) > 0) {
- if ((a = as[(n - 1) & h]) == null) {
+ CounterCell[] cs; CounterCell c; int n; long v;
+ if ((cs = counterCells) != null && (n = cs.length) > 0) {
+ if ((c = cs[(n - 1) & h]) == null) {
if (cellsBusy == 0) { // Try to attach new Cell
CounterCell r = new CounterCell(x); // Optimistic create
if (cellsBusy == 0 &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
boolean created = false;
try { // Recheck under lock
CounterCell[] rs; int m, j;
@@ -2620,21 +2614,17 @@
}
else if (!wasUncontended) // CAS already known to fail
wasUncontended = true; // Continue after rehash
- else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
+ else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
break;
- else if (counterCells != as || n >= NCPU)
+ else if (counterCells != cs || n >= NCPU)
collide = false; // At max size or stale
else if (!collide)
collide = true;
else if (cellsBusy == 0 &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
try {
- if (counterCells == as) {// Expand table unless stale
- CounterCell[] rs = new CounterCell[n << 1];
- for (int i = 0; i < n; ++i)
- rs[i] = as[i];
- counterCells = rs;
- }
+ if (counterCells == cs) // Expand table unless stale
+ counterCells = Arrays.copyOf(cs, n << 1);
} finally {
cellsBusy = 0;
}
@@ -2643,11 +2633,11 @@
}
h = ThreadLocalRandom.advanceProbe(h);
}
- else if (cellsBusy == 0 && counterCells == as &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ else if (cellsBusy == 0 && counterCells == cs &&
+ U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
boolean init = false;
try { // Initialize table
- if (counterCells == as) {
+ if (counterCells == cs) {
CounterCell[] rs = new CounterCell[2];
rs[h & 1] = new CounterCell(x);
counterCells = rs;
@@ -2659,7 +2649,7 @@
if (init)
break;
}
- else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
+ else if (U.compareAndSetLong(this, BASECOUNT, v = baseCount, v + x))
break; // Fall back on using base
}
}
@@ -2697,12 +2687,12 @@
}
/**
- * Returns a list on non-TreeNodes replacing those in given list.
+ * Returns a list of non-TreeNodes replacing those in given list.
*/
static <K,V> Node<K,V> untreeify(Node<K,V> b) {
Node<K,V> hd = null, tl = null;
for (Node<K,V> q = b; q != null; q = q.next) {
- Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
+ Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val);
if (tl == null)
hd = p;
else
@@ -2808,7 +2798,7 @@
* Creates bin with initial set of nodes headed by b.
*/
TreeBin(TreeNode<K,V> b) {
- super(TREEBIN, null, null, null);
+ super(TREEBIN, null, null);
this.first = b;
TreeNode<K,V> r = null;
for (TreeNode<K,V> x = b, next; x != null; x = next) {
@@ -2855,7 +2845,7 @@
* Acquires write lock for tree restructuring.
*/
private final void lockRoot() {
- if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
+ if (!U.compareAndSetInt(this, LOCKSTATE, 0, WRITER))
contendedLock(); // offload to separate method
}
@@ -2873,14 +2863,14 @@
boolean waiting = false;
for (int s;;) {
if (((s = lockState) & ~WAITER) == 0) {
- if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
+ if (U.compareAndSetInt(this, LOCKSTATE, s, WRITER)) {
if (waiting)
waiter = null;
return;
}
}
else if ((s & WAITER) == 0) {
- if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
+ if (U.compareAndSetInt(this, LOCKSTATE, s, s | WAITER)) {
waiting = true;
waiter = Thread.currentThread();
}
@@ -2905,7 +2895,7 @@
return e;
e = e.next;
}
- else if (U.compareAndSwapInt(this, LOCKSTATE, s,
+ else if (U.compareAndSetInt(this, LOCKSTATE, s,
s + READER)) {
TreeNode<K,V> r, p;
try {
@@ -3302,16 +3292,9 @@
return true;
}
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long LOCKSTATE;
- static {
- try {
- LOCKSTATE = U.objectFieldOffset
- (TreeBin.class.getDeclaredField("lockState"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
+ private static final Unsafe U = Unsafe.getUnsafe();
+ private static final long LOCKSTATE
+ = U.objectFieldOffset(TreeBin.class, "lockState");
}
/* ----------------Table Traversal -------------- */
@@ -3465,9 +3448,9 @@
static final class KeyIterator<K,V> extends BaseIterator<K,V>
implements Iterator<K>, Enumeration<K> {
- KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
+ KeyIterator(Node<K,V>[] tab, int size, int index, int limit,
ConcurrentHashMap<K,V> map) {
- super(tab, index, size, limit, map);
+ super(tab, size, index, limit, map);
}
public final K next() {
@@ -3485,9 +3468,9 @@
static final class ValueIterator<K,V> extends BaseIterator<K,V>
implements Iterator<V>, Enumeration<V> {
- ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
+ ValueIterator(Node<K,V>[] tab, int size, int index, int limit,
ConcurrentHashMap<K,V> map) {
- super(tab, index, size, limit, map);
+ super(tab, size, index, limit, map);
}
public final V next() {
@@ -3505,9 +3488,9 @@
static final class EntryIterator<K,V> extends BaseIterator<K,V>
implements Iterator<Map.Entry<K,V>> {
- EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
+ EntryIterator(Node<K,V>[] tab, int size, int index, int limit,
ConcurrentHashMap<K,V> map) {
- super(tab, index, size, limit, map);
+ super(tab, size, index, limit, map);
}
public final Map.Entry<K,V> next() {
@@ -4558,14 +4541,24 @@
return true;
}
- public final boolean removeAll(Collection<?> c) {
+ public boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean modified = false;
- for (Iterator<E> it = iterator(); it.hasNext();) {
- if (c.contains(it.next())) {
- it.remove();
- modified = true;
+ // Use (c instanceof Set) as a hint that lookup in c is as
+ // efficient as this view
+ Node<K,V>[] t;
+ if ((t = map.table) == null) {
+ return false;
+ } else if (c instanceof Set<?> && c.size() > t.length) {
+ for (Iterator<?> it = iterator(); it.hasNext(); ) {
+ if (c.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
}
+ } else {
+ for (Object e : c)
+ modified |= remove(e);
}
return modified;
}
@@ -4751,6 +4744,18 @@
throw new UnsupportedOperationException();
}
+ @Override public boolean removeAll(Collection<?> c) {
+ if (c == null) throw new NullPointerException();
+ boolean modified = false;
+ for (Iterator<V> it = iterator(); it.hasNext();) {
+ if (c.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
public boolean removeIf(Predicate<? super V> filter) {
return map.removeValueIf(filter);
}
@@ -6344,7 +6349,7 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
@@ -6354,30 +6359,29 @@
private static final int ASHIFT;
static {
- try {
- SIZECTL = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
- TRANSFERINDEX = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
- BASECOUNT = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("baseCount"));
- CELLSBUSY = U.objectFieldOffset
- (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
+ SIZECTL = U.objectFieldOffset
+ (ConcurrentHashMap.class, "sizeCtl");
+ TRANSFERINDEX = U.objectFieldOffset
+ (ConcurrentHashMap.class, "transferIndex");
+ BASECOUNT = U.objectFieldOffset
+ (ConcurrentHashMap.class, "baseCount");
+ CELLSBUSY = U.objectFieldOffset
+ (ConcurrentHashMap.class, "cellsBusy");
- CELLVALUE = U.objectFieldOffset
- (CounterCell.class.getDeclaredField("value"));
+ CELLVALUE = U.objectFieldOffset
+ (CounterCell.class, "value");
- ABASE = U.arrayBaseOffset(Node[].class);
- int scale = U.arrayIndexScale(Node[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
+ ABASE = U.arrayBaseOffset(Node[].class);
+ int scale = U.arrayIndexScale(Node[].class);
+ if ((scale & (scale - 1)) != 0)
+ throw new ExceptionInInitializerError("array index scale not a power of two");
+ ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
// Reduce the risk of rare disastrous classloading in first call to
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
Class<?> ensureLoaded = LockSupport.class;
+
+ // Eager class load observed to help JIT during startup
+ ensureLoaded = ReservationNode.class;
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 3edde54..91ddabd 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
@@ -46,10 +48,7 @@
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
/**
* An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
@@ -68,12 +67,12 @@
* asynchronous nature of these deques, determining the current number
* of elements requires a traversal of the elements, and so may report
* inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
*
* <p>This class and its iterator implement all of the <em>optional</em>
* methods of the {@link Deque} and {@link Iterator} interfaces.
@@ -85,6 +84,10 @@
* actions subsequent to the access or removal of that element from
* the {@code ConcurrentLinkedDeque} in another thread.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.7
* @author Doug Lea
* @author Martin Buchholz
@@ -228,15 +231,16 @@
*
* The implementation is completely directionally symmetrical,
* except that most public methods that iterate through the list
- * follow next pointers ("forward" direction).
+ * follow next pointers, in the "forward" direction.
*
- * We believe (without full proof) that all single-element deque
- * operations (e.g., addFirst, peekLast, pollLast) are linearizable
- * (see Herlihy and Shavit's book). However, some combinations of
+ * We believe (without full proof) that all single-element Deque
+ * operations that operate directly at the two ends of the Deque
+ * (e.g., addFirst, peekLast, pollLast) are linearizable (see
+ * Herlihy and Shavit's book). However, some combinations of
* operations are known not to be linearizable. In particular,
- * when an addFirst(A) is racing with pollFirst() removing B, it is
- * possible for an observer iterating over the elements to observe
- * A B C and subsequently observe A C, even though no interior
+ * when an addFirst(A) is racing with pollFirst() removing B, it
+ * is possible for an observer iterating over the elements to
+ * observe first [A B C] and then [A C], even though no interior
* removes are ever performed. Nevertheless, iterators behave
* reasonably, providing the "weakly consistent" guarantees.
*
@@ -292,64 +296,23 @@
volatile Node<E> prev;
volatile E item;
volatile Node<E> next;
+ }
- Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
- }
-
- /**
- * Constructs a new node. Uses relaxed write because item can
- * only be seen after publication via casNext or casPrev.
- */
- Node(E item) {
- U.putObject(this, ITEM, item);
- }
-
- boolean casItem(E cmp, E val) {
- return U.compareAndSwapObject(this, ITEM, cmp, val);
- }
-
- void lazySetNext(Node<E> val) {
- U.putOrderedObject(this, NEXT, val);
- }
-
- boolean casNext(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
- }
-
- void lazySetPrev(Node<E> val) {
- U.putOrderedObject(this, PREV, val);
- }
-
- boolean casPrev(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, PREV, cmp, val);
- }
-
- // Unsafe mechanics
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PREV;
- private static final long ITEM;
- private static final long NEXT;
-
- static {
- try {
- PREV = U.objectFieldOffset
- (Node.class.getDeclaredField("prev"));
- ITEM = U.objectFieldOffset
- (Node.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
+ /**
+ * Returns a new node holding item. Uses relaxed write because item
+ * can only be seen after piggy-backing publication via CAS.
+ */
+ static <E> Node<E> newNode(E item) {
+ Node<E> node = new Node<E>();
+ ITEM.set(node, item);
+ return node;
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
- final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ final Node<E> newNode = newNode(Objects.requireNonNull(e));
restartFromHead:
for (;;)
@@ -363,13 +326,13 @@
continue restartFromHead;
else {
// p is first node
- newNode.lazySetNext(p); // CAS piggyback
- if (p.casPrev(null, newNode)) {
+ NEXT.set(newNode, p); // CAS piggyback
+ if (PREV.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
- if (p != h) // hop two nodes at a time
- casHead(h, newNode); // Failure is OK.
+ if (p != h) // hop two nodes at a time; failure is OK
+ HEAD.weakCompareAndSet(this, h, newNode);
return;
}
// Lost CAS race to another thread; re-read prev
@@ -381,7 +344,7 @@
* Links e as last element.
*/
private void linkLast(E e) {
- final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ final Node<E> newNode = newNode(Objects.requireNonNull(e));
restartFromTail:
for (;;)
@@ -395,13 +358,13 @@
continue restartFromTail;
else {
// p is last node
- newNode.lazySetPrev(p); // CAS piggyback
- if (p.casNext(null, newNode)) {
+ PREV.set(newNode, p); // CAS piggyback
+ if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
- if (p != t) // hop two nodes at a time
- casTail(t, newNode); // Failure is OK.
+ if (p != t) // hop two nodes at a time; failure is OK
+ TAIL.weakCompareAndSet(this, t, newNode);
return;
}
// Lost CAS race to another thread; re-read next
@@ -516,8 +479,8 @@
updateTail(); // Ensure x is not reachable from tail
// Finally, actually gc-unlink
- x.lazySetPrev(isFirst ? prevTerminator() : x);
- x.lazySetNext(isLast ? nextTerminator() : x);
+ PREV.setRelease(x, isFirst ? prevTerminator() : x);
+ NEXT.setRelease(x, isLast ? nextTerminator() : x);
}
}
}
@@ -531,7 +494,8 @@
// assert first.item == null;
for (Node<E> o = null, p = next, q;;) {
if (p.item != null || (q = p.next) == null) {
- if (o != null && p.prev != p && first.casNext(next, p)) {
+ if (o != null && p.prev != p &&
+ NEXT.compareAndSet(first, next, p)) {
skipDeletedPredecessors(p);
if (first.prev == null &&
(p.next == null || p.item != null) &&
@@ -541,8 +505,8 @@
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
- o.lazySetNext(o);
- o.lazySetPrev(prevTerminator());
+ NEXT.setRelease(o, o);
+ PREV.setRelease(o, prevTerminator());
}
}
return;
@@ -565,7 +529,8 @@
// assert last.item == null;
for (Node<E> o = null, p = prev, q;;) {
if (p.item != null || (q = p.prev) == null) {
- if (o != null && p.next != p && last.casPrev(prev, p)) {
+ if (o != null && p.next != p &&
+ PREV.compareAndSet(last, prev, p)) {
skipDeletedSuccessors(p);
if (last.next == null &&
(p.prev == null || p.item != null) &&
@@ -575,8 +540,8 @@
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
- o.lazySetPrev(o);
- o.lazySetNext(nextTerminator());
+ PREV.setRelease(o, o);
+ NEXT.setRelease(o, nextTerminator());
}
}
return;
@@ -607,7 +572,7 @@
(q = (p = q).prev) == null) {
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- if (casHead(h, p))
+ if (HEAD.compareAndSet(this, h, p))
return;
else
continue restartFromHead;
@@ -637,7 +602,7 @@
(q = (p = q).next) == null) {
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- if (casTail(t, p))
+ if (TAIL.compareAndSet(this, t, p))
return;
else
continue restartFromTail;
@@ -675,7 +640,7 @@
}
// found active CAS target
- if (prev == p || x.casPrev(prev, p))
+ if (prev == p || PREV.compareAndSet(x, prev, p))
return;
} while (x.item != null || x.next == null);
@@ -706,7 +671,7 @@
}
// found active CAS target
- if (next == p || x.casNext(next, p))
+ if (next == p || NEXT.compareAndSet(x, next, p))
return;
} while (x.item != null || x.prev == null);
@@ -719,8 +684,9 @@
*/
final Node<E> succ(Node<E> p) {
// TODO: should we skip deleted nodes here?
- Node<E> q = p.next;
- return (p == q) ? first() : q;
+ if (p == (p = p.next))
+ p = first();
+ return p;
}
/**
@@ -729,8 +695,9 @@
* stale pointer that is now off the list.
*/
final Node<E> pred(Node<E> p) {
- Node<E> q = p.prev;
- return (p == q) ? last() : q;
+ if (p == (p = p.prev))
+ p = last();
+ return p;
}
/**
@@ -751,7 +718,7 @@
else if (p == h
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- || casHead(h, p))
+ || HEAD.compareAndSet(this, h, p))
return p;
else
continue restartFromHead;
@@ -776,7 +743,7 @@
else if (p == t
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- || casTail(t, p))
+ || TAIL.compareAndSet(this, t, p))
return p;
else
continue restartFromTail;
@@ -802,7 +769,7 @@
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
- head = tail = new Node<E>(null);
+ head = tail = new Node<E>();
}
/**
@@ -818,12 +785,12 @@
// Copy c into a private chain of Nodes
Node<E> h = null, t = null;
for (E e : c) {
- Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ Node<E> newNode = newNode(Objects.requireNonNull(e));
if (h == null)
h = t = newNode;
else {
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
@@ -836,12 +803,12 @@
private void initHeadTail(Node<E> h, Node<E> t) {
if (h == t) {
if (h == null)
- h = t = new Node<E>(null);
+ h = t = new Node<E>();
else {
// Avoid edge case of a single Node with non-null item.
- Node<E> newNode = new Node<E>(null);
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ Node<E> newNode = new Node<E>();
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
@@ -900,21 +867,33 @@
}
public E peekFirst() {
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null)
- return item;
+ restart: for (;;) {
+ E item;
+ Node<E> first = first(), p = first;
+ while ((item = p.item) == null) {
+ if (p == (p = p.next)) continue restart;
+ if (p == null)
+ break;
+ }
+ // recheck for linearizability
+ if (first.prev != null) continue restart;
+ return item;
}
- return null;
}
public E peekLast() {
- for (Node<E> p = last(); p != null; p = pred(p)) {
- E item = p.item;
- if (item != null)
- return item;
+ restart: for (;;) {
+ E item;
+ Node<E> last = last(), p = last;
+ while ((item = p.item) == null) {
+ if (p == (p = p.prev)) continue restart;
+ if (p == null)
+ break;
+ }
+ // recheck for linearizability
+ if (last.next != null) continue restart;
+ return item;
}
- return null;
}
/**
@@ -932,25 +911,45 @@
}
public E pollFirst() {
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null && p.casItem(item, null)) {
- unlink(p);
- return item;
+ restart: for (;;) {
+ for (Node<E> first = first(), p = first;;) {
+ final E item;
+ if ((item = p.item) != null) {
+ // recheck for linearizability
+ if (first.prev != null) continue restart;
+ if (ITEM.compareAndSet(p, item, null)) {
+ unlink(p);
+ return item;
+ }
+ }
+ if (p == (p = p.next)) continue restart;
+ if (p == null) {
+ if (first.prev != null) continue restart;
+ return null;
+ }
}
}
- return null;
}
public E pollLast() {
- for (Node<E> p = last(); p != null; p = pred(p)) {
- E item = p.item;
- if (item != null && p.casItem(item, null)) {
- unlink(p);
- return item;
+ restart: for (;;) {
+ for (Node<E> last = last(), p = last;;) {
+ final E item;
+ if ((item = p.item) != null) {
+ // recheck for linearizability
+ if (last.next != null) continue restart;
+ if (ITEM.compareAndSet(p, item, null)) {
+ unlink(p);
+ return item;
+ }
+ }
+ if (p == (p = p.prev)) continue restart;
+ if (p == null) {
+ if (last.next != null) continue restart;
+ return null;
+ }
}
}
- return null;
}
/**
@@ -1030,8 +1029,10 @@
public boolean removeFirstOccurrence(Object o) {
Objects.requireNonNull(o);
for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null && o.equals(item) && p.casItem(item, null)) {
+ final E item;
+ if ((item = p.item) != null
+ && o.equals(item)
+ && ITEM.compareAndSet(p, item, null)) {
unlink(p);
return true;
}
@@ -1054,8 +1055,10 @@
public boolean removeLastOccurrence(Object o) {
Objects.requireNonNull(o);
for (Node<E> p = last(); p != null; p = pred(p)) {
- E item = p.item;
- if (item != null && o.equals(item) && p.casItem(item, null)) {
+ final E item;
+ if ((item = p.item) != null
+ && o.equals(item)
+ && ITEM.compareAndSet(p, item, null)) {
unlink(p);
return true;
}
@@ -1074,8 +1077,8 @@
public boolean contains(Object o) {
if (o != null) {
for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null && o.equals(item))
+ final E item;
+ if ((item = p.item) != null && o.equals(item))
return true;
}
}
@@ -1108,14 +1111,14 @@
* @return the number of elements in this deque
*/
public int size() {
- restartFromHead: for (;;) {
+ restart: for (;;) {
int count = 0;
for (Node<E> p = first(); p != null;) {
if (p.item != null)
if (++count == Integer.MAX_VALUE)
break; // @see Collection.size()
if (p == (p = p.next))
- continue restartFromHead;
+ continue restart;
}
return count;
}
@@ -1159,12 +1162,12 @@
// Copy c into a private chain of Nodes
Node<E> beginningOfTheEnd = null, last = null;
for (E e : c) {
- Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ Node<E> newNode = newNode(Objects.requireNonNull(e));
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
- last.lazySetNext(newNode);
- newNode.lazySetPrev(last);
+ NEXT.set(last, newNode);
+ PREV.set(newNode, last);
last = newNode;
}
}
@@ -1184,16 +1187,16 @@
continue restartFromTail;
else {
// p is last node
- beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
- if (p.casNext(null, beginningOfTheEnd)) {
+ PREV.set(beginningOfTheEnd, p); // CAS piggyback
+ if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this deque.
- if (!casTail(t, last)) {
+ if (!TAIL.weakCompareAndSet(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
- casTail(t, last);
+ TAIL.weakCompareAndSet(this, t, last);
}
return true;
}
@@ -1212,12 +1215,12 @@
public String toString() {
String[] a = null;
- restartFromHead: for (;;) {
+ restart: for (;;) {
int charLength = 0;
int size = 0;
for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
+ final E item;
+ if ((item = p.item) != null) {
if (a == null)
a = new String[4];
else if (size == a.length)
@@ -1227,7 +1230,7 @@
charLength += s.length();
}
if (p == (p = p.next))
- continue restartFromHead;
+ continue restart;
}
if (size == 0)
@@ -1239,11 +1242,11 @@
private Object[] toArrayInternal(Object[] a) {
Object[] x = a;
- restartFromHead: for (;;) {
+ restart: for (;;) {
int size = 0;
for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
+ final E item;
+ if ((item = p.item) != null) {
if (x == null)
x = new Object[4];
else if (size == x.length)
@@ -1251,7 +1254,7 @@
x[size++] = item;
}
if (p == (p = p.next))
- continue restartFromHead;
+ continue restart;
}
if (x == null)
return new Object[0];
@@ -1395,8 +1398,8 @@
nextItem = null;
break;
}
- E item = p.item;
- if (item != null) {
+ final E item;
+ if ((item = p.item) != null) {
nextNode = p;
nextItem = item;
break;
@@ -1426,90 +1429,75 @@
/** Forward iterator */
private class Itr extends AbstractItr {
+ Itr() {} // prevent access constructor creation
Node<E> startNode() { return first(); }
Node<E> nextNode(Node<E> p) { return succ(p); }
}
/** Descending iterator */
private class DescendingItr extends AbstractItr {
+ DescendingItr() {} // prevent access constructor creation
Node<E> startNode() { return last(); }
Node<E> nextNode(Node<E> p) { return pred(p); }
}
/** A customized variant of Spliterators.IteratorSpliterator */
- static final class CLDSpliterator<E> implements Spliterator<E> {
+ final class CLDSpliterator implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25; // max batch array size;
- final ConcurrentLinkedDeque<E> queue;
Node<E> current; // current node; null until initialized
int batch; // batch size for splits
boolean exhausted; // true when no more nodes
- CLDSpliterator(ConcurrentLinkedDeque<E> queue) {
- this.queue = queue;
- }
public Spliterator<E> trySplit() {
- Node<E> p;
- final ConcurrentLinkedDeque<E> q = this.queue;
- int b = batch;
- int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null)) {
- if (p.item == null && p == (p = p.next))
- current = p = q.first();
- if (p != null && p.next != null) {
- Object[] a = new Object[n];
- int i = 0;
- do {
- if ((a[i] = p.item) != null)
- ++i;
- if (p == (p = p.next))
- p = q.first();
- } while (p != null && i < n);
- if ((current = p) == null)
- exhausted = true;
- if (i > 0) {
- batch = i;
- return Spliterators.spliterator
- (a, 0, i, (Spliterator.ORDERED |
- Spliterator.NONNULL |
- Spliterator.CONCURRENT));
- }
+ Node<E> p, q;
+ if ((p = current()) == null || (q = p.next) == null)
+ return null;
+ int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+ Object[] a = null;
+ do {
+ final E e;
+ if ((e = p.item) != null) {
+ if (a == null)
+ a = new Object[n];
+ a[i++] = e;
}
- }
- return null;
+ if (p == (p = q))
+ p = first();
+ } while (p != null && (q = p.next) != null && i < n);
+ setCurrent(p);
+ return (i == 0) ? null :
+ Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
public void forEachRemaining(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
Node<E> p;
- if (action == null) throw new NullPointerException();
- final ConcurrentLinkedDeque<E> q = this.queue;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null)) {
+ if ((p = current()) != null) {
+ current = null;
exhausted = true;
do {
- E e = p.item;
- if (p == (p = p.next))
- p = q.first();
- if (e != null)
+ final E e;
+ if ((e = p.item) != null)
action.accept(e);
+ if (p == (p = p.next))
+ p = first();
} while (p != null);
}
}
public boolean tryAdvance(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
Node<E> p;
- if (action == null) throw new NullPointerException();
- final ConcurrentLinkedDeque<E> q = this.queue;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null)) {
+ if ((p = current()) != null) {
E e;
do {
e = p.item;
if (p == (p = p.next))
- p = q.first();
+ p = first();
} while (e == null && p != null);
- if ((current = p) == null)
- exhausted = true;
+ setCurrent(p);
if (e != null) {
action.accept(e);
return true;
@@ -1518,11 +1506,24 @@
return false;
}
+ private void setCurrent(Node<E> p) {
+ if ((current = p) == null)
+ exhausted = true;
+ }
+
+ private Node<E> current() {
+ Node<E> p;
+ if ((p = current) == null && !exhausted)
+ setCurrent(p = first());
+ return p;
+ }
+
public long estimateSize() { return Long.MAX_VALUE; }
public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
+ return (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT);
}
}
@@ -1543,7 +1544,7 @@
* @since 1.8
*/
public Spliterator<E> spliterator() {
- return new CLDSpliterator<E>(this);
+ return new CLDSpliterator();
}
/**
@@ -1562,8 +1563,8 @@
// Write out all elements in the proper order.
for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null)
+ final E item;
+ if ((item = p.item) != null)
s.writeObject(item);
}
@@ -1586,43 +1587,91 @@
Node<E> h = null, t = null;
for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
- Node<E> newNode = new Node<E>((E) item);
+ Node<E> newNode = newNode((E) item);
if (h == null)
h = t = newNode;
else {
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
initHeadTail(h, t);
}
- private boolean casHead(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> filter) {
+ Objects.requireNonNull(filter);
+ return bulkRemove(filter);
}
- private boolean casTail(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeAll(Collection<?> c) {
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> c.contains(e));
}
- // Unsafe mechanics
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean retainAll(Collection<?> c) {
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> !c.contains(e));
+ }
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
+ /** Implementation of bulk remove methods. */
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ boolean removed = false;
+ for (Node<E> p = first(), succ; p != null; p = succ) {
+ succ = succ(p);
+ final E item;
+ if ((item = p.item) != null
+ && filter.test(item)
+ && ITEM.compareAndSet(p, item, null)) {
+ unlink(p);
+ removed = true;
+ }
+ }
+ return removed;
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ E item;
+ for (Node<E> p = first(); p != null; p = succ(p))
+ if ((item = p.item) != null)
+ action.accept(item);
+ }
+
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
+ private static final VarHandle PREV;
+ private static final VarHandle NEXT;
+ private static final VarHandle ITEM;
static {
PREV_TERMINATOR = new Node<Object>();
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>();
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
try {
- HEAD = U.objectFieldOffset
- (ConcurrentLinkedDeque.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
+ Node.class);
+ TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
+ Node.class);
+ PREV = l.findVarHandle(Node.class, "prev", Node.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ ITEM = l.findVarHandle(Node.class, "item", Object.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index 7997c60..eac8ee7 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@@ -45,10 +47,7 @@
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
/**
* An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
@@ -82,12 +81,12 @@
* asynchronous nature of these queues, determining the current number
* of elements requires a traversal of the elements, and so may report
* inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
*
* <p>This class and its iterator implement all of the <em>optional</em>
* methods of the {@link Queue} and {@link Iterator} interfaces.
@@ -99,6 +98,10 @@
* actions subsequent to the access or removal of that element from
* the {@code ConcurrentLinkedQueue} in another thread.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.5
* @author Doug Lea
* @param <E> the type of elements held in this queue
@@ -110,7 +113,7 @@
/*
* This is a modification of the Michael & Scott algorithm,
* adapted for a garbage-collected environment, with support for
- * interior node deletion (to support remove(Object)). For
+ * interior node deletion (to support e.g. remove(Object)). For
* explanation, read the paper.
*
* Note that like most non-blocking algorithms in this package,
@@ -158,17 +161,17 @@
* it is possible for tail to lag behind head (why not)?
*
* CASing a Node's item reference to null atomically removes the
- * element from the queue. Iterators skip over Nodes with null
- * items. Prior implementations of this class had a race between
- * poll() and remove(Object) where the same element would appear
- * to be successfully removed by two concurrent operations. The
- * method remove(Object) also lazily unlinks deleted Nodes, but
- * this is merely an optimization.
+ * element from the queue, leaving a "dead" node that should later
+ * be unlinked (but unlinking is merely an optimization).
+ * Interior element removal methods (other than Iterator.remove())
+ * keep track of the predecessor node during traversal so that the
+ * node can be CAS-unlinked. Some traversal methods try to unlink
+ * any deleted nodes encountered during traversal. See comments
+ * in bulkRemove.
*
* When constructing a Node (before enqueuing it) we avoid paying
- * for a volatile write to item by using Unsafe.putObject instead
- * of a normal write. This allows the cost of enqueue to be
- * "one-and-a-half" CASes.
+ * for a volatile write to item. This allows the cost of enqueue
+ * to be "one-and-a-half" CASes.
*
* Both head and tail may or may not point to a Node with a
* non-null item. If the queue is empty, all items must of course
@@ -178,31 +181,33 @@
* optimization.
*/
- private static class Node<E> {
+ static final class Node<E> {
volatile E item;
volatile Node<E> next;
- }
- /**
- * Returns a new node holding item. Uses relaxed write because item
- * can only be seen after piggy-backing publication via casNext.
- */
- static <E> Node<E> newNode(E item) {
- Node<E> node = new Node<E>();
- U.putObject(node, ITEM, item);
- return node;
- }
+ /**
+ * Constructs a node holding item. Uses relaxed write because
+ * item can only be seen after piggy-backing publication via CAS.
+ */
+ Node(E item) {
+ ITEM.set(this, item);
+ }
- static <E> boolean casItem(Node<E> node, E cmp, E val) {
- return U.compareAndSwapObject(node, ITEM, cmp, val);
- }
+ /** Constructs a dead dummy node. */
+ Node() {}
- static <E> void lazySetNext(Node<E> node, Node<E> val) {
- U.putOrderedObject(node, NEXT, val);
- }
+ void appendRelaxed(Node<E> next) {
+ // assert next != null;
+ // assert this.next == null;
+ NEXT.set(this, next);
+ }
- static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(node, NEXT, cmp, val);
+ boolean casItem(E cmp, E val) {
+ // assert item == cmp || item == null;
+ // assert cmp != null;
+ // assert val == null;
+ return ITEM.compareAndSet(this, cmp, val);
+ }
}
/**
@@ -229,7 +234,7 @@
* - tail.item may or may not be null.
* - it is permitted for tail to lag behind head, that is, for tail
* to not be reachable from head!
- * - tail.next may or may not be self-pointing to tail.
+ * - tail.next may or may not be self-linked.
*/
private transient volatile Node<E> tail;
@@ -237,7 +242,7 @@
* Creates a {@code ConcurrentLinkedQueue} that is initially empty.
*/
public ConcurrentLinkedQueue() {
- head = tail = newNode(null);
+ head = tail = new Node<E>();
}
/**
@@ -252,16 +257,14 @@
public ConcurrentLinkedQueue(Collection<? extends E> c) {
Node<E> h = null, t = null;
for (E e : c) {
- Node<E> newNode = newNode(Objects.requireNonNull(e));
+ Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
if (h == null)
h = t = newNode;
- else {
- lazySetNext(t, newNode);
- t = newNode;
- }
+ else
+ t.appendRelaxed(t = newNode);
}
if (h == null)
- h = t = newNode(null);
+ h = t = new Node<E>();
head = h;
tail = t;
}
@@ -286,8 +289,8 @@
*/
final void updateHead(Node<E> h, Node<E> p) {
// assert h != null && p != null && (h == p || h.item == null);
- if (h != p && casHead(h, p))
- lazySetNext(h, h);
+ if (h != p && HEAD.compareAndSet(this, h, p))
+ NEXT.setRelease(h, h);
}
/**
@@ -296,8 +299,49 @@
* stale pointer that is now off the list.
*/
final Node<E> succ(Node<E> p) {
- Node<E> next = p.next;
- return (p == next) ? head : next;
+ if (p == (p = p.next))
+ p = head;
+ return p;
+ }
+
+ /**
+ * Tries to CAS pred.next (or head, if pred is null) from c to p.
+ * Caller must ensure that we're not unlinking the trailing node.
+ */
+ private boolean tryCasSuccessor(Node<E> pred, Node<E> c, Node<E> p) {
+ // assert p != null;
+ // assert c.item == null;
+ // assert c != p;
+ if (pred != null)
+ return NEXT.compareAndSet(pred, c, p);
+ if (HEAD.compareAndSet(this, c, p)) {
+ NEXT.setRelease(c, c);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Collapse dead nodes between pred and q.
+ * @param pred the last known live node, or null if none
+ * @param c the first dead node
+ * @param p the last dead node
+ * @param q p.next: the next live node, or null if at end
+ * @return either old pred or p if pred dead or CAS failed
+ */
+ private Node<E> skipDeadNodes(Node<E> pred, Node<E> c, Node<E> p, Node<E> q) {
+ // assert pred != c;
+ // assert p != q;
+ // assert c.item == null;
+ // assert p.item == null;
+ if (q == null) {
+ // Never unlink trailing node.
+ if (c == p) return pred;
+ q = p;
+ }
+ return (tryCasSuccessor(pred, c, q)
+ && (pred == null || ITEM.get(pred) != null))
+ ? pred : p;
}
/**
@@ -308,18 +352,18 @@
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
- final Node<E> newNode = newNode(Objects.requireNonNull(e));
+ final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
// p is last node
- if (casNext(p, null, newNode)) {
+ if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
- if (p != t) // hop two nodes at a time
- casTail(t, newNode); // Failure is OK.
+ if (p != t) // hop two nodes at a time; failure is OK
+ TAIL.weakCompareAndSet(this, t, newNode);
return true;
}
// Lost CAS race to another thread; re-read next
@@ -337,12 +381,10 @@
}
public E poll() {
- restartFromHead:
- for (;;) {
- for (Node<E> h = head, p = h, q;;) {
- E item = p.item;
-
- if (item != null && casItem(p, item, null)) {
+ restartFromHead: for (;;) {
+ for (Node<E> h = head, p = h, q;; p = q) {
+ final E item;
+ if ((item = p.item) != null && p.casItem(item, null)) {
// Successful CAS is the linearization point
// for item to be removed from this queue.
if (p != h) // hop two nodes at a time
@@ -355,25 +397,21 @@
}
else if (p == q)
continue restartFromHead;
- else
- p = q;
}
}
}
public E peek() {
- restartFromHead:
- for (;;) {
- for (Node<E> h = head, p = h, q;;) {
- E item = p.item;
- if (item != null || (q = p.next) == null) {
+ restartFromHead: for (;;) {
+ for (Node<E> h = head, p = h, q;; p = q) {
+ final E item;
+ if ((item = p.item) != null
+ || (q = p.next) == null) {
updateHead(h, p);
return item;
}
else if (p == q)
continue restartFromHead;
- else
- p = q;
}
}
}
@@ -387,9 +425,8 @@
* of losing a race to a concurrent poll().
*/
Node<E> first() {
- restartFromHead:
- for (;;) {
- for (Node<E> h = head, p = h, q;;) {
+ restartFromHead: for (;;) {
+ for (Node<E> h = head, p = h, q;; p = q) {
boolean hasItem = (p.item != null);
if (hasItem || (q = p.next) == null) {
updateHead(h, p);
@@ -397,8 +434,6 @@
}
else if (p == q)
continue restartFromHead;
- else
- p = q;
}
}
}
@@ -451,14 +486,25 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- if (o != null) {
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null && o.equals(item))
- return true;
+ if (o == null) return false;
+ restartFromHead: for (;;) {
+ for (Node<E> p = head, pred = null; p != null; ) {
+ Node<E> q = p.next;
+ final E item;
+ if ((item = p.item) != null) {
+ if (o.equals(item))
+ return true;
+ pred = p; p = q; continue;
+ }
+ for (Node<E> c = p;; q = p.next) {
+ if (q == null || q.item != null) {
+ pred = skipDeadNodes(pred, c, p, q); p = q; break;
+ }
+ if (p == (p = q)) continue restartFromHead;
+ }
}
+ return false;
}
- return false;
}
/**
@@ -473,27 +519,27 @@
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
- if (o != null) {
- Node<E> next, pred = null;
- for (Node<E> p = first(); p != null; pred = p, p = next) {
- boolean removed = false;
- E item = p.item;
- if (item != null) {
- if (!o.equals(item)) {
- next = succ(p);
- continue;
+ if (o == null) return false;
+ restartFromHead: for (;;) {
+ for (Node<E> p = head, pred = null; p != null; ) {
+ Node<E> q = p.next;
+ final E item;
+ if ((item = p.item) != null) {
+ if (o.equals(item) && p.casItem(item, null)) {
+ skipDeadNodes(pred, p, p, q);
+ return true;
}
- removed = casItem(p, item, null);
+ pred = p; p = q; continue;
}
-
- next = succ(p);
- if (pred != null && next != null) // unlink
- casNext(pred, p, next);
- if (removed)
- return true;
+ for (Node<E> c = p;; q = p.next) {
+ if (q == null || q.item != null) {
+ pred = skipDeadNodes(pred, c, p, q); p = q; break;
+ }
+ if (p == (p = q)) continue restartFromHead;
+ }
}
+ return false;
}
- return false;
}
/**
@@ -516,13 +562,11 @@
// Copy c into a private chain of Nodes
Node<E> beginningOfTheEnd = null, last = null;
for (E e : c) {
- Node<E> newNode = newNode(Objects.requireNonNull(e));
+ Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
- else {
- lazySetNext(last, newNode);
- last = newNode;
- }
+ else
+ last.appendRelaxed(last = newNode);
}
if (beginningOfTheEnd == null)
return false;
@@ -532,15 +576,15 @@
Node<E> q = p.next;
if (q == null) {
// p is last node
- if (casNext(p, null, beginningOfTheEnd)) {
+ if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this queue.
- if (!casTail(t, last)) {
+ if (!TAIL.weakCompareAndSet(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
- casTail(t, last);
+ TAIL.weakCompareAndSet(this, t, last);
}
return true;
}
@@ -564,8 +608,8 @@
int charLength = 0;
int size = 0;
for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
+ final E item;
+ if ((item = p.item) != null) {
if (a == null)
a = new String[4];
else if (size == a.length)
@@ -590,8 +634,8 @@
restartFromHead: for (;;) {
int size = 0;
for (Node<E> p = first(); p != null;) {
- E item = p.item;
- if (item != null) {
+ final E item;
+ if ((item = p.item) != null) {
if (x == null)
x = new Object[4];
else if (size == x.length)
@@ -668,7 +712,7 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- if (a == null) throw new NullPointerException();
+ Objects.requireNonNull(a);
return (T[]) toArrayInternal(a);
}
@@ -708,7 +752,7 @@
restartFromHead: for (;;) {
Node<E> h, p, q;
for (p = h = head;; p = q) {
- E item;
+ final E item;
if ((item = p.item) != null) {
nextNode = p;
nextItem = item;
@@ -744,10 +788,12 @@
}
// unlink deleted nodes
if ((q = succ(p)) != null)
- casNext(pred, p, q);
+ NEXT.compareAndSet(pred, p, q);
}
}
+ // Default implementation of forEachRemaining is "good enough".
+
public void remove() {
Node<E> l = lastRet;
if (l == null) throw new IllegalStateException();
@@ -773,8 +819,8 @@
// Write out all elements in the proper order.
for (Node<E> p = first(); p != null; p = succ(p)) {
- Object item = p.item;
- if (item != null)
+ final E item;
+ if ((item = p.item) != null)
s.writeObject(item);
}
@@ -797,91 +843,69 @@
Node<E> h = null, t = null;
for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
- Node<E> newNode = newNode((E) item);
+ Node<E> newNode = new Node<E>((E) item);
if (h == null)
h = t = newNode;
- else {
- lazySetNext(t, newNode);
- t = newNode;
- }
+ else
+ t.appendRelaxed(t = newNode);
}
if (h == null)
- h = t = newNode(null);
+ h = t = new Node<E>();
head = h;
tail = t;
}
/** A customized variant of Spliterators.IteratorSpliterator */
- static final class CLQSpliterator<E> implements Spliterator<E> {
+ final class CLQSpliterator implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25; // max batch array size;
- final ConcurrentLinkedQueue<E> queue;
Node<E> current; // current node; null until initialized
int batch; // batch size for splits
boolean exhausted; // true when no more nodes
- CLQSpliterator(ConcurrentLinkedQueue<E> queue) {
- this.queue = queue;
- }
public Spliterator<E> trySplit() {
- Node<E> p;
- final ConcurrentLinkedQueue<E> q = this.queue;
- int b = batch;
- int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null) &&
- p.next != null) {
- Object[] a = new Object[n];
- int i = 0;
- do {
- if ((a[i] = p.item) != null)
- ++i;
- if (p == (p = p.next))
- p = q.first();
- } while (p != null && i < n);
- if ((current = p) == null)
- exhausted = true;
- if (i > 0) {
- batch = i;
- return Spliterators.spliterator
- (a, 0, i, (Spliterator.ORDERED |
- Spliterator.NONNULL |
- Spliterator.CONCURRENT));
+ Node<E> p, q;
+ if ((p = current()) == null || (q = p.next) == null)
+ return null;
+ int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+ Object[] a = null;
+ do {
+ final E e;
+ if ((e = p.item) != null) {
+ if (a == null)
+ a = new Object[n];
+ a[i++] = e;
}
- }
- return null;
+ if (p == (p = q))
+ p = first();
+ } while (p != null && (q = p.next) != null && i < n);
+ setCurrent(p);
+ return (i == 0) ? null :
+ Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
public void forEachRemaining(Consumer<? super E> action) {
- Node<E> p;
- if (action == null) throw new NullPointerException();
- final ConcurrentLinkedQueue<E> q = this.queue;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null)) {
+ Objects.requireNonNull(action);
+ final Node<E> p;
+ if ((p = current()) != null) {
+ current = null;
exhausted = true;
- do {
- E e = p.item;
- if (p == (p = p.next))
- p = q.first();
- if (e != null)
- action.accept(e);
- } while (p != null);
+ forEachFrom(action, p);
}
}
public boolean tryAdvance(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
Node<E> p;
- if (action == null) throw new NullPointerException();
- final ConcurrentLinkedQueue<E> q = this.queue;
- if (!exhausted &&
- ((p = current) != null || (p = q.first()) != null)) {
+ if ((p = current()) != null) {
E e;
do {
e = p.item;
if (p == (p = p.next))
- p = q.first();
+ p = first();
} while (e == null && p != null);
- if ((current = p) == null)
- exhausted = true;
+ setCurrent(p);
if (e != null) {
action.accept(e);
return true;
@@ -890,11 +914,24 @@
return false;
}
+ private void setCurrent(Node<E> p) {
+ if ((current = p) == null)
+ exhausted = true;
+ }
+
+ private Node<E> current() {
+ Node<E> p;
+ if ((p = current) == null && !exhausted)
+ setCurrent(p = first());
+ return p;
+ }
+
public long estimateSize() { return Long.MAX_VALUE; }
public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
+ return (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT);
}
}
@@ -916,36 +953,123 @@
*/
@Override
public Spliterator<E> spliterator() {
- return new CLQSpliterator<E>(this);
+ return new CLQSpliterator();
}
- private boolean casTail(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> filter) {
+ Objects.requireNonNull(filter);
+ return bulkRemove(filter);
}
- private boolean casHead(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeAll(Collection<?> c) {
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> c.contains(e));
}
- // Unsafe mechanics
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean retainAll(Collection<?> c) {
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> !c.contains(e));
+ }
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
- private static final long ITEM;
- private static final long NEXT;
+ public void clear() {
+ bulkRemove(e -> true);
+ }
+
+ /**
+ * Tolerate this many consecutive dead nodes before CAS-collapsing.
+ * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
+ */
+ private static final int MAX_HOPS = 8;
+
+ /** Implementation of bulk remove methods. */
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ boolean removed = false;
+ restartFromHead: for (;;) {
+ int hops = MAX_HOPS;
+ // c will be CASed to collapse intervening dead nodes between
+ // pred (or head if null) and p.
+ for (Node<E> p = head, c = p, pred = null, q; p != null; p = q) {
+ q = p.next;
+ final E item; boolean pAlive;
+ if (pAlive = ((item = p.item) != null)) {
+ if (filter.test(item)) {
+ if (p.casItem(item, null))
+ removed = true;
+ pAlive = false;
+ }
+ }
+ if (pAlive || q == null || --hops == 0) {
+ // p might already be self-linked here, but if so:
+ // - CASing head will surely fail
+ // - CASing pred's next will be useless but harmless.
+ if ((c != p && !tryCasSuccessor(pred, c, c = p))
+ || pAlive) {
+ // if CAS failed or alive, abandon old pred
+ hops = MAX_HOPS;
+ pred = p;
+ c = q;
+ }
+ } else if (p == q)
+ continue restartFromHead;
+ }
+ return removed;
+ }
+ }
+
+ /**
+ * Runs action on each element found during a traversal starting at p.
+ * If p is null, the action is not run.
+ */
+ void forEachFrom(Consumer<? super E> action, Node<E> p) {
+ for (Node<E> pred = null; p != null; ) {
+ Node<E> q = p.next;
+ final E item;
+ if ((item = p.item) != null) {
+ action.accept(item);
+ pred = p; p = q; continue;
+ }
+ for (Node<E> c = p;; q = p.next) {
+ if (q == null || q.item != null) {
+ pred = skipDeadNodes(pred, c, p, q); p = q; break;
+ }
+ if (p == (p = q)) { pred = null; p = head; break; }
+ }
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ forEachFrom(action, head);
+ }
+
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
+ static final VarHandle ITEM;
+ static final VarHandle NEXT;
static {
try {
- HEAD = U.objectFieldOffset
- (ConcurrentLinkedQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
- ITEM = U.objectFieldOffset
- (Node.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
+ Node.class);
+ TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
+ Node.class);
+ ITEM = l.findVarHandle(Node.class, "item", Object.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
index 69dae6f..2037e31 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentMap.java
@@ -41,14 +41,8 @@
import java.util.function.BiFunction;
import java.util.function.Function;
-// BEGIN android-note
-// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
/**
- * A {@link java.util.Map} providing thread safety and atomicity
- * guarantees.
+ * A {@link Map} providing thread safety and atomicity guarantees.
*
* <p>To maintain the specified guarantees, default implementations of
* methods including {@link #putIfAbsent} inherited from {@link Map}
@@ -65,6 +59,10 @@
* actions subsequent to the access or removal of that object from
* the {@code ConcurrentMap} in another thread.
*
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.5
* @author Doug Lea
* @param <K> the type of keys maintained by this map
@@ -182,10 +180,10 @@
* is not supported by this map
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key or value is null,
* and this map does not permit null keys or values
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object key, Object value);
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
index 94a90cd..1666c8b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
@@ -38,14 +38,14 @@
import java.util.NavigableMap;
import java.util.NavigableSet;
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
/**
* A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
* and recursively so for its navigable sub-maps.
*
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @author Doug Lea
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
index 583244b..db14d4b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
@@ -46,7 +48,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -57,10 +58,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.concurrent.atomic.LongAdder;
/**
* A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -89,12 +87,7 @@
* associated map using {@code put}, {@code putIfAbsent}, or
* {@code replace}, depending on exactly which effect you need.)
*
- * <p>Beware that, unlike in most collections, the {@code size}
- * method is <em>not</em> a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current number
- * of elements requires a traversal of the elements, and so may report
- * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code putAll}, {@code equals},
+ * <p>Beware that bulk operations {@code putAll}, {@code equals},
* {@code toArray}, {@code containsValue}, and {@code clear} are
* <em>not</em> guaranteed to be performed atomically. For example, an
* iterator operating concurrently with a {@code putAll} operation
@@ -107,6 +100,10 @@
* null return values cannot be reliably distinguished from the absence of
* elements.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @author Doug Lea
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
@@ -157,42 +154,35 @@
* be slow and space-intensive using AtomicMarkedReference), nodes
* use direct CAS'able next pointers. On deletion, instead of
* marking a pointer, they splice in another node that can be
- * thought of as standing for a marked pointer (indicating this by
- * using otherwise impossible field values). Using plain nodes
- * acts roughly like "boxed" implementations of marked pointers,
- * but uses new nodes only when nodes are deleted, not for every
- * link. This requires less space and supports faster
- * traversal. Even if marked references were better supported by
- * JVMs, traversal using this technique might still be faster
- * because any search need only read ahead one more node than
- * otherwise required (to check for trailing marker) rather than
- * unmasking mark bits or whatever on each read.
+ * thought of as standing for a marked pointer (see method
+ * unlinkNode). Using plain nodes acts roughly like "boxed"
+ * implementations of marked pointers, but uses new nodes only
+ * when nodes are deleted, not for every link. This requires less
+ * space and supports faster traversal. Even if marked references
+ * were better supported by JVMs, traversal using this technique
+ * might still be faster because any search need only read ahead
+ * one more node than otherwise required (to check for trailing
+ * marker) rather than unmasking mark bits or whatever on each
+ * read.
*
* This approach maintains the essential property needed in the HM
* algorithm of changing the next-pointer of a deleted node so
* that any other CAS of it will fail, but implements the idea by
- * changing the pointer to point to a different node, not by
- * marking it. While it would be possible to further squeeze
- * space by defining marker nodes not to have key/value fields, it
- * isn't worth the extra type-testing overhead. The deletion
- * markers are rarely encountered during traversal and are
- * normally quickly garbage collected. (Note that this technique
- * would not work well in systems without garbage collection.)
+ * changing the pointer to point to a different node (with
+ * otherwise illegal null fields), not by marking it. While it
+ * would be possible to further squeeze space by defining marker
+ * nodes not to have key/value fields, it isn't worth the extra
+ * type-testing overhead. The deletion markers are rarely
+ * encountered during traversal, are easily detected via null
+ * checks that are needed anyway, and are normally quickly garbage
+ * collected. (Note that this technique would not work well in
+ * systems without garbage collection.)
*
* In addition to using deletion markers, the lists also use
* nullness of value fields to indicate deletion, in a style
* similar to typical lazy-deletion schemes. If a node's value is
* null, then it is considered logically deleted and ignored even
- * though it is still reachable. This maintains proper control of
- * concurrent replace vs delete operations -- an attempted replace
- * must fail if a delete beat it by nulling field, and a delete
- * must return the last non-null value held in the field. (Note:
- * Null, rather than some special marker, is used for value fields
- * here because it just so happens to mesh with the Map API
- * requirement that method get returns null if there is no
- * mapping, which allows nodes to remain concurrently readable
- * even when deleted. Using any other marker value here would be
- * messy at best.)
+ * though it is still reachable.
*
* Here's the sequence of events for a deletion of node n with
* predecessor b and successor f, initially:
@@ -202,9 +192,8 @@
* +------+ +------+ +------+
*
* 1. CAS n's value field from non-null to null.
- * From this point on, no public operations encountering
- * the node consider this mapping to exist. However, other
- * ongoing insertions and deletions might still modify
+ * Traversals encountering a node with null value ignore it.
+ * However, ongoing insertions and deletions might still modify
* n's next pointer.
*
* 2. CAS n's next pointer to point to a new marker node.
@@ -227,12 +216,7 @@
* thread noticed during a traversal a node with null value and
* helped out by marking and/or unlinking. This helping-out
* ensures that no thread can become stuck waiting for progress of
- * the deleting thread. The use of marker nodes slightly
- * complicates helping-out code because traversals must track
- * consistent reads of up to four nodes (b, n, marker, f), not
- * just (b, n, f), although the next field of a marker is
- * immutable, and once a next field is CAS'ed to point to a
- * marker, it never again changes, so this requires less care.
+ * the deleting thread.
*
* Skip lists add indexing to this scheme, so that the base-level
* traversals start close to the locations being found, inserted
@@ -242,113 +226,101 @@
* b) that are not (structurally) deleted, otherwise retrying
* after processing the deletion.
*
- * Index levels are maintained as lists with volatile next fields,
- * using CAS to link and unlink. Races are allowed in index-list
- * operations that can (rarely) fail to link in a new index node
- * or delete one. (We can't do this of course for data nodes.)
- * However, even when this happens, the index lists remain sorted,
- * so correctly serve as indices. This can impact performance,
- * but since skip lists are probabilistic anyway, the net result
- * is that under contention, the effective "p" value may be lower
- * than its nominal value. And race windows are kept small enough
- * that in practice these failures are rare, even under a lot of
- * contention.
+ * Index levels are maintained using CAS to link and unlink
+ * successors ("right" fields). Races are allowed in index-list
+ * operations that can (rarely) fail to link in a new index node.
+ * (We can't do this of course for data nodes.) However, even
+ * when this happens, the index lists correctly guide search.
+ * This can impact performance, but since skip lists are
+ * probabilistic anyway, the net result is that under contention,
+ * the effective "p" value may be lower than its nominal value.
*
- * The fact that retries (for both base and index lists) are
- * relatively cheap due to indexing allows some minor
- * simplifications of retry logic. Traversal restarts are
- * performed after most "helping-out" CASes. This isn't always
- * strictly necessary, but the implicit backoffs tend to help
- * reduce other downstream failed CAS's enough to outweigh restart
- * cost. This worsens the worst case, but seems to improve even
- * highly contended cases.
- *
- * Unlike most skip-list implementations, index insertion and
- * deletion here require a separate traversal pass occurring after
- * the base-level action, to add or remove index nodes. This adds
- * to single-threaded overhead, but improves contended
- * multithreaded performance by narrowing interference windows,
- * and allows deletion to ensure that all index nodes will be made
- * unreachable upon return from a public remove operation, thus
- * avoiding unwanted garbage retention. This is more important
- * here than in some other data structures because we cannot null
- * out node fields referencing user keys since they might still be
- * read by other ongoing traversals.
+ * Index insertion and deletion sometimes require a separate
+ * traversal pass occurring after the base-level action, to add or
+ * remove index nodes. This adds to single-threaded overhead, but
+ * improves contended multithreaded performance by narrowing
+ * interference windows, and allows deletion to ensure that all
+ * index nodes will be made unreachable upon return from a public
+ * remove operation, thus avoiding unwanted garbage retention.
*
* Indexing uses skip list parameters that maintain good search
* performance while using sparser-than-usual indices: The
- * hardwired parameters k=1, p=0.5 (see method doPut) mean
- * that about one-quarter of the nodes have indices. Of those that
- * do, half have one level, a quarter have two, and so on (see
- * Pugh's Skip List Cookbook, sec 3.4). The expected total space
- * requirement for a map is slightly less than for the current
- * implementation of java.util.TreeMap.
+ * hardwired parameters k=1, p=0.5 (see method doPut) mean that
+ * about one-quarter of the nodes have indices. Of those that do,
+ * half have one level, a quarter have two, and so on (see Pugh's
+ * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
+ * (appropriate for up to 2^63 elements). The expected total
+ * space requirement for a map is slightly less than for the
+ * current implementation of java.util.TreeMap.
*
* Changing the level of the index (i.e, the height of the
- * tree-like structure) also uses CAS. The head index has initial
- * level/height of one. Creation of an index with height greater
- * than the current level adds a level to the head index by
- * CAS'ing on a new top-most head. To maintain good performance
- * after a lot of removals, deletion methods heuristically try to
- * reduce the height if the topmost levels appear to be empty.
- * This may encounter races in which it possible (but rare) to
- * reduce and "lose" a level just as it is about to contain an
- * index (that will then never be encountered). This does no
- * structural harm, and in practice appears to be a better option
- * than allowing unrestrained growth of levels.
+ * tree-like structure) also uses CAS. Creation of an index with
+ * height greater than the current level adds a level to the head
+ * index by CAS'ing on a new top-most head. To maintain good
+ * performance after a lot of removals, deletion methods
+ * heuristically try to reduce the height if the topmost levels
+ * appear to be empty. This may encounter races in which it is
+ * possible (but rare) to reduce and "lose" a level just as it is
+ * about to contain an index (that will then never be
+ * encountered). This does no structural harm, and in practice
+ * appears to be a better option than allowing unrestrained growth
+ * of levels.
*
- * The code for all this is more verbose than you'd like. Most
- * operations entail locating an element (or position to insert an
- * element). The code to do this can't be nicely factored out
- * because subsequent uses require a snapshot of predecessor
- * and/or successor and/or value fields which can't be returned
- * all at once, at least not without creating yet another object
- * to hold them -- creating such little objects is an especially
- * bad idea for basic internal search operations because it adds
- * to GC overhead. (This is one of the few times I've wished Java
- * had macros.) Instead, some traversal code is interleaved within
- * insertion and removal operations. The control logic to handle
- * all the retry conditions is sometimes twisty. Most search is
- * broken into 2 parts. findPredecessor() searches index nodes
- * only, returning a base-level predecessor of the key. findNode()
- * finishes out the base-level search. Even with this factoring,
- * there is a fair amount of near-duplication of code to handle
- * variants.
+ * This class provides concurrent-reader-style memory consistency,
+ * ensuring that read-only methods report status and/or values no
+ * staler than those holding at method entry. This is done by
+ * performing all publication and structural updates using
+ * (volatile) CAS, placing an acquireFence in a few access
+ * methods, and ensuring that linked objects are transitively
+ * acquired via dependent reads (normally once) unless performing
+ * a volatile-mode CAS operation (that also acts as an acquire and
+ * release). This form of fence-hoisting is similar to RCU and
+ * related techniques (see McKenney's online book
+ * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
+ * It minimizes overhead that may otherwise occur when using so
+ * many volatile-mode reads. Using explicit acquireFences is
+ * logistically easier than targeting particular fields to be read
+ * in acquire mode: fences are just hoisted up as far as possible,
+ * to the entry points or loop headers of a few methods. A
+ * potential disadvantage is that these few remaining fences are
+ * not easily optimized away by compilers under exclusively
+ * single-thread use. It requires some care to avoid volatile
+ * mode reads of other fields. (Note that the memory semantics of
+ * a reference dependently read in plain mode exactly once are
+ * equivalent to those for atomic opaque mode.) Iterators and
+ * other traversals encounter each node and value exactly once.
+ * Other operations locate an element (or position to insert an
+ * element) via a sequence of dereferences. This search is broken
+ * into two parts. Method findPredecessor (and its specialized
+ * embeddings) searches index nodes only, returning a base-level
+ * predecessor of the key. Callers carry out the base-level
+ * search, restarting if encountering a marker preventing link
+ * modification. In some cases, it is possible to encounter a
+ * node multiple times while descending levels. For mutative
+ * operations, the reported value is validated using CAS (else
+ * retrying), preserving linearizability with respect to each
+ * other. Others may return any (non-null) value holding in the
+ * course of the method call. (Search-based methods also include
+ * some useless-looking explicit null checks designed to allow
+ * more fields to be nulled out upon removal, to reduce floating
+ * garbage, but which is not currently done, pending discovery of
+ * a way to do this with less impact on other operations.)
*
* To produce random values without interference across threads,
* we use within-JDK thread local random support (via the
* "secondary seed", to avoid interference with user-level
* ThreadLocalRandom.)
*
- * A previous version of this class wrapped non-comparable keys
- * with their comparators to emulate Comparables when using
- * comparators vs Comparables. However, JVMs now appear to better
- * handle infusing comparator-vs-comparable choice into search
- * loops. Static method cpr(comparator, x, y) is used for all
- * comparisons, which works well as long as the comparator
- * argument is set up outside of loops (thus sometimes passed as
- * an argument to internal methods) to avoid field re-reads.
- *
* For explanation of algorithms sharing at least a couple of
* features with this one, see Mikhail Fomitchev's thesis
* (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
* (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
* thesis (http://www.cs.chalmers.se/~phs/).
*
- * Given the use of tree-like index nodes, you might wonder why
- * this doesn't use some kind of search tree instead, which would
- * support somewhat faster search operations. The reason is that
- * there are no known efficient lock-free insertion and deletion
- * algorithms for search trees. The immutability of the "down"
- * links of index nodes (as opposed to mutable "left" fields in
- * true trees) makes this tractable using only CAS operations.
- *
* Notation guide for local variables
- * Node: b, n, f for predecessor, node, successor
+ * Node: b, n, f, p for predecessor, node, successor, aux
* Index: q, r, d for index node, right, down.
- * t for another index node
* Head: h
- * Levels: j
* Keys: k, key
* Values: v, value
* Comparisons: c
@@ -357,16 +329,6 @@
private static final long serialVersionUID = -8627078645895051609L;
/**
- * Special value used to identify base-level header.
- */
- static final Object BASE_HEADER = new Object();
-
- /**
- * The topmost head index of the skiplist.
- */
- private transient volatile HeadIndex<K,V> head;
-
- /**
* The comparator used to maintain order in this map, or null if
* using natural ordering. (Non-private to simplify access in
* nested classes.)
@@ -374,316 +336,152 @@
*/
final Comparator<? super K> comparator;
+ /** Lazily initialized topmost index of the skiplist. */
+ private transient Index<K,V> head;
+ /** Lazily initialized element count */
+ private transient LongAdder adder;
/** Lazily initialized key set */
private transient KeySet<K,V> keySet;
- /** Lazily initialized entry set */
- private transient EntrySet<K,V> entrySet;
/** Lazily initialized values collection */
private transient Values<K,V> values;
- /** Lazily initialized descending key set */
- private transient ConcurrentNavigableMap<K,V> descendingMap;
-
- /**
- * Initializes or resets state. Needed by constructors, clone,
- * clear, readObject. and ConcurrentSkipListSet.clone.
- * (Note that comparator must be separately initialized.)
- */
- private void initialize() {
- keySet = null;
- entrySet = null;
- values = null;
- descendingMap = null;
- head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
- null, null, 1);
- }
-
- /**
- * compareAndSet head node.
- */
- private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
- }
-
- /* ---------------- Nodes -------------- */
+ /** Lazily initialized entry set */
+ private transient EntrySet<K,V> entrySet;
+ /** Lazily initialized descending map */
+ private transient SubMap<K,V> descendingMap;
/**
* Nodes hold keys and values, and are singly linked in sorted
* order, possibly with some intervening marker nodes. The list is
- * headed by a dummy node accessible as head.node. The value field
- * is declared only as Object because it takes special non-V
- * values for marker and header nodes.
+ * headed by a header node accessible as head.node. Headers and
+ * marker nodes have null keys. The val field (but currently not
+ * the key field) is nulled out upon deletion.
*/
static final class Node<K,V> {
- final K key;
- volatile Object value;
- volatile Node<K,V> next;
-
- /**
- * Creates a new regular node.
- */
- Node(K key, Object value, Node<K,V> next) {
+ final K key; // currently, never detached
+ V val;
+ Node<K,V> next;
+ Node(K key, V value, Node<K,V> next) {
this.key = key;
- this.value = value;
+ this.val = value;
this.next = next;
}
-
- /**
- * Creates a new marker node. A marker is distinguished by
- * having its value field point to itself. Marker nodes also
- * have null keys, a fact that is exploited in a few places,
- * but this doesn't distinguish markers from the base-level
- * header node (head.node), which also has a null key.
- */
- Node(Node<K,V> next) {
- this.key = null;
- this.value = this;
- this.next = next;
- }
-
- /**
- * compareAndSet value field.
- */
- boolean casValue(Object cmp, Object val) {
- return U.compareAndSwapObject(this, VALUE, cmp, val);
- }
-
- /**
- * compareAndSet next field.
- */
- boolean casNext(Node<K,V> cmp, Node<K,V> val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
- }
-
- /**
- * Returns true if this node is a marker. This method isn't
- * actually called in any current code checking for markers
- * because callers will have already read value field and need
- * to use that read (not another done here) and so directly
- * test if value points to node.
- *
- * @return true if this node is a marker node
- */
- boolean isMarker() {
- return value == this;
- }
-
- /**
- * Returns true if this node is the header of base-level list.
- * @return true if this node is header node
- */
- boolean isBaseHeader() {
- return value == BASE_HEADER;
- }
-
- /**
- * Tries to append a deletion marker to this node.
- * @param f the assumed current successor of this node
- * @return true if successful
- */
- boolean appendMarker(Node<K,V> f) {
- return casNext(f, new Node<K,V>(f));
- }
-
- /**
- * Helps out a deletion by appending marker or unlinking from
- * predecessor. This is called during traversals when value
- * field seen to be null.
- * @param b predecessor
- * @param f successor
- */
- void helpDelete(Node<K,V> b, Node<K,V> f) {
- /*
- * Rechecking links and then doing only one of the
- * help-out stages per call tends to minimize CAS
- * interference among helping threads.
- */
- if (f == next && this == b.next) {
- if (f == null || f.value != f) // not already marked
- casNext(f, new Node<K,V>(f));
- else
- b.casNext(this, f.next);
- }
- }
-
- /**
- * Returns value if this node contains a valid key-value pair,
- * else null.
- * @return this node's value if it isn't a marker or header or
- * is deleted, else null
- */
- V getValidValue() {
- Object v = value;
- if (v == this || v == BASE_HEADER)
- return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
-
- /**
- * Creates and returns a new SimpleImmutableEntry holding current
- * mapping if this node holds a valid value, else null.
- * @return new entry or null
- */
- AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
- Object v = value;
- if (v == null || v == this || v == BASE_HEADER)
- return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
- }
-
- // Unsafe mechanics
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
- private static final long NEXT;
-
- static {
- try {
- VALUE = U.objectFieldOffset
- (Node.class.getDeclaredField("value"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
}
- /* ---------------- Indexing -------------- */
-
/**
- * Index nodes represent the levels of the skip list. Note that
- * even though both Nodes and Indexes have forward-pointing
- * fields, they have different types and are handled in different
- * ways, that can't nicely be captured by placing field in a
- * shared abstract class.
+ * Index nodes represent the levels of the skip list.
*/
- static class Index<K,V> {
- final Node<K,V> node;
+ static final class Index<K,V> {
+ final Node<K,V> node; // currently, never detached
final Index<K,V> down;
- volatile Index<K,V> right;
-
- /**
- * Creates index node with given values.
- */
+ Index<K,V> right;
Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
this.node = node;
this.down = down;
this.right = right;
}
-
- /**
- * compareAndSet right field.
- */
- final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
- return U.compareAndSwapObject(this, RIGHT, cmp, val);
- }
-
- /**
- * Returns true if the node this indexes has been deleted.
- * @return true if indexed node is known to be deleted
- */
- final boolean indexesDeletedNode() {
- return node.value == null;
- }
-
- /**
- * Tries to CAS newSucc as successor. To minimize races with
- * unlink that may lose this index node, if the node being
- * indexed is known to be deleted, it doesn't try to link in.
- * @param succ the expected current successor
- * @param newSucc the new successor
- * @return true if successful
- */
- final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
- Node<K,V> n = node;
- newSucc.right = succ;
- return n.value != null && casRight(succ, newSucc);
- }
-
- /**
- * Tries to CAS right field to skip over apparent successor
- * succ. Fails (forcing a retraversal by caller) if this node
- * is known to be deleted.
- * @param succ the expected current successor
- * @return true if successful
- */
- final boolean unlink(Index<K,V> succ) {
- return node.value != null && casRight(succ, succ.right);
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long RIGHT;
- static {
- try {
- RIGHT = U.objectFieldOffset
- (Index.class.getDeclaredField("right"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
}
- /* ---------------- Head nodes -------------- */
-
- /**
- * Nodes heading each level keep track of their level.
- */
- static final class HeadIndex<K,V> extends Index<K,V> {
- final int level;
- HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
- super(node, down, right);
- this.level = level;
- }
- }
-
- /* ---------------- Comparison utilities -------------- */
+ /* ---------------- Utilities -------------- */
/**
* Compares using comparator or natural ordering if null.
* Called only by methods that have performed required type checks.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
- static final int cpr(Comparator c, Object x, Object y) {
+ static int cpr(Comparator c, Object x, Object y) {
return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
}
+ /**
+ * Returns the header for base node list, or null if uninitialized
+ */
+ final Node<K,V> baseHead() {
+ Index<K,V> h;
+ VarHandle.acquireFence();
+ return ((h = head) == null) ? null : h.node;
+ }
+
+ /**
+ * Tries to unlink deleted node n from predecessor b (if both
+ * exist), by first splicing in a marker if not already present.
+ * Upon return, node n is sure to be unlinked from b, possibly
+ * via the actions of some other thread.
+ *
+ * @param b if nonnull, predecessor
+ * @param n if nonnull, node known to be deleted
+ */
+ static <K,V> void unlinkNode(Node<K,V> b, Node<K,V> n) {
+ if (b != null && n != null) {
+ Node<K,V> f, p;
+ for (;;) {
+ if ((f = n.next) != null && f.key == null) {
+ p = f.next; // already marked
+ break;
+ }
+ else if (NEXT.compareAndSet(n, f,
+ new Node<K,V>(null, null, f))) {
+ p = f; // add marker
+ break;
+ }
+ }
+ NEXT.compareAndSet(b, n, p);
+ }
+ }
+
+ /**
+ * Adds to element count, initializing adder if necessary
+ *
+ * @param c count to add
+ */
+ private void addCount(long c) {
+ LongAdder a;
+ do {} while ((a = adder) == null &&
+ !ADDER.compareAndSet(this, null, a = new LongAdder()));
+ a.add(c);
+ }
+
+ /**
+ * Returns element count, initializing adder if necessary.
+ */
+ final long getAdderCount() {
+ LongAdder a; long c;
+ do {} while ((a = adder) == null &&
+ !ADDER.compareAndSet(this, null, a = new LongAdder()));
+ return ((c = a.sum()) <= 0L) ? 0L : c; // ignore transient negatives
+ }
+
/* ---------------- Traversal -------------- */
/**
- * Returns a base-level node with key strictly less than given key,
- * or the base-level header if there is no such node. Also
- * unlinks indexes to deleted nodes found along the way. Callers
- * rely on this side-effect of clearing indices to deleted nodes.
- * @param key the key
- * @return a predecessor of key
+ * Returns an index node with key strictly less than given key.
+ * Also unlinks indexes to deleted nodes found along the way.
+ * Callers rely on this side-effect of clearing indices to deleted
+ * nodes.
+ *
+ * @param key if nonnull the key
+ * @return a predecessor node of key, or null if uninitialized or null key
*/
private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
- if (key == null)
- throw new NullPointerException(); // don't postpone errors
- for (;;) {
- for (Index<K,V> q = head, r = q.right, d;;) {
- if (r != null) {
- Node<K,V> n = r.node;
- K k = n.key;
- if (n.value == null) {
- if (!q.unlink(r))
- break; // restart
- r = q.right; // reread r
- continue;
- }
- if (cpr(cmp, key, k) > 0) {
+ Index<K,V> q;
+ VarHandle.acquireFence();
+ if ((q = head) == null || key == null)
+ return null;
+ else {
+ for (Index<K,V> r, d;;) {
+ while ((r = q.right) != null) {
+ Node<K,V> p; K k;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ p.val == null) // unlink index to deleted node
+ RIGHT.compareAndSet(q, r, r.right);
+ else if (cpr(cmp, key, k) > 0)
q = r;
- r = r.right;
- continue;
- }
+ else
+ break;
}
- if ((d = q.down) == null)
+ if ((d = q.down) != null)
+ q = d;
+ else
return q.node;
- q = d;
- r = d.right;
}
}
}
@@ -693,41 +491,11 @@
* deleted nodes seen along the way. Repeatedly traverses at
* base-level looking for key starting at predecessor returned
* from findPredecessor, processing base-level deletions as
- * encountered. Some callers rely on this side-effect of clearing
- * deleted nodes.
- *
- * Restarts occur, at traversal step centered on node n, if:
- *
- * (1) After reading n's next field, n is no longer assumed
- * predecessor b's current successor, which means that
- * we don't have a consistent 3-node snapshot and so cannot
- * unlink any subsequent deleted nodes encountered.
- *
- * (2) n's value field is null, indicating n is deleted, in
- * which case we help out an ongoing structural deletion
- * before retrying. Even though there are cases where such
- * unlinking doesn't require restart, they aren't sorted out
- * here because doing so would not usually outweigh cost of
- * restarting.
- *
- * (3) n is a marker or n's predecessor's value field is null,
- * indicating (among other possibilities) that
- * findPredecessor returned a deleted node. We can't unlink
- * the node because we don't know its predecessor, so rely
- * on another call to findPredecessor to notice and return
- * some earlier predecessor, which it will do. This check is
- * only strictly needed at beginning of loop, (and the
- * b.value check isn't strictly needed at all) but is done
- * each iteration to help avoid contention with other
- * threads by callers that will fail to be able to change
- * links, and so will retry anyway.
- *
- * The traversal loops in doPut, doRemove, and findNear all
- * include the same three kinds of checks. And specialized
- * versions appear in findFirst, and findLast and their variants.
- * They can't easily share code because each uses the reads of
- * fields held in locals occurring in the orders they were
- * performed.
+ * encountered. Restarts occur, at traversal step encountering
+ * node n, if n's key field is null, indicating it is a marker, so
+ * its predecessor is deleted before continuing, which we help do
+ * by re-finding a valid predecessor. The traversal loops in
+ * doPut, doRemove, and findNear all include the same checks.
*
* @param key the key
* @return node holding key, or null if no such
@@ -736,67 +504,81 @@
if (key == null)
throw new NullPointerException(); // don't postpone errors
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
- if (n == null)
- break outer;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) == 0)
+ Node<K,V> b;
+ outer: while ((b = findPredecessor(key, cmp)) != null) {
+ for (;;) {
+ Node<K,V> n; K k; V v; int c;
+ if ((n = b.next) == null)
+ break outer; // empty
+ else if ((k = n.key) == null)
+ break; // b is deleted
+ else if ((v = n.val) == null)
+ unlinkNode(b, n); // n is deleted
+ else if ((c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else if (c == 0)
return n;
- if (c < 0)
+ else
break outer;
- b = n;
- n = f;
}
}
return null;
}
/**
- * Gets value for key. Almost the same as findNode, but returns
- * the found value (to avoid retries during re-reads)
+ * Gets value for key. Same idea as findNode, except skips over
+ * deletions and markers, and returns first encountered value to
+ * avoid possibly inconsistent rereads.
*
* @param key the key
* @return the value, or null if absent
*/
private V doGet(Object key) {
+ Index<K,V> q;
+ VarHandle.acquireFence();
if (key == null)
throw new NullPointerException();
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
- if (n == null)
- break outer;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
+ V result = null;
+ if ((q = head) != null) {
+ outer: for (Index<K,V> r, d;;) {
+ while ((r = q.right) != null) {
+ Node<K,V> p; K k; V v; int c;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ (v = p.val) == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else if ((c = cpr(cmp, key, k)) > 0)
+ q = r;
+ else if (c == 0) {
+ result = v;
+ break outer;
+ }
+ else
+ break;
+ }
+ if ((d = q.down) != null)
+ q = d;
+ else {
+ Node<K,V> b, n;
+ if ((b = q.node) != null) {
+ while ((n = b.next) != null) {
+ V v; int c;
+ K k = n.key;
+ if ((v = n.val) == null || k == null ||
+ (c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else {
+ if (c == 0)
+ result = v;
+ break;
+ }
+ }
+ }
break;
}
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) == 0) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
- if (c < 0)
- break outer;
- b = n;
- n = f;
}
}
- return null;
+ return result;
}
/* ---------------- Insertion -------------- */
@@ -804,126 +586,160 @@
/**
* Main insertion method. Adds element if not present, or
* replaces value if present and onlyIfAbsent is false.
+ *
* @param key the key
* @param value the value that must be associated with key
* @param onlyIfAbsent if should not insert if already present
* @return the old value, or null if newly inserted
*/
private V doPut(K key, V value, boolean onlyIfAbsent) {
- Node<K,V> z; // added node
if (key == null)
throw new NullPointerException();
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- if (n != null) {
- Object v; int c;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) > 0) {
- b = n;
- n = f;
- continue;
- }
- if (c == 0) {
- if (onlyIfAbsent || n.casValue(v, value)) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
- break; // restart if lost race to replace value
- }
- // else c < 0; fall through
- }
-
- z = new Node<K,V>(key, value, n);
- if (!b.casNext(n, z))
- break; // restart if lost race to append to b
- break outer;
+ for (;;) {
+ Index<K,V> h; Node<K,V> b;
+ VarHandle.acquireFence();
+ int levels = 0; // number of levels descended
+ if ((h = head) == null) { // try to initialize
+ Node<K,V> base = new Node<K,V>(null, null, null);
+ h = new Index<K,V>(base, null, null);
+ b = (HEAD.compareAndSet(this, null, h)) ? base : null;
}
- }
-
- int rnd = ThreadLocalRandom.nextSecondarySeed();
- if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
- int level = 1, max;
- while (((rnd >>>= 1) & 1) != 0)
- ++level;
- Index<K,V> idx = null;
- HeadIndex<K,V> h = head;
- if (level <= (max = h.level)) {
- for (int i = 1; i <= level; ++i)
- idx = new Index<K,V>(z, idx, null);
- }
- else { // try to grow by one level
- level = max + 1; // hold in array and later pick the one to use
- @SuppressWarnings("unchecked")Index<K,V>[] idxs =
- (Index<K,V>[])new Index<?,?>[level+1];
- for (int i = 1; i <= level; ++i)
- idxs[i] = idx = new Index<K,V>(z, idx, null);
- for (;;) {
- h = head;
- int oldLevel = h.level;
- if (level <= oldLevel) // lost race to add level
- break;
- HeadIndex<K,V> newh = h;
- Node<K,V> oldbase = h.node;
- for (int j = oldLevel+1; j <= level; ++j)
- newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
- if (casHead(h, newh)) {
- h = newh;
- idx = idxs[level = oldLevel];
- break;
- }
- }
- }
- // find insertion points and splice in
- splice: for (int insertionLevel = level;;) {
- int j = h.level;
- for (Index<K,V> q = h, r = q.right, t = idx;;) {
- if (q == null || t == null)
- break splice;
- if (r != null) {
- Node<K,V> n = r.node;
- // compare before deletion check avoids needing recheck
- int c = cpr(cmp, key, n.key);
- if (n.value == null) {
- if (!q.unlink(r))
- break;
- r = q.right;
- continue;
- }
- if (c > 0) {
+ else {
+ for (Index<K,V> q = h, r, d;;) { // count while descending
+ while ((r = q.right) != null) {
+ Node<K,V> p; K k;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ p.val == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else if (cpr(cmp, key, k) > 0)
q = r;
- r = r.right;
- continue;
- }
+ else
+ break;
}
-
- if (j == insertionLevel) {
- if (!q.link(r, t))
- break; // restart
- if (t.node.value == null) {
- findNode(key);
- break splice;
- }
- if (--insertionLevel == 0)
- break splice;
+ if ((d = q.down) != null) {
+ ++levels;
+ q = d;
}
+ else {
+ b = q.node;
+ break;
+ }
+ }
+ }
+ if (b != null) {
+ Node<K,V> z = null; // new node, if inserted
+ for (;;) { // find insertion point
+ Node<K,V> n, p; K k; V v; int c;
+ if ((n = b.next) == null) {
+ if (b.key == null) // if empty, type check key now
+ cpr(cmp, key, key);
+ c = -1;
+ }
+ else if ((k = n.key) == null)
+ break; // can't append; restart
+ else if ((v = n.val) == null) {
+ unlinkNode(b, n);
+ c = 1;
+ }
+ else if ((c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else if (c == 0 &&
+ (onlyIfAbsent || VAL.compareAndSet(n, v, value)))
+ return v;
- if (--j >= insertionLevel && j < level)
- t = t.down;
- q = q.down;
- r = q.right;
+ if (c < 0 &&
+ NEXT.compareAndSet(b, n,
+ p = new Node<K,V>(key, value, n))) {
+ z = p;
+ break;
+ }
+ }
+
+ if (z != null) {
+ int lr = ThreadLocalRandom.nextSecondarySeed();
+ if ((lr & 0x3) == 0) { // add indices with 1/4 prob
+ int hr = ThreadLocalRandom.nextSecondarySeed();
+ long rnd = ((long)hr << 32) | ((long)lr & 0xffffffffL);
+ int skips = levels; // levels to descend before add
+ Index<K,V> x = null;
+ for (;;) { // create at most 62 indices
+ x = new Index<K,V>(z, x, null);
+ if (rnd >= 0L || --skips < 0)
+ break;
+ else
+ rnd <<= 1;
+ }
+ if (addIndices(h, skips, x, cmp) && skips < 0 &&
+ head == h) { // try to add new level
+ Index<K,V> hx = new Index<K,V>(z, x, null);
+ Index<K,V> nh = new Index<K,V>(h.node, h, hx);
+ HEAD.compareAndSet(this, h, nh);
+ }
+ if (z.val == null) // deleted while adding indices
+ findPredecessor(key, cmp); // clean
+ }
+ addCount(1L);
+ return null;
}
}
}
- return null;
+ }
+
+ /**
+ * Add indices after an insertion. Descends iteratively to the
+ * highest level of insertion, then recursively, to chain index
+ * nodes to lower ones. Returns null on (staleness) failure,
+ * disabling higher-level insertions. Recursion depths are
+ * exponentially less probable.
+ *
+ * @param q starting index for current level
+ * @param skips levels to skip before inserting
+ * @param x index for this insertion
+ * @param cmp comparator
+ */
+ static <K,V> boolean addIndices(Index<K,V> q, int skips, Index<K,V> x,
+ Comparator<? super K> cmp) {
+ Node<K,V> z; K key;
+ if (x != null && (z = x.node) != null && (key = z.key) != null &&
+ q != null) { // hoist checks
+ boolean retrying = false;
+ for (;;) { // find splice point
+ Index<K,V> r, d; int c;
+ if ((r = q.right) != null) {
+ Node<K,V> p; K k;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ p.val == null) {
+ RIGHT.compareAndSet(q, r, r.right);
+ c = 0;
+ }
+ else if ((c = cpr(cmp, key, k)) > 0)
+ q = r;
+ else if (c == 0)
+ break; // stale
+ }
+ else
+ c = -1;
+
+ if (c < 0) {
+ if ((d = q.down) != null && skips > 0) {
+ --skips;
+ q = d;
+ }
+ else if (d != null && !retrying &&
+ !addIndices(d, 0, x.down, cmp))
+ break;
+ else {
+ x.right = r;
+ if (RIGHT.compareAndSet(q, r, x))
+ return true;
+ else
+ retrying = true; // re-find splice point
+ }
+ }
+ }
+ }
+ return false;
}
/* ---------------- Deletion -------------- */
@@ -933,15 +749,6 @@
* deletion marker, unlinks predecessor, removes associated index
* nodes, and possibly reduces head index level.
*
- * Index nodes are cleared out simply by calling findPredecessor.
- * which unlinks indexes to deleted nodes found along path to key,
- * which will include the indexes to this node. This is done
- * unconditionally. We can't check beforehand whether there are
- * index nodes because it might be the case that some or all
- * indexes hadn't been inserted yet for this node during initial
- * search for it, and we'd like to ensure lack of garbage
- * retention, so must call to be sure.
- *
* @param key the key
* @param value if non-null, the value that must be
* associated with key
@@ -951,43 +758,36 @@
if (key == null)
throw new NullPointerException();
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
- if (n == null)
+ V result = null;
+ Node<K,V> b;
+ outer: while ((b = findPredecessor(key, cmp)) != null &&
+ result == null) {
+ for (;;) {
+ Node<K,V> n; K k; V v; int c;
+ if ((n = b.next) == null)
break outer;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
+ else if ((k = n.key) == null)
break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) < 0)
- break outer;
- if (c > 0) {
+ else if ((v = n.val) == null)
+ unlinkNode(b, n);
+ else if ((c = cpr(cmp, key, k)) > 0)
b = n;
- n = f;
- continue;
- }
- if (value != null && !value.equals(v))
+ else if (c < 0)
break outer;
- if (!n.casValue(v, null))
- break;
- if (!n.appendMarker(f) || !b.casNext(n, f))
- findNode(key); // retry via findNode
- else {
- findPredecessor(key, cmp); // clean index
- if (head.right == null)
- tryReduceLevel();
+ else if (value != null && !value.equals(v))
+ break outer;
+ else if (VAL.compareAndSet(n, v, null)) {
+ result = v;
+ unlinkNode(b, n);
+ break; // loop to clean up
}
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
}
}
- return null;
+ if (result != null) {
+ tryReduceLevel();
+ addCount(-1L);
+ }
+ return result;
}
/**
@@ -1011,125 +811,71 @@
* reduction.
*/
private void tryReduceLevel() {
- HeadIndex<K,V> h = head;
- HeadIndex<K,V> d;
- HeadIndex<K,V> e;
- if (h.level > 3 &&
- (d = (HeadIndex<K,V>)h.down) != null &&
- (e = (HeadIndex<K,V>)d.down) != null &&
- e.right == null &&
- d.right == null &&
- h.right == null &&
- casHead(h, d) && // try to set
- h.right != null) // recheck
- casHead(d, h); // try to backout
+ Index<K,V> h, d, e;
+ if ((h = head) != null && h.right == null &&
+ (d = h.down) != null && d.right == null &&
+ (e = d.down) != null && e.right == null &&
+ HEAD.compareAndSet(this, h, d) &&
+ h.right != null) // recheck
+ HEAD.compareAndSet(this, d, h); // try to backout
}
/* ---------------- Finding and removing first element -------------- */
/**
- * Specialized variant of findNode to get first valid node.
+ * Gets first valid node, unlinking deleted nodes if encountered.
* @return first node or null if empty
*/
final Node<K,V> findFirst() {
- for (Node<K,V> b, n;;) {
- if ((n = (b = head.node).next) == null)
- return null;
- if (n.value != null)
- return n;
- n.helpDelete(b, n.next);
+ Node<K,V> b, n;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if (n.val == null)
+ unlinkNode(b, n);
+ else
+ return n;
+ }
}
+ return null;
+ }
+
+ /**
+ * Entry snapshot version of findFirst
+ */
+ final AbstractMap.SimpleImmutableEntry<K,V> findFirstEntry() {
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) == null)
+ unlinkNode(b, n);
+ else
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+ }
+ }
+ return null;
}
/**
* Removes first entry; returns its snapshot.
* @return null if empty, else snapshot of first entry
*/
- private Map.Entry<K,V> doRemoveFirstEntry() {
- for (Node<K,V> b, n;;) {
- if ((n = (b = head.node).next) == null)
- return null;
- Node<K,V> f = n.next;
- if (n != b.next)
- continue;
- Object v = n.value;
- if (v == null) {
- n.helpDelete(b, f);
- continue;
- }
- if (!n.casValue(v, null))
- continue;
- if (!n.appendMarker(f) || !b.casNext(n, f))
- findFirst(); // retry
- clearIndexToFirst();
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
- }
- }
-
- /**
- * Clears out index nodes associated with deleted first entry.
- */
- private void clearIndexToFirst() {
- for (;;) {
- for (Index<K,V> q = head;;) {
- Index<K,V> r = q.right;
- if (r != null && r.indexesDeletedNode() && !q.unlink(r))
- break;
- if ((q = q.down) == null) {
- if (head.right == null)
+ private AbstractMap.SimpleImmutableEntry<K,V> doRemoveFirstEntry() {
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) == null || VAL.compareAndSet(n, v, null)) {
+ K k = n.key;
+ unlinkNode(b, n);
+ if (v != null) {
tryReduceLevel();
- return;
+ findPredecessor(k, comparator); // clean index
+ addCount(-1L);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
}
}
}
- }
-
- /**
- * Removes last entry; returns its snapshot.
- * Specialized variant of doRemove.
- * @return null if empty, else snapshot of last entry
- */
- private Map.Entry<K,V> doRemoveLastEntry() {
- for (;;) {
- Node<K,V> b = findPredecessorOfLast();
- Node<K,V> n = b.next;
- if (n == null) {
- if (b.isBaseHeader()) // empty
- return null;
- else
- continue; // all b's successors are deleted; retry
- }
- for (;;) {
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- Object v = n.value;
- if (v == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if (f != null) {
- b = n;
- n = f;
- continue;
- }
- if (!n.casValue(v, null))
- break;
- K key = n.key;
- if (!n.appendMarker(f) || !b.casNext(n, f))
- findNode(key); // retry via findNode
- else { // clean index
- findPredecessor(key, comparator);
- if (head.right == null)
- tryReduceLevel();
- }
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
- }
- }
+ return null;
}
/* ---------------- Finding and removing last element -------------- */
@@ -1139,73 +885,115 @@
* @return last node or null if empty
*/
final Node<K,V> findLast() {
- /*
- * findPredecessor can't be used to traverse index level
- * because this doesn't use comparisons. So traversals of
- * both levels are folded together.
- */
- Index<K,V> q = head;
- for (;;) {
- Index<K,V> d, r;
- if ((r = q.right) != null) {
- if (r.indexesDeletedNode()) {
- q.unlink(r);
- q = head; // restart
+ outer: for (;;) {
+ Index<K,V> q; Node<K,V> b;
+ VarHandle.acquireFence();
+ if ((q = head) == null)
+ break;
+ for (Index<K,V> r, d;;) {
+ while ((r = q.right) != null) {
+ Node<K,V> p;
+ if ((p = r.node) == null || p.val == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else
+ q = r;
}
- else
- q = r;
- } else if ((d = q.down) != null) {
- q = d;
- } else {
- for (Node<K,V> b = q.node, n = b.next;;) {
- if (n == null)
- return b.isBaseHeader() ? null : b;
- Node<K,V> f = n.next; // inconsistent read
- if (n != b.next)
- break;
- Object v = n.value;
- if (v == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- b = n;
- n = f;
+ if ((d = q.down) != null)
+ q = d;
+ else {
+ b = q.node;
+ break;
}
- q = head; // restart
}
+ if (b != null) {
+ for (;;) {
+ Node<K,V> n;
+ if ((n = b.next) == null) {
+ if (b.key == null) // empty
+ break outer;
+ else
+ return b;
+ }
+ else if (n.key == null)
+ break;
+ else if (n.val == null)
+ unlinkNode(b, n);
+ else
+ b = n;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Entry version of findLast
+ * @return Entry for last node or null if empty
+ */
+ final AbstractMap.SimpleImmutableEntry<K,V> findLastEntry() {
+ for (;;) {
+ Node<K,V> n; V v;
+ if ((n = findLast()) == null)
+ return null;
+ if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
/**
- * Specialized variant of findPredecessor to get predecessor of last
- * valid node. Needed when removing the last entry. It is possible
- * that all successors of returned node will have been deleted upon
- * return, in which case this method can be retried.
- * @return likely predecessor of last node
+ * Removes last entry; returns its snapshot.
+ * Specialized variant of doRemove.
+ * @return null if empty, else snapshot of last entry
*/
- private Node<K,V> findPredecessorOfLast() {
- for (;;) {
- for (Index<K,V> q = head;;) {
- Index<K,V> d, r;
- if ((r = q.right) != null) {
- if (r.indexesDeletedNode()) {
- q.unlink(r);
- break; // must restart
- }
- // proceed as far across as possible without overshooting
- if (r.node.next != null) {
- q = r;
- continue;
- }
+ private Map.Entry<K,V> doRemoveLastEntry() {
+ outer: for (;;) {
+ Index<K,V> q; Node<K,V> b;
+ VarHandle.acquireFence();
+ if ((q = head) == null)
+ break;
+ for (;;) {
+ Index<K,V> d, r; Node<K,V> p;
+ while ((r = q.right) != null) {
+ if ((p = r.node) == null || p.val == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else if (p.next != null)
+ q = r; // continue only if a successor
+ else
+ break;
}
if ((d = q.down) != null)
q = d;
- else
- return q.node;
+ else {
+ b = q.node;
+ break;
+ }
+ }
+ if (b != null) {
+ for (;;) {
+ Node<K,V> n; K k; V v;
+ if ((n = b.next) == null) {
+ if (b.key == null) // empty
+ break outer;
+ else
+ break; // retry
+ }
+ else if ((k = n.key) == null)
+ break;
+ else if ((v = n.val) == null)
+ unlinkNode(b, n);
+ else if (n.next != null)
+ b = n;
+ else if (VAL.compareAndSet(n, v, null)) {
+ unlinkNode(b, n);
+ tryReduceLevel();
+ findPredecessor(k, comparator); // clean index
+ addCount(-1L);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
+ }
}
}
+ return null;
}
/* ---------------- Relational operations -------------- */
@@ -1225,47 +1013,52 @@
final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
if (key == null)
throw new NullPointerException();
- for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v;
- if (n == null)
- return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
+ Node<K,V> result;
+ outer: for (Node<K,V> b;;) {
+ if ((b = findPredecessor(key, cmp)) == null) {
+ result = null;
+ break; // empty
+ }
+ for (;;) {
+ Node<K,V> n; K k; int c;
+ if ((n = b.next) == null) {
+ result = ((rel & LT) != 0 && b.key != null) ? b : null;
+ break outer;
}
- if (b.value == null || v == n) // b is deleted
+ else if ((k = n.key) == null)
break;
- int c = cpr(cmp, key, n.key);
- if ((c == 0 && (rel & EQ) != 0) ||
- (c < 0 && (rel & LT) == 0))
- return n;
- if ( c <= 0 && (rel & LT) != 0)
- return b.isBaseHeader() ? null : b;
- b = n;
- n = f;
+ else if (n.val == null)
+ unlinkNode(b, n);
+ else if (((c = cpr(cmp, key, k)) == 0 && (rel & EQ) != 0) ||
+ (c < 0 && (rel & LT) == 0)) {
+ result = n;
+ break outer;
+ }
+ else if (c <= 0 && (rel & LT) != 0) {
+ result = (b.key != null) ? b : null;
+ break outer;
+ }
+ else
+ b = n;
}
}
+ return result;
}
/**
- * Returns SimpleImmutableEntry for results of findNear.
+ * Variant of findNear returning SimpleImmutableEntry
* @param key the key
* @param rel the relation -- OR'ed combination of EQ, LT, GT
* @return Entry fitting relation, or null if no such
*/
- final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
- Comparator<? super K> cmp = comparator;
+ final AbstractMap.SimpleImmutableEntry<K,V> findNearEntry(K key, int rel,
+ Comparator<? super K> cmp) {
for (;;) {
- Node<K,V> n = findNear(key, rel, cmp);
- if (n == null)
+ Node<K,V> n; V v;
+ if ((n = findNear(key, rel, cmp)) == null)
return null;
- AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
+ if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
@@ -1277,7 +1070,6 @@
*/
public ConcurrentSkipListMap() {
this.comparator = null;
- initialize();
}
/**
@@ -1290,7 +1082,6 @@
*/
public ConcurrentSkipListMap(Comparator<? super K> comparator) {
this.comparator = comparator;
- initialize();
}
/**
@@ -1306,7 +1097,6 @@
*/
public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
this.comparator = null;
- initialize();
putAll(m);
}
@@ -1321,8 +1111,7 @@
*/
public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
this.comparator = m.comparator();
- initialize();
- buildFromSorted(m);
+ buildFromSorted(m); // initializes transients
}
/**
@@ -1336,7 +1125,10 @@
@SuppressWarnings("unchecked")
ConcurrentSkipListMap<K,V> clone =
(ConcurrentSkipListMap<K,V>) super.clone();
- clone.initialize();
+ clone.keySet = null;
+ clone.entrySet = null;
+ clone.values = null;
+ clone.descendingMap = null;
clone.buildFromSorted(this);
return clone;
} catch (CloneNotSupportedException e) {
@@ -1352,58 +1144,49 @@
private void buildFromSorted(SortedMap<K, ? extends V> map) {
if (map == null)
throw new NullPointerException();
-
- HeadIndex<K,V> h = head;
- Node<K,V> basepred = h.node;
-
- // Track the current rightmost node at each level. Uses an
- // ArrayList to avoid committing to initial or maximum level.
- ArrayList<Index<K,V>> preds = new ArrayList<>();
-
- // initialize
- for (int i = 0; i <= h.level; ++i)
- preds.add(null);
- Index<K,V> q = h;
- for (int i = h.level; i > 0; --i) {
- preds.set(i, q);
- q = q.down;
- }
-
Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
map.entrySet().iterator();
+
+ /*
+ * Add equally spaced indices at log intervals, using the bits
+ * of count during insertion. The maximum possible resulting
+ * level is less than the number of bits in a long (64). The
+ * preds array tracks the current rightmost node at each
+ * level.
+ */
+ @SuppressWarnings("unchecked")
+ Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+ Node<K,V> bp = new Node<K,V>(null, null, null);
+ Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+ long count = 0;
+
while (it.hasNext()) {
Map.Entry<? extends K, ? extends V> e = it.next();
- int rnd = ThreadLocalRandom.current().nextInt();
- int j = 0;
- if ((rnd & 0x80000001) == 0) {
- do {
- ++j;
- } while (((rnd >>>= 1) & 1) != 0);
- if (j > h.level) j = h.level + 1;
- }
K k = e.getKey();
V v = e.getValue();
if (k == null || v == null)
throw new NullPointerException();
Node<K,V> z = new Node<K,V>(k, v, null);
- basepred.next = z;
- basepred = z;
- if (j > 0) {
- Index<K,V> idx = null;
- for (int i = 1; i <= j; ++i) {
+ bp = bp.next = z;
+ if ((++count & 3L) == 0L) {
+ long m = count >>> 2;
+ int i = 0;
+ Index<K,V> idx = null, q;
+ do {
idx = new Index<K,V>(z, idx, null);
- if (i > h.level)
- h = new HeadIndex<K,V>(h.node, h, idx, i);
-
- if (i < preds.size()) {
- preds.get(i).right = idx;
- preds.set(i, idx);
- } else
- preds.add(idx);
- }
+ if ((q = preds[i]) == null)
+ preds[i] = h = new Index<K,V>(h.node, h, idx);
+ else
+ preds[i] = q.right = idx;
+ } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
}
}
- head = h;
+ if (count != 0L) {
+ VarHandle.releaseFence(); // emulate volatile stores
+ addCount(count);
+ head = h;
+ VarHandle.fullFence();
+ }
}
/* ---------------- Serialization -------------- */
@@ -1425,11 +1208,14 @@
s.defaultWriteObject();
// Write out keys and values (alternating)
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v = n.getValidValue();
- if (v != null) {
- s.writeObject(n.key);
- s.writeObject(v);
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null) {
+ s.writeObject(n.key);
+ s.writeObject(v);
+ }
+ b = n;
}
}
s.writeObject(null);
@@ -1447,64 +1233,47 @@
throws java.io.IOException, ClassNotFoundException {
// Read in the Comparator and any hidden stuff
s.defaultReadObject();
- // Reset transients
- initialize();
- /*
- * This is nearly identical to buildFromSorted, but is
- * distinct because readObject calls can't be nicely adapted
- * as the kind of iterator needed by buildFromSorted. (They
- * can be, but doing so requires type cheats and/or creation
- * of adapter classes.) It is simpler to just adapt the code.
- */
-
- HeadIndex<K,V> h = head;
- Node<K,V> basepred = h.node;
- ArrayList<Index<K,V>> preds = new ArrayList<>();
- for (int i = 0; i <= h.level; ++i)
- preds.add(null);
- Index<K,V> q = h;
- for (int i = h.level; i > 0; --i) {
- preds.set(i, q);
- q = q.down;
- }
+ // Same idea as buildFromSorted
+ @SuppressWarnings("unchecked")
+ Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+ Node<K,V> bp = new Node<K,V>(null, null, null);
+ Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+ Comparator<? super K> cmp = comparator;
+ K prevKey = null;
+ long count = 0;
for (;;) {
- Object k = s.readObject();
+ K k = (K)s.readObject();
if (k == null)
break;
- Object v = s.readObject();
+ V v = (V)s.readObject();
if (v == null)
throw new NullPointerException();
- K key = (K) k;
- V val = (V) v;
- int rnd = ThreadLocalRandom.current().nextInt();
- int j = 0;
- if ((rnd & 0x80000001) == 0) {
+ if (prevKey != null && cpr(cmp, prevKey, k) > 0)
+ throw new IllegalStateException("out of order");
+ prevKey = k;
+ Node<K,V> z = new Node<K,V>(k, v, null);
+ bp = bp.next = z;
+ if ((++count & 3L) == 0L) {
+ long m = count >>> 2;
+ int i = 0;
+ Index<K,V> idx = null, q;
do {
- ++j;
- } while (((rnd >>>= 1) & 1) != 0);
- if (j > h.level) j = h.level + 1;
- }
- Node<K,V> z = new Node<K,V>(key, val, null);
- basepred.next = z;
- basepred = z;
- if (j > 0) {
- Index<K,V> idx = null;
- for (int i = 1; i <= j; ++i) {
idx = new Index<K,V>(z, idx, null);
- if (i > h.level)
- h = new HeadIndex<K,V>(h.node, h, idx, i);
-
- if (i < preds.size()) {
- preds.get(i).right = idx;
- preds.set(i, idx);
- } else
- preds.add(idx);
- }
+ if ((q = preds[i]) == null)
+ preds[i] = h = new Index<K,V>(h.node, h, idx);
+ else
+ preds[i] = q.right = idx;
+ } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
}
}
- head = h;
+ if (count != 0L) {
+ VarHandle.releaseFence();
+ addCount(count);
+ head = h;
+ VarHandle.fullFence();
+ }
}
/* ------ Map API methods ------ */
@@ -1605,42 +1374,30 @@
public boolean containsValue(Object value) {
if (value == null)
throw new NullPointerException();
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v = n.getValidValue();
- if (v != null && value.equals(v))
- return true;
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null && value.equals(v))
+ return true;
+ else
+ b = n;
+ }
}
return false;
}
/**
- * Returns the number of key-value mappings in this map. If this map
- * contains more than {@code Integer.MAX_VALUE} elements, it
- * returns {@code Integer.MAX_VALUE}.
- *
- * <p>Beware that, unlike in most collections, this method is
- * <em>NOT</em> a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current
- * number of elements requires traversing them all to count them.
- * Additionally, it is possible for the size to change during
- * execution of this method, in which case the returned result
- * will be inaccurate. Thus, this method is typically not very
- * useful in concurrent applications.
- *
- * @return the number of elements in this map
+ * {@inheritDoc}
*/
public int size() {
- long count = 0;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- if (n.getValidValue() != null)
- ++count;
- }
- return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+ long c;
+ return ((baseHead() == null) ? 0 :
+ ((c = getAdderCount()) >= Integer.MAX_VALUE) ?
+ Integer.MAX_VALUE : (int) c);
}
/**
- * Returns {@code true} if this map contains no key-value mappings.
- * @return {@code true} if this map contains no key-value mappings
+ * {@inheritDoc}
*/
public boolean isEmpty() {
return findFirst() == null;
@@ -1650,7 +1407,33 @@
* Removes all of the mappings from this map.
*/
public void clear() {
- initialize();
+ Index<K,V> h, r, d; Node<K,V> b;
+ VarHandle.acquireFence();
+ while ((h = head) != null) {
+ if ((r = h.right) != null) // remove indices
+ RIGHT.compareAndSet(h, r, null);
+ else if ((d = h.down) != null) // remove levels
+ HEAD.compareAndSet(this, h, d);
+ else {
+ long count = 0L;
+ if ((b = h.node) != null) { // remove nodes
+ Node<K,V> n; V v;
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null &&
+ VAL.compareAndSet(n, v, null)) {
+ --count;
+ v = null;
+ }
+ if (v == null)
+ unlinkNode(b, n);
+ }
+ }
+ if (count != 0L)
+ addCount(count);
+ else
+ break;
+ }
+ }
}
/**
@@ -1696,16 +1479,15 @@
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
- Node<K,V> n; Object v;
+ Node<K,V> n; V v;
while ((n = findNode(key)) != null) {
- if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- V r = remappingFunction.apply(key, vv);
+ if ((v = n.val) != null) {
+ V r = remappingFunction.apply(key, v);
if (r != null) {
- if (n.casValue(vv, r))
+ if (VAL.compareAndSet(n, v, r))
return r;
}
- else if (doRemove(key, vv) != null)
+ else if (doRemove(key, v) != null)
break;
}
}
@@ -1730,20 +1512,19 @@
if (key == null || remappingFunction == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v; V r;
+ Node<K,V> n; V v; V r;
if ((n = findNode(key)) == null) {
if ((r = remappingFunction.apply(key, null)) == null)
break;
if (doPut(key, r, true) == null)
return r;
}
- else if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- if ((r = remappingFunction.apply(key, vv)) != null) {
- if (n.casValue(vv, r))
+ else if ((v = n.val) != null) {
+ if ((r = remappingFunction.apply(key, v)) != null) {
+ if (VAL.compareAndSet(n, v, r))
return r;
}
- else if (doRemove(key, vv) != null)
+ else if (doRemove(key, v) != null)
break;
}
}
@@ -1770,18 +1551,17 @@
if (key == null || value == null || remappingFunction == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v; V r;
+ Node<K,V> n; V v; V r;
if ((n = findNode(key)) == null) {
if (doPut(key, value, true) == null)
return value;
}
- else if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- if ((r = remappingFunction.apply(vv, value)) != null) {
- if (n.casValue(vv, r))
+ else if ((v = n.val) != null) {
+ if ((r = remappingFunction.apply(v, value)) != null) {
+ if (VAL.compareAndSet(n, v, r))
return r;
}
- else if (doRemove(key, vv) != null)
+ else if (doRemove(key, v) != null)
return null;
}
}
@@ -1805,9 +1585,11 @@
* The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
* {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
* {@link Spliterator#ORDERED}, with an encounter order that is ascending
- * key order. The spliterator's comparator (see
- * {@link java.util.Spliterator#getComparator()}) is {@code null} if
- * the map's comparator (see {@link #comparator()}) is {@code null}.
+ * key order.
+ *
+ * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
+ * is {@code null} if the {@linkplain #comparator() map's comparator}
+ * is {@code null}.
* Otherwise, the spliterator's comparator is the same as or imposes the
* same total ordering as the map's comparator.
*
@@ -1827,13 +1609,15 @@
* @return a navigable set view of the keys in this map
*/
public NavigableSet<K> keySet() {
- KeySet<K,V> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet<>(this));
+ KeySet<K,V> ks;
+ if ((ks = keySet) != null) return ks;
+ return keySet = new KeySet<>(this);
}
public NavigableSet<K> navigableKeySet() {
- KeySet<K,V> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet<>(this));
+ KeySet<K,V> ks;
+ if ((ks = keySet) != null) return ks;
+ return keySet = new KeySet<>(this);
}
/**
@@ -1856,8 +1640,9 @@
* <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
*/
public Collection<V> values() {
- Values<K,V> vs = values;
- return (vs != null) ? vs : (values = new Values<>(this));
+ Values<K,V> vs;
+ if ((vs = values) != null) return vs;
+ return values = new Values<>(this);
}
/**
@@ -1888,14 +1673,16 @@
* sorted in ascending key order
*/
public Set<Map.Entry<K,V>> entrySet() {
- EntrySet<K,V> es = entrySet;
- return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
+ EntrySet<K,V> es;
+ if ((es = entrySet) != null) return es;
+ return entrySet = new EntrySet<K,V>(this);
}
public ConcurrentNavigableMap<K,V> descendingMap() {
- ConcurrentNavigableMap<K,V> dm = descendingMap;
- return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
- (this, null, false, null, false, true));
+ ConcurrentNavigableMap<K,V> dm;
+ if ((dm = descendingMap) != null) return dm;
+ return descendingMap =
+ new SubMap<K,V>(this, null, false, null, false, true);
}
public NavigableSet<K> descendingKeySet() {
@@ -1923,19 +1710,61 @@
return false;
Map<?,?> m = (Map<?,?>) o;
try {
- for (Map.Entry<K,V> e : this.entrySet())
- if (! e.getValue().equals(m.get(e.getKey())))
- return false;
- for (Map.Entry<?,?> e : m.entrySet()) {
- Object k = e.getKey();
- Object v = e.getValue();
- if (k == null || v == null || !v.equals(get(k)))
- return false;
+ Comparator<? super K> cmp = comparator;
+ @SuppressWarnings("unchecked")
+ Iterator<Map.Entry<?,?>> it =
+ (Iterator<Map.Entry<?,?>>)m.entrySet().iterator();
+ if (m instanceof SortedMap &&
+ ((SortedMap<?,?>)m).comparator() == cmp) {
+ Node<K,V> b, n;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ K k; V v;
+ if ((v = n.val) != null && (k = n.key) != null) {
+ if (!it.hasNext())
+ return false;
+ Map.Entry<?,?> e = it.next();
+ Object mk = e.getKey();
+ Object mv = e.getValue();
+ if (mk == null || mv == null)
+ return false;
+ try {
+ if (cpr(cmp, k, mk) != 0)
+ return false;
+ } catch (ClassCastException cce) {
+ return false;
+ }
+ if (!mv.equals(v))
+ return false;
+ }
+ b = n;
+ }
+ }
+ return !it.hasNext();
}
- return true;
- } catch (ClassCastException unused) {
- return false;
- } catch (NullPointerException unused) {
+ else {
+ while (it.hasNext()) {
+ V v;
+ Map.Entry<?,?> e = it.next();
+ Object mk = e.getKey();
+ Object mv = e.getValue();
+ if (mk == null || mv == null ||
+ (v = get(mk)) == null || !v.equals(mv))
+ return false;
+ }
+ Node<K,V> b, n;
+ if ((b = baseHead()) != null) {
+ K k; V v; Object mv;
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null && (k = n.key) != null &&
+ ((mv = m.get(k)) == null || !mv.equals(v)))
+ return false;
+ b = n;
+ }
+ }
+ return true;
+ }
+ } catch (ClassCastException | NullPointerException unused) {
return false;
}
}
@@ -1981,13 +1810,13 @@
if (key == null || oldValue == null || newValue == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v;
+ Node<K,V> n; V v;
if ((n = findNode(key)) == null)
return false;
- if ((v = n.value) != null) {
+ if ((v = n.val) != null) {
if (!oldValue.equals(v))
return false;
- if (n.casValue(v, newValue))
+ if (VAL.compareAndSet(n, v, newValue))
return true;
}
}
@@ -2006,13 +1835,11 @@
if (key == null || value == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v;
+ Node<K,V> n; V v;
if ((n = findNode(key)) == null)
return null;
- if ((v = n.value) != null && n.casValue(v, value)) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
+ if ((v = n.val) != null && VAL.compareAndSet(n, v, value))
+ return v;
}
}
@@ -2122,7 +1949,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> lowerEntry(K key) {
- return getNear(key, LT);
+ return findNearEntry(key, LT, comparator);
}
/**
@@ -2145,7 +1972,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> floorEntry(K key) {
- return getNear(key, LT|EQ);
+ return findNearEntry(key, LT|EQ, comparator);
}
/**
@@ -2168,7 +1995,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> ceilingEntry(K key) {
- return getNear(key, GT|EQ);
+ return findNearEntry(key, GT|EQ, comparator);
}
/**
@@ -2191,7 +2018,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> higherEntry(K key) {
- return getNear(key, GT);
+ return findNearEntry(key, GT, comparator);
}
/**
@@ -2211,14 +2038,7 @@
* the {@code Entry.setValue} method.
*/
public Map.Entry<K,V> firstEntry() {
- for (;;) {
- Node<K,V> n = findFirst();
- if (n == null)
- return null;
- AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
- }
+ return findFirstEntry();
}
/**
@@ -2228,14 +2048,7 @@
* the {@code Entry.setValue} method.
*/
public Map.Entry<K,V> lastEntry() {
- for (;;) {
- Node<K,V> n = findLast();
- if (n == null)
- return null;
- AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
- }
+ return findLastEntry();
}
/**
@@ -2258,11 +2071,10 @@
return doRemoveLastEntry();
}
-
/* ---------------- Iterators -------------- */
/**
- * Base of iterator classes:
+ * Base of iterator classes
*/
abstract class Iter<T> implements Iterator<T> {
/** the last node returned by next() */
@@ -2274,14 +2086,7 @@
/** Initializes ascending iterator for entire range. */
Iter() {
- while ((next = findFirst()) != null) {
- Object x = next.value;
- if (x != null && x != next) {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- break;
- }
- }
+ advance(baseHead());
}
public final boolean hasNext() {
@@ -2289,54 +2094,58 @@
}
/** Advances next to higher entry. */
- final void advance() {
- if (next == null)
- throw new NoSuchElementException();
- lastReturned = next;
- while ((next = next.next) != null) {
- Object x = next.value;
- if (x != null && x != next) {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- break;
- }
+ final void advance(Node<K,V> b) {
+ Node<K,V> n = null;
+ V v = null;
+ if ((lastReturned = b) != null) {
+ while ((n = b.next) != null && (v = n.val) == null)
+ b = n;
}
+ nextValue = v;
+ next = n;
}
- public void remove() {
- Node<K,V> l = lastReturned;
- if (l == null)
+ public final void remove() {
+ Node<K,V> n; K k;
+ if ((n = lastReturned) == null || (k = n.key) == null)
throw new IllegalStateException();
// It would not be worth all of the overhead to directly
// unlink from here. Using remove is fast enough.
- ConcurrentSkipListMap.this.remove(l.key);
+ ConcurrentSkipListMap.this.remove(k);
lastReturned = null;
}
-
}
final class ValueIterator extends Iter<V> {
public V next() {
- V v = nextValue;
- advance();
+ V v;
+ if ((v = nextValue) == null)
+ throw new NoSuchElementException();
+ advance(next);
return v;
}
}
final class KeyIterator extends Iter<K> {
public K next() {
- Node<K,V> n = next;
- advance();
- return n.key;
+ Node<K,V> n;
+ if ((n = next) == null)
+ throw new NoSuchElementException();
+ K k = n.key;
+ advance(n);
+ return k;
}
}
final class EntryIterator extends Iter<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
- Node<K,V> n = next;
+ Node<K,V> n;
+ if ((n = next) == null)
+ throw new NoSuchElementException();
+ K k = n.key;
V v = nextValue;
- advance();
- return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+ advance(n);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
}
}
@@ -2393,9 +2202,7 @@
Collection<?> c = (Collection<?>) o;
try {
return containsAll(c) && c.containsAll(this);
- } catch (ClassCastException unused) {
- return false;
- } catch (NullPointerException unused) {
+ } catch (ClassCastException | NullPointerException unused) {
return false;
}
}
@@ -2520,9 +2327,7 @@
Collection<?> c = (Collection<?>) o;
try {
return containsAll(c) && c.containsAll(this);
- } catch (ClassCastException unused) {
- return false;
- } catch (NullPointerException unused) {
+ } catch (ClassCastException | NullPointerException unused) {
return false;
}
}
@@ -2564,7 +2369,7 @@
* @serial include
*/
static final class SubMap<K,V> extends AbstractMap<K,V>
- implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+ implements ConcurrentNavigableMap<K,V>, Serializable {
private static final long serialVersionUID = -7647078645895051609L;
/** Underlying map */
@@ -2582,8 +2387,8 @@
// Lazily initialized view holders
private transient KeySet<K,V> keySetView;
- private transient Set<Map.Entry<K,V>> entrySetView;
- private transient Collection<V> valuesView;
+ private transient Values<K,V> valuesView;
+ private transient EntrySet<K,V> entrySetView;
/**
* Creates a new submap, initializing all fields.
@@ -2642,9 +2447,7 @@
if (k == null) // pass by markers and headers
return true;
int c = cpr(cmp, k, hi);
- if (c > 0 || (c == 0 && !hiInclusive))
- return false;
- return true;
+ return c < 0 || (c == 0 && hiInclusive);
}
/**
@@ -2702,38 +2505,34 @@
Map.Entry<K,V> lowestEntry() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- if (!isBeforeEnd(n, cmp))
+ ConcurrentSkipListMap.Node<K,V> n; V v;
+ if ((n = loNode(cmp)) == null || !isBeforeEnd(n, cmp))
return null;
- Map.Entry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
+ else if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
Map.Entry<K,V> highestEntry() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
- if (n == null || !inBounds(n.key, cmp))
+ ConcurrentSkipListMap.Node<K,V> n; V v;
+ if ((n = hiNode(cmp)) == null || !inBounds(n.key, cmp))
return null;
- Map.Entry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
+ else if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
Map.Entry<K,V> removeLowest() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- Node<K,V> n = loNode(cmp);
- if (n == null)
+ ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+ if ((n = loNode(cmp)) == null)
return null;
- K k = n.key;
- if (!inBounds(k, cmp))
+ else if (!inBounds((k = n.key), cmp))
return null;
- V v = m.doRemove(k, null);
- if (v != null)
+ else if ((v = m.doRemove(k, null)) != null)
return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
}
}
@@ -2741,20 +2540,18 @@
Map.Entry<K,V> removeHighest() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- Node<K,V> n = hiNode(cmp);
- if (n == null)
+ ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+ if ((n = hiNode(cmp)) == null)
return null;
- K k = n.key;
- if (!inBounds(k, cmp))
+ else if (!inBounds((k = n.key), cmp))
return null;
- V v = m.doRemove(k, null);
- if (v != null)
+ else if ((v = m.doRemove(k, null)) != null)
return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
}
}
/**
- * Submap version of ConcurrentSkipListMap.getNearEntry.
+ * Submap version of ConcurrentSkipListMap.findNearEntry.
*/
Map.Entry<K,V> getNearEntry(K key, int rel) {
Comparator<? super K> cmp = m.comparator;
@@ -2768,15 +2565,12 @@
return ((rel & LT) != 0) ? null : lowestEntry();
if (tooHigh(key, cmp))
return ((rel & LT) != 0) ? highestEntry() : null;
- for (;;) {
- Node<K,V> n = m.findNear(key, rel, cmp);
- if (n == null || !inBounds(n.key, cmp))
- return null;
- K k = n.key;
- V v = n.getValidValue();
- if (v != null)
- return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
- }
+ AbstractMap.SimpleImmutableEntry<K,V> e =
+ m.findNearEntry(key, rel, cmp);
+ if (e == null || !inBounds(e.getKey(), cmp))
+ return null;
+ else
+ return e;
}
// Almost the same as getNearEntry, except for keys
@@ -2811,10 +2605,8 @@
Node<K,V> n = m.findNear(key, rel, cmp);
if (n == null || !inBounds(n.key, cmp))
return null;
- K k = n.key;
- V v = n.getValidValue();
- if (v != null)
- return k;
+ if (n.val != null)
+ return n.key;
}
}
@@ -2845,7 +2637,7 @@
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
isBeforeEnd(n, cmp);
n = n.next) {
- if (n.getValidValue() != null)
+ if (n.val != null)
++count;
}
return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
@@ -2863,7 +2655,7 @@
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
isBeforeEnd(n, cmp);
n = n.next) {
- V v = n.getValidValue();
+ V v = n.val;
if (v != null && value.equals(v))
return true;
}
@@ -2875,7 +2667,7 @@
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
isBeforeEnd(n, cmp);
n = n.next) {
- if (n.getValidValue() != null)
+ if (n.val != null)
m.remove(n.key);
}
}
@@ -3049,23 +2841,27 @@
/* ---------------- Submap Views -------------- */
public NavigableSet<K> keySet() {
- KeySet<K,V> ks = keySetView;
- return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+ KeySet<K,V> ks;
+ if ((ks = keySetView) != null) return ks;
+ return keySetView = new KeySet<>(this);
}
public NavigableSet<K> navigableKeySet() {
- KeySet<K,V> ks = keySetView;
- return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+ KeySet<K,V> ks;
+ if ((ks = keySetView) != null) return ks;
+ return keySetView = new KeySet<>(this);
}
public Collection<V> values() {
- Collection<V> vs = valuesView;
- return (vs != null) ? vs : (valuesView = new Values<>(this));
+ Values<K,V> vs;
+ if ((vs = valuesView) != null) return vs;
+ return valuesView = new Values<>(this);
}
public Set<Map.Entry<K,V>> entrySet() {
- Set<Map.Entry<K,V>> es = entrySetView;
- return (es != null) ? es : (entrySetView = new EntrySet<K,V>(this));
+ EntrySet<K,V> es;
+ if ((es = entrySetView) != null) return es;
+ return entrySetView = new EntrySet<K,V>(this);
}
public NavigableSet<K> descendingKeySet() {
@@ -3085,19 +2881,18 @@
V nextValue;
SubMapIter() {
+ VarHandle.acquireFence();
Comparator<? super K> cmp = m.comparator;
for (;;) {
next = isDescending ? hiNode(cmp) : loNode(cmp);
if (next == null)
break;
- Object x = next.value;
- if (x != null && x != next) {
+ V x = next.val;
+ if (x != null) {
if (! inBounds(next.key, cmp))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = x;
break;
}
}
@@ -3123,14 +2918,12 @@
next = next.next;
if (next == null)
break;
- Object x = next.value;
- if (x != null && x != next) {
+ V x = next.val;
+ if (x != null) {
if (tooHigh(next.key, cmp))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = x;
break;
}
}
@@ -3142,14 +2935,12 @@
next = m.findNear(lastReturned.key, LT, cmp);
if (next == null)
break;
- Object x = next.value;
- if (x != null && x != next) {
+ V x = next.val;
+ if (x != null) {
if (tooLow(next.key, cmp))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = x;
break;
}
}
@@ -3229,22 +3020,28 @@
public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null) throw new NullPointerException();
- V v;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- if ((v = n.getValidValue()) != null)
- action.accept(n.key, v);
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null)
+ action.accept(n.key, v);
+ b = n;
+ }
}
}
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
if (function == null) throw new NullPointerException();
- V v;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- while ((v = n.getValidValue()) != null) {
- V r = function.apply(n.key, v);
- if (r == null) throw new NullPointerException();
- if (n.casValue(v, r))
- break;
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ while ((v = n.val) != null) {
+ V r = function.apply(n.key, v);
+ if (r == null) throw new NullPointerException();
+ if (VAL.compareAndSet(n, v, r))
+ break;
+ }
+ b = n;
}
}
}
@@ -3255,13 +3052,16 @@
boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
if (function == null) throw new NullPointerException();
boolean removed = false;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v;
- if ((v = n.getValidValue()) != null) {
- K k = n.key;
- Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
- if (function.test(e) && remove(k, v))
- removed = true;
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null) {
+ K k = n.key;
+ Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+ if (function.test(e) && remove(k, v))
+ removed = true;
+ }
+ b = n;
}
}
return removed;
@@ -3273,12 +3073,12 @@
boolean removeValueIf(Predicate<? super V> function) {
if (function == null) throw new NullPointerException();
boolean removed = false;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v;
- if ((v = n.getValidValue()) != null) {
- K k = n.key;
- if (function.test(v) && remove(k, v))
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null && function.test(v) && remove(n.key, v))
removed = true;
+ b = n;
}
}
return removed;
@@ -3296,30 +3096,27 @@
* off, or the end of row is encountered. Control of the number of
* splits relies on some statistical estimation: The expected
* remaining number of elements of a skip list when advancing
- * either across or down decreases by about 25%. To make this
- * observation useful, we need to know initial size, which we
- * don't. But we can just use Integer.MAX_VALUE so that we
- * don't prematurely zero out while splitting.
+ * either across or down decreases by about 25%.
*/
abstract static class CSLMSpliterator<K,V> {
final Comparator<? super K> comparator;
final K fence; // exclusive upper bound for keys, or null if to end
Index<K,V> row; // the level to split out
Node<K,V> current; // current traversal node; initialize at origin
- int est; // pseudo-size estimate
+ long est; // size estimate
CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
this.comparator = comparator; this.row = row;
this.current = origin; this.fence = fence; this.est = est;
}
- public final long estimateSize() { return (long)est; }
+ public final long estimateSize() { return est; }
}
static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
implements Spliterator<K> {
KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
super(comparator, row, origin, fence, est);
}
@@ -3331,7 +3128,7 @@
for (Index<K,V> q = row; q != null; q = row = q.down) {
Index<K,V> s; Node<K,V> b, n; K sk;
if ((s = q.right) != null && (b = s.node) != null &&
- (n = b.next) != null && n.value != null &&
+ (n = b.next) != null && n.val != null &&
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
(f == null || cpr(cmp, sk, f) < 0)) {
current = n;
@@ -3352,10 +3149,10 @@
Node<K,V> e = current;
current = null;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
break;
- if ((v = e.value) != null && v != e)
+ if (e.val != null)
action.accept(k);
}
}
@@ -3366,12 +3163,12 @@
K f = fence;
Node<K,V> e = current;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
e = null;
break;
}
- if ((v = e.value) != null && v != e) {
+ if (e.val != null) {
current = e.next;
action.accept(k);
return true;
@@ -3393,21 +3190,23 @@
}
// factory method for KeySpliterator
final KeySpliterator<K,V> keySpliterator() {
- Comparator<? super K> cmp = comparator;
- for (;;) { // ensure h corresponds to origin p
- HeadIndex<K,V> h; Node<K,V> p;
- Node<K,V> b = (h = head).node;
- if ((p = b.next) == null || p.value != null)
- return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
- 0 : Integer.MAX_VALUE);
- p.helpDelete(b, p.next);
+ Index<K,V> h; Node<K,V> n; long est;
+ VarHandle.acquireFence();
+ if ((h = head) == null) {
+ n = null;
+ est = 0L;
}
+ else {
+ n = h.node;
+ est = getAdderCount();
+ }
+ return new KeySpliterator<K,V>(comparator, h, n, null, est);
}
static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
implements Spliterator<V> {
ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
super(comparator, row, origin, fence, est);
}
@@ -3419,7 +3218,7 @@
for (Index<K,V> q = row; q != null; q = row = q.down) {
Index<K,V> s; Node<K,V> b, n; K sk;
if ((s = q.right) != null && (b = s.node) != null &&
- (n = b.next) != null && n.value != null &&
+ (n = b.next) != null && n.val != null &&
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
(f == null || cpr(cmp, sk, f) < 0)) {
current = n;
@@ -3440,13 +3239,11 @@
Node<K,V> e = current;
current = null;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
break;
- if ((v = e.value) != null && v != e) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept(vv);
- }
+ if ((v = e.val) != null)
+ action.accept(v);
}
}
@@ -3456,15 +3253,14 @@
K f = fence;
Node<K,V> e = current;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
e = null;
break;
}
- if ((v = e.value) != null && v != e) {
+ if ((v = e.val) != null) {
current = e.next;
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept(vv);
+ action.accept(v);
return true;
}
}
@@ -3480,21 +3276,23 @@
// Almost the same as keySpliterator()
final ValueSpliterator<K,V> valueSpliterator() {
- Comparator<? super K> cmp = comparator;
- for (;;) {
- HeadIndex<K,V> h; Node<K,V> p;
- Node<K,V> b = (h = head).node;
- if ((p = b.next) == null || p.value != null)
- return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
- 0 : Integer.MAX_VALUE);
- p.helpDelete(b, p.next);
+ Index<K,V> h; Node<K,V> n; long est;
+ VarHandle.acquireFence();
+ if ((h = head) == null) {
+ n = null;
+ est = 0L;
}
+ else {
+ n = h.node;
+ est = getAdderCount();
+ }
+ return new ValueSpliterator<K,V>(comparator, h, n, null, est);
}
static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
super(comparator, row, origin, fence, est);
}
@@ -3506,7 +3304,7 @@
for (Index<K,V> q = row; q != null; q = row = q.down) {
Index<K,V> s; Node<K,V> b, n; K sk;
if ((s = q.right) != null && (b = s.node) != null &&
- (n = b.next) != null && n.value != null &&
+ (n = b.next) != null && n.val != null &&
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
(f == null || cpr(cmp, sk, f) < 0)) {
current = n;
@@ -3527,13 +3325,12 @@
Node<K,V> e = current;
current = null;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
break;
- if ((v = e.value) != null && v != e) {
- @SuppressWarnings("unchecked") V vv = (V)v;
+ if ((v = e.val) != null) {
action.accept
- (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+ (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
}
}
}
@@ -3544,16 +3341,15 @@
K f = fence;
Node<K,V> e = current;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
e = null;
break;
}
- if ((v = e.value) != null && v != e) {
+ if ((v = e.val) != null) {
current = e.next;
- @SuppressWarnings("unchecked") V vv = (V)v;
action.accept
- (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+ (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
return true;
}
}
@@ -3584,26 +3380,37 @@
// Almost the same as keySpliterator()
final EntrySpliterator<K,V> entrySpliterator() {
- Comparator<? super K> cmp = comparator;
- for (;;) { // almost same as key version
- HeadIndex<K,V> h; Node<K,V> p;
- Node<K,V> b = (h = head).node;
- if ((p = b.next) == null || p.value != null)
- return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
- 0 : Integer.MAX_VALUE);
- p.helpDelete(b, p.next);
+ Index<K,V> h; Node<K,V> n; long est;
+ VarHandle.acquireFence();
+ if ((h = head) == null) {
+ n = null;
+ est = 0L;
}
+ else {
+ n = h.node;
+ est = getAdderCount();
+ }
+ return new EntrySpliterator<K,V>(comparator, h, n, null, est);
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle ADDER;
+ private static final VarHandle NEXT;
+ private static final VarHandle VAL;
+ private static final VarHandle RIGHT;
static {
try {
- HEAD = U.objectFieldOffset
- (ConcurrentSkipListMap.class.getDeclaredField("head"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
+ Index.class);
+ ADDER = l.findVarHandle(ConcurrentSkipListMap.class, "adder",
+ LongAdder.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ VAL = l.findVarHandle(Node.class, "val", Object.class);
+ RIGHT = l.findVarHandle(Index.class, "right", Index.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
index 2e11b17..140bde4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/ojluni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -35,23 +35,18 @@
package java.util.concurrent;
+import java.lang.reflect.Field;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
-import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.Spliterator;
-// BEGIN android-note
-// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
/**
* A scalable concurrent {@link NavigableSet} implementation based on
* a {@link ConcurrentSkipListMap}. The elements of the set are kept
@@ -75,12 +70,12 @@
* asynchronous nature of these sets, determining the current number
* of elements requires a traversal of the elements, and so may report
* inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
*
* <p>This class and its iterators implement all of the
* <em>optional</em> methods of the {@link Set} and {@link Iterator}
@@ -89,6 +84,10 @@
* because {@code null} arguments and return values cannot be reliably
* distinguished from the absence of elements.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @author Doug Lea
* @param <E> the type of elements maintained by this set
* @since 1.6
@@ -310,9 +309,7 @@
Collection<?> c = (Collection<?>) o;
try {
return containsAll(c) && c.containsAll(this);
- } catch (ClassCastException unused) {
- return false;
- } catch (NullPointerException unused) {
+ } catch (ClassCastException | NullPointerException unused) {
return false;
}
}
@@ -327,7 +324,7 @@
* @return {@code true} if this set changed as a result of the call
* @throws ClassCastException if the class of an element of this set
* is incompatible with the specified collection
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
@@ -491,9 +488,9 @@
* encounter order that is ascending order. Overriding implementations
* should document the reporting of additional characteristic values.
*
- * <p>The spliterator's comparator (see
- * {@link java.util.Spliterator#getComparator()}) is {@code null} if
- * the set's comparator (see {@link #comparator()}) is {@code null}.
+ * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
+ * is {@code null} if the {@linkplain #comparator() set's comparator}
+ * is {@code null}.
* Otherwise, the spliterator's comparator is the same as or imposes the
* same total ordering as the set's comparator.
*
@@ -506,18 +503,21 @@
: ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
}
- // Support for resetting map in clone
+ /** Initializes map field; for use in clone. */
private void setMap(ConcurrentNavigableMap<E,Object> map) {
- U.putObjectVolatile(this, MAP, map);
- }
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long MAP;
- static {
+ Field mapField = java.security.AccessController.doPrivileged(
+ (java.security.PrivilegedAction<Field>) () -> {
+ try {
+ Field f = ConcurrentSkipListSet.class
+ .getDeclaredField("m");
+ f.setAccessible(true);
+ return f;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }});
try {
- MAP = U.objectFieldOffset
- (ConcurrentSkipListSet.class.getDeclaredField("m"));
- } catch (ReflectiveOperationException e) {
+ mapField.set(this, map);
+ } catch (IllegalAccessException e) {
throw new Error(e);
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
index ebcbbef..912204f 100644
--- a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
@@ -34,7 +34,8 @@
package java.util.concurrent;
-import java.util.AbstractList;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
@@ -50,6 +51,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.misc.SharedSecrets;
// Android-changed: Removed javadoc link to collections framework docs
/**
@@ -81,6 +83,10 @@
* actions subsequent to the access or removal of that element from
* the {@code CopyOnWriteArrayList} in another thread.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.5
* @author Doug Lea
* @param <E> the type of elements held in this list
@@ -129,17 +135,17 @@
* @throws NullPointerException if the specified collection is null
*/
public CopyOnWriteArrayList(Collection<? extends E> c) {
- Object[] elements;
+ Object[] es;
if (c.getClass() == CopyOnWriteArrayList.class)
- elements = ((CopyOnWriteArrayList<?>)c).getArray();
+ es = ((CopyOnWriteArrayList<?>)c).getArray();
else {
- elements = c.toArray();
+ es = c.toArray();
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
- if (elements.getClass() != Object[].class)
- elements = Arrays.copyOf(elements, elements.length, Object[].class);
+ if (es.getClass() != Object[].class)
+ es = Arrays.copyOf(es, es.length, Object[].class);
}
- setArray(elements);
+ setArray(es);
}
/**
@@ -175,20 +181,19 @@
* static version of indexOf, to allow repeated calls without
* needing to re-acquire array each time.
* @param o element to search for
- * @param elements the array
- * @param index first index to search
- * @param fence one past last index to search
+ * @param es the array
+ * @param from first index to search
+ * @param to one past last index to search
* @return index of element, or -1 if absent
*/
- private static int indexOf(Object o, Object[] elements,
- int index, int fence) {
+ private static int indexOfRange(Object o, Object[] es, int from, int to) {
if (o == null) {
- for (int i = index; i < fence; i++)
- if (elements[i] == null)
+ for (int i = from; i < to; i++)
+ if (es[i] == null)
return i;
} else {
- for (int i = index; i < fence; i++)
- if (o.equals(elements[i]))
+ for (int i = from; i < to; i++)
+ if (o.equals(es[i]))
return i;
}
return -1;
@@ -197,18 +202,19 @@
/**
* static version of lastIndexOf.
* @param o element to search for
- * @param elements the array
- * @param index first index to search
+ * @param es the array
+ * @param from index of first element of range, last element to search
+ * @param to one past last element of range, first element to search
* @return index of element, or -1 if absent
*/
- private static int lastIndexOf(Object o, Object[] elements, int index) {
+ private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
if (o == null) {
- for (int i = index; i >= 0; i--)
- if (elements[i] == null)
+ for (int i = to - 1; i >= from; i--)
+ if (es[i] == null)
return i;
} else {
- for (int i = index; i >= 0; i--)
- if (o.equals(elements[i]))
+ for (int i = to - 1; i >= from; i--)
+ if (o.equals(es[i]))
return i;
}
return -1;
@@ -223,16 +229,15 @@
* @return {@code true} if this list contains the specified element
*/
public boolean contains(Object o) {
- Object[] elements = getArray();
- return indexOf(o, elements, 0, elements.length) >= 0;
+ return indexOf(o) >= 0;
}
/**
* {@inheritDoc}
*/
public int indexOf(Object o) {
- Object[] elements = getArray();
- return indexOf(o, elements, 0, elements.length);
+ Object[] es = getArray();
+ return indexOfRange(o, es, 0, es.length);
}
/**
@@ -251,16 +256,16 @@
* @throws IndexOutOfBoundsException if the specified index is negative
*/
public int indexOf(E e, int index) {
- Object[] elements = getArray();
- return indexOf(e, elements, index, elements.length);
+ Object[] es = getArray();
+ return indexOfRange(e, es, index, es.length);
}
/**
* {@inheritDoc}
*/
public int lastIndexOf(Object o) {
- Object[] elements = getArray();
- return lastIndexOf(o, elements, elements.length - 1);
+ Object[] es = getArray();
+ return lastIndexOfRange(o, es, 0, es.length);
}
/**
@@ -280,8 +285,8 @@
* than or equal to the current size of this list
*/
public int lastIndexOf(E e, int index) {
- Object[] elements = getArray();
- return lastIndexOf(e, elements, index);
+ Object[] es = getArray();
+ return lastIndexOfRange(e, es, 0, index + 1);
}
/**
@@ -296,6 +301,9 @@
CopyOnWriteArrayList<E> clone =
(CopyOnWriteArrayList<E>) super.clone();
clone.resetLock();
+ // Unlike in readObject, here we cannot visibility-piggyback on the
+ // volatile write in setArray().
+ VarHandle.releaseFence();
return clone;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
@@ -317,8 +325,7 @@
* @return an array containing all the elements in this list
*/
public Object[] toArray() {
- Object[] elements = getArray();
- return Arrays.copyOf(elements, elements.length);
+ return getArray().clone();
}
/**
@@ -361,12 +368,12 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (a.length < len)
- return (T[]) Arrays.copyOf(elements, len, a.getClass());
+ return (T[]) Arrays.copyOf(es, len, a.getClass());
else {
- System.arraycopy(elements, 0, a, 0, len);
+ System.arraycopy(es, 0, a, 0, len);
if (a.length > len)
a[len] = null;
return a;
@@ -376,7 +383,7 @@
// Positional Access Operations
@SuppressWarnings("unchecked")
- private E get(Object[] a, int index) {
+ static <E> E elementAt(Object[] a, int index) {
return (E) a[index];
}
@@ -390,7 +397,7 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
- return get(getArray(), index);
+ return elementAt(getArray(), index);
}
/**
@@ -401,17 +408,13 @@
*/
public E set(int index, E element) {
synchronized (lock) {
- Object[] elements = getArray();
- E oldValue = get(elements, index);
+ Object[] es = getArray();
+ E oldValue = elementAt(es, index);
if (oldValue != element) {
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len);
- newElements[index] = element;
- setArray(newElements);
- } else {
- // Not quite a no-op; ensures volatile write semantics
- setArray(elements);
+ es = es.clone();
+ es[index] = element;
+ setArray(es);
}
return oldValue;
}
@@ -425,11 +428,11 @@
*/
public boolean add(E e) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len + 1);
- newElements[len] = e;
- setArray(newElements);
+ Object[] es = getArray();
+ int len = es.length;
+ es = Arrays.copyOf(es, len + 1);
+ es[len] = e;
+ setArray(es);
return true;
}
}
@@ -443,18 +446,18 @@
*/
public void add(int index, E element) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
- newElements = Arrays.copyOf(elements, len + 1);
+ newElements = Arrays.copyOf(es, len + 1);
else {
newElements = new Object[len + 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index, newElements, index + 1,
+ System.arraycopy(es, 0, newElements, 0, index);
+ System.arraycopy(es, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
@@ -471,19 +474,20 @@
*/
public E remove(int index) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- E oldValue = get(elements, index);
+ Object[] es = getArray();
+ int len = es.length;
+ E oldValue = elementAt(es, index);
int numMoved = len - index - 1;
+ Object[] newElements;
if (numMoved == 0)
- setArray(Arrays.copyOf(elements, len - 1));
+ newElements = Arrays.copyOf(es, len - 1);
else {
- Object[] newElements = new Object[len - 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index + 1, newElements, index,
+ newElements = new Object[len - 1];
+ System.arraycopy(es, 0, newElements, 0, index);
+ System.arraycopy(es, index + 1, newElements, index,
numMoved);
- setArray(newElements);
}
+ setArray(newElements);
return oldValue;
}
}
@@ -502,8 +506,8 @@
*/
public boolean remove(Object o) {
Object[] snapshot = getArray();
- int index = indexOf(o, snapshot, 0, snapshot.length);
- return (index < 0) ? false : remove(o, snapshot, index);
+ int index = indexOfRange(o, snapshot, 0, snapshot.length);
+ return index >= 0 && remove(o, snapshot, index);
}
/**
@@ -527,7 +531,7 @@
return false;
if (current[index] == o)
break findIndex;
- index = indexOf(o, current, index, len);
+ index = indexOfRange(o, current, index, len);
if (index < 0)
return false;
}
@@ -555,19 +559,19 @@
*/
void removeRange(int fromIndex, int toIndex) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
throw new IndexOutOfBoundsException();
int newlen = len - (toIndex - fromIndex);
int numMoved = len - toIndex;
if (numMoved == 0)
- setArray(Arrays.copyOf(elements, newlen));
+ setArray(Arrays.copyOf(es, newlen));
else {
Object[] newElements = new Object[newlen];
- System.arraycopy(elements, 0, newElements, 0, fromIndex);
- System.arraycopy(elements, toIndex, newElements,
+ System.arraycopy(es, 0, newElements, 0, fromIndex);
+ System.arraycopy(es, toIndex, newElements,
fromIndex, numMoved);
setArray(newElements);
}
@@ -582,8 +586,8 @@
*/
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();
- return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
- addIfAbsent(e, snapshot);
+ return indexOfRange(e, snapshot, 0, snapshot.length) < 0
+ && addIfAbsent(e, snapshot);
}
/**
@@ -601,7 +605,7 @@
if (current[i] != snapshot[i]
&& Objects.equals(e, current[i]))
return false;
- if (indexOf(e, current, common, len) >= 0)
+ if (indexOfRange(e, current, common, len) >= 0)
return false;
}
Object[] newElements = Arrays.copyOf(current, len + 1);
@@ -622,10 +626,10 @@
* @see #contains(Object)
*/
public boolean containsAll(Collection<?> c) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
for (Object e : c) {
- if (indexOf(e, elements, 0, len) < 0)
+ if (indexOfRange(e, es, 0, len) < 0)
return false;
}
return true;
@@ -640,34 +644,16 @@
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
public boolean removeAll(Collection<?> c) {
- if (c == null) throw new NullPointerException();
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (len != 0) {
- // temp array holds those elements we know we want to keep
- int newlen = 0;
- Object[] temp = new Object[len];
- for (int i = 0; i < len; ++i) {
- Object element = elements[i];
- if (!c.contains(element))
- temp[newlen++] = element;
- }
- if (newlen != len) {
- setArray(Arrays.copyOf(temp, newlen));
- return true;
- }
- }
- return false;
- }
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> c.contains(e));
}
/**
@@ -679,34 +665,16 @@
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
- * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
- * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
public boolean retainAll(Collection<?> c) {
- if (c == null) throw new NullPointerException();
- synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (len != 0) {
- // temp array holds those elements we know we want to keep
- int newlen = 0;
- Object[] temp = new Object[len];
- for (int i = 0; i < len; ++i) {
- Object element = elements[i];
- if (c.contains(element))
- temp[newlen++] = element;
- }
- if (newlen != len) {
- setArray(Arrays.copyOf(temp, newlen));
- return true;
- }
- }
- return false;
- }
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> !c.contains(e));
}
/**
@@ -725,18 +693,18 @@
if (cs.length == 0)
return 0;
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
int added = 0;
// uniquify and compact elements in cs
for (int i = 0; i < cs.length; ++i) {
Object e = cs[i];
- if (indexOf(e, elements, 0, len) < 0 &&
- indexOf(e, cs, 0, added) < 0)
+ if (indexOfRange(e, es, 0, len) < 0 &&
+ indexOfRange(e, cs, 0, added) < 0)
cs[added++] = e;
}
if (added > 0) {
- Object[] newElements = Arrays.copyOf(elements, len + added);
+ Object[] newElements = Arrays.copyOf(es, len + added);
System.arraycopy(cs, 0, newElements, len, added);
setArray(newElements);
}
@@ -770,15 +738,16 @@
if (cs.length == 0)
return false;
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
+ Object[] newElements;
if (len == 0 && cs.getClass() == Object[].class)
- setArray(cs);
+ newElements = cs;
else {
- Object[] newElements = Arrays.copyOf(elements, len + cs.length);
+ newElements = Arrays.copyOf(es, len + cs.length);
System.arraycopy(cs, 0, newElements, len, cs.length);
- setArray(newElements);
}
+ setArray(newElements);
return true;
}
}
@@ -802,8 +771,8 @@
public boolean addAll(int index, Collection<? extends E> c) {
Object[] cs = c.toArray();
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
if (cs.length == 0)
@@ -811,11 +780,11 @@
int numMoved = len - index;
Object[] newElements;
if (numMoved == 0)
- newElements = Arrays.copyOf(elements, len + cs.length);
+ newElements = Arrays.copyOf(es, len + cs.length);
else {
newElements = new Object[len + cs.length];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index,
+ System.arraycopy(es, 0, newElements, 0, index);
+ System.arraycopy(es, index,
newElements, index + cs.length,
numMoved);
}
@@ -825,65 +794,106 @@
}
}
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
public void forEach(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
+ Objects.requireNonNull(action);
for (Object x : getArray()) {
@SuppressWarnings("unchecked") E e = (E) x;
action.accept(e);
}
}
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
public boolean removeIf(Predicate<? super E> filter) {
- if (filter == null) throw new NullPointerException();
+ 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 boolean bulkRemove(Predicate<? super E> filter) {
synchronized (lock) {
- final Object[] elements = getArray();
- final int len = elements.length;
- int i;
- for (i = 0; i < len; i++) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- if (filter.test(e)) {
- int newlen = i;
- final Object[] newElements = new Object[len - 1];
- System.arraycopy(elements, 0, newElements, 0, newlen);
- for (i++; i < len; i++) {
- @SuppressWarnings("unchecked") E x = (E) elements[i];
- if (!filter.test(x))
- newElements[newlen++] = x;
- }
- setArray((newlen == len - 1)
- ? newElements // one match => one copy
- : Arrays.copyOf(newElements, newlen));
- return true;
+ return bulkRemove(filter, 0, getArray().length);
+ }
+ }
+
+ boolean bulkRemove(Predicate<? super E> filter, int i, int end) {
+ // assert Thread.holdsLock(lock);
+ final Object[] es = getArray();
+ // Optimize for initial run of survivors
+ for (; i < end && !filter.test(elementAt(es, i)); i++)
+ ;
+ if (i < end) {
+ final int beg = i;
+ final long[] deathRow = nBits(end - beg);
+ int deleted = 1;
+ deathRow[0] = 1L; // set bit 0
+ for (i = beg + 1; i < end; i++)
+ if (filter.test(elementAt(es, i))) {
+ setBit(deathRow, i - beg);
+ deleted++;
}
- }
- return false; // zero matches => zero copies
+ // Did filter reentrantly modify the list?
+ if (es != getArray())
+ throw new ConcurrentModificationException();
+ final Object[] newElts = Arrays.copyOf(es, es.length - deleted);
+ int w = beg;
+ for (i = beg; i < end; i++)
+ if (isClear(deathRow, i - beg))
+ newElts[w++] = es[i];
+ System.arraycopy(es, i, newElts, w, es.length - i);
+ setArray(newElts);
+ return true;
+ } else {
+ if (es != getArray())
+ throw new ConcurrentModificationException();
+ return false;
}
}
public void replaceAll(UnaryOperator<E> operator) {
- if (operator == null) throw new NullPointerException();
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len);
- for (int i = 0; i < len; ++i) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- newElements[i] = operator.apply(e);
- }
- setArray(newElements);
+ replaceAllRange(operator, 0, getArray().length);
}
}
+ void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
+ // assert Thread.holdsLock(lock);
+ Objects.requireNonNull(operator);
+ final Object[] es = getArray().clone();
+ for (; i < end; i++)
+ es[i] = operator.apply(elementAt(es, i));
+ setArray(es);
+ }
+
public void sort(Comparator<? super E> c) {
synchronized (lock) {
- Object[] elements = getArray();
- Object[] newElements = Arrays.copyOf(elements, elements.length);
- @SuppressWarnings("unchecked") E[] es = (E[])newElements;
- Arrays.sort(es, c);
- setArray(newElements);
+ sortRange(c, 0, getArray().length);
}
}
+ @SuppressWarnings("unchecked")
+ void sortRange(Comparator<? super E> c, int i, int end) {
+ // assert Thread.holdsLock(lock);
+ final Object[] es = getArray().clone();
+ Arrays.sort(es, i, end, (Comparator<Object>)c);
+ setArray(es);
+ }
+
/**
* Saves this list to a stream (that is, serializes it).
*
@@ -898,12 +908,12 @@
s.defaultWriteObject();
- Object[] elements = getArray();
+ Object[] es = getArray();
// Write out array length
- s.writeInt(elements.length);
+ s.writeInt(es.length);
// Write out all elements in the proper order.
- for (Object element : elements)
+ for (Object element : es)
s.writeObject(element);
}
@@ -924,12 +934,13 @@
// Read in array length and allocate array
int len = s.readInt();
- Object[] elements = new Object[len];
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
+ Object[] es = new Object[len];
// Read in all elements in the proper order.
for (int i = 0; i < len; i++)
- elements[i] = s.readObject();
- setArray(elements);
+ es[i] = s.readObject();
+ setArray(es);
}
/**
@@ -969,13 +980,19 @@
List<?> list = (List<?>)o;
Iterator<?> it = list.iterator();
- Object[] elements = getArray();
- for (int i = 0, len = elements.length; i < len; i++)
- if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
+ for (Object element : getArray())
+ if (!it.hasNext() || !Objects.equals(element, it.next()))
return false;
- if (it.hasNext())
- return false;
- return true;
+ return !it.hasNext();
+ }
+
+ private static int hashCodeOfRange(Object[] es, int from, int to) {
+ int hashCode = 1;
+ for (int i = from; i < to; i++) {
+ Object x = es[i];
+ hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+ }
+ return hashCode;
}
/**
@@ -986,10 +1003,8 @@
* @return the hash code value for this list
*/
public int hashCode() {
- int hashCode = 1;
- for (Object x : getArray())
- hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
- return hashCode;
+ Object[] es = getArray();
+ return hashCodeOfRange(es, 0, es.length);
}
/**
@@ -1029,12 +1044,12 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public ListIterator<E> listIterator(int index) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (index < 0 || index > len)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
- return new COWIterator<E>(elements, index);
+ return new COWIterator<E>(es, index);
}
/**
@@ -1062,9 +1077,9 @@
/** Index of element to be returned by subsequent call to next. */
private int cursor;
- COWIterator(Object[] elements, int initialCursor) {
+ COWIterator(Object[] es, int initialCursor) {
cursor = initialCursor;
- snapshot = elements;
+ snapshot = es;
}
public boolean hasNext() {
@@ -1094,7 +1109,7 @@
}
public int previousIndex() {
- return cursor-1;
+ return cursor - 1;
}
/**
@@ -1125,14 +1140,13 @@
}
@Override
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int size = snapshot.length;
- for (int i = cursor; i < size; i++) {
- action.accept((E) snapshot[i]);
- }
+ int i = cursor;
cursor = size;
+ for (; i < size; i++)
+ action.accept(elementAt(snapshot, i));
}
}
@@ -1153,324 +1167,358 @@
*/
public List<E> subList(int fromIndex, int toIndex) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
+ Object[] es = getArray();
+ int len = es.length;
+ int size = toIndex - fromIndex;
+ if (fromIndex < 0 || toIndex > len || size < 0)
throw new IndexOutOfBoundsException();
- return new COWSubList<E>(this, fromIndex, toIndex);
+ return new COWSubList(es, fromIndex, size);
}
}
/**
* Sublist for CopyOnWriteArrayList.
- * This class extends AbstractList merely for convenience, to
- * avoid having to define addAll, etc. This doesn't hurt, but
- * is wasteful. This class does not need or use modCount
- * mechanics in AbstractList, but does need to check for
- * concurrent modification using similar mechanics. On each
- * operation, the array that we expect the backing list to use
- * is checked and updated. Since we do this for all of the
- * base operations invoked by those defined in AbstractList,
- * all is well. While inefficient, this is not worth
- * improving. The kinds of list operations inherited from
- * AbstractList are already so slow on COW sublists that
- * adding a bit more space/time doesn't seem even noticeable.
*/
- private static class COWSubList<E>
- extends AbstractList<E>
- implements RandomAccess
- {
- private final CopyOnWriteArrayList<E> l;
+ private class COWSubList implements List<E>, RandomAccess {
private final int offset;
private int size;
private Object[] expectedArray;
- // only call this holding l's lock
- COWSubList(CopyOnWriteArrayList<E> list,
- int fromIndex, int toIndex) {
- // assert Thread.holdsLock(list.lock);
- l = list;
- expectedArray = l.getArray();
- offset = fromIndex;
- size = toIndex - fromIndex;
+ COWSubList(Object[] es, int offset, int size) {
+ // assert Thread.holdsLock(lock);
+ expectedArray = es;
+ this.offset = offset;
+ this.size = size;
}
- // only call this holding l's lock
private void checkForComodification() {
- // assert Thread.holdsLock(l.lock);
- if (l.getArray() != expectedArray)
+ // assert Thread.holdsLock(lock);
+ if (getArray() != expectedArray)
throw new ConcurrentModificationException();
}
- // only call this holding l's lock
+ private Object[] getArrayChecked() {
+ // assert Thread.holdsLock(lock);
+ Object[] a = getArray();
+ if (a != expectedArray)
+ throw new ConcurrentModificationException();
+ return a;
+ }
+
private void rangeCheck(int index) {
- // assert Thread.holdsLock(l.lock);
+ // assert Thread.holdsLock(lock);
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBounds(index, size));
}
+ private void rangeCheckForAdd(int index) {
+ // assert Thread.holdsLock(lock);
+ if (index < 0 || index > size)
+ throw new IndexOutOfBoundsException(outOfBounds(index, size));
+ }
+
+ public Object[] toArray() {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ return Arrays.copyOfRange(es, offset, offset + size);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ if (a.length < size)
+ return (T[]) Arrays.copyOfRange(
+ es, offset, offset + size, a.getClass());
+ else {
+ System.arraycopy(es, offset, a, 0, size);
+ if (a.length > size)
+ a[size] = null;
+ return a;
+ }
+ }
+
+ public int indexOf(Object o) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ int i = indexOfRange(o, es, offset, offset + size);
+ return (i == -1) ? -1 : i - offset;
+ }
+
+ public int lastIndexOf(Object o) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ int i = lastIndexOfRange(o, es, offset, offset + size);
+ return (i == -1) ? -1 : i - offset;
+ }
+
+ public boolean contains(Object o) {
+ return indexOf(o) >= 0;
+ }
+
+ public boolean containsAll(Collection<?> c) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ for (Object o : c)
+ if (indexOfRange(o, es, offset, offset + size) < 0)
+ return false;
+ return true;
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ public String toString() {
+ return Arrays.toString(toArray());
+ }
+
+ public int hashCode() {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ return hashCodeOfRange(es, offset, offset + size);
+ }
+
+ public boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof List))
+ return false;
+ Iterator<?> it = ((List<?>)o).iterator();
+
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+
+ for (int i = offset, end = offset + size; i < end; i++)
+ if (!it.hasNext() || !Objects.equals(es[i], it.next()))
+ return false;
+ return !it.hasNext();
+ }
+
public E set(int index, E element) {
- synchronized (l.lock) {
+ synchronized (lock) {
rangeCheck(index);
checkForComodification();
- E x = l.set(index+offset, element);
- expectedArray = l.getArray();
+ E x = CopyOnWriteArrayList.this.set(offset + index, element);
+ expectedArray = getArray();
return x;
}
}
public E get(int index) {
- synchronized (l.lock) {
+ synchronized (lock) {
rangeCheck(index);
checkForComodification();
- return l.get(index+offset);
+ return CopyOnWriteArrayList.this.get(offset + index);
}
}
public int size() {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
return size;
}
}
- public void add(int index, E element) {
- synchronized (l.lock) {
+ public boolean add(E element) {
+ synchronized (lock) {
checkForComodification();
- if (index < 0 || index > size)
- throw new IndexOutOfBoundsException
- (outOfBounds(index, size));
- l.add(index+offset, element);
- expectedArray = l.getArray();
+ CopyOnWriteArrayList.this.add(offset + size, element);
+ expectedArray = getArray();
+ size++;
+ }
+ return true;
+ }
+
+ public void add(int index, E element) {
+ synchronized (lock) {
+ checkForComodification();
+ rangeCheckForAdd(index);
+ CopyOnWriteArrayList.this.add(offset + index, element);
+ expectedArray = getArray();
size++;
}
}
+ public boolean addAll(Collection<? extends E> c) {
+ synchronized (lock) {
+ final Object[] oldArray = getArrayChecked();
+ boolean modified =
+ CopyOnWriteArrayList.this.addAll(offset + size, c);
+ size += (expectedArray = getArray()).length - oldArray.length;
+ return modified;
+ }
+ }
+
+ public boolean addAll(int index, Collection<? extends E> c) {
+ synchronized (lock) {
+ rangeCheckForAdd(index);
+ final Object[] oldArray = getArrayChecked();
+ boolean modified =
+ CopyOnWriteArrayList.this.addAll(offset + index, c);
+ size += (expectedArray = getArray()).length - oldArray.length;
+ return modified;
+ }
+ }
+
public void clear() {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- l.removeRange(offset, offset+size);
- expectedArray = l.getArray();
+ removeRange(offset, offset + size);
+ expectedArray = getArray();
size = 0;
}
}
public E remove(int index) {
- synchronized (l.lock) {
+ synchronized (lock) {
rangeCheck(index);
checkForComodification();
- E result = l.remove(index+offset);
- expectedArray = l.getArray();
+ E result = CopyOnWriteArrayList.this.remove(offset + index);
+ expectedArray = getArray();
size--;
return result;
}
}
public boolean remove(Object o) {
- int index = indexOf(o);
- if (index == -1)
- return false;
- remove(index);
- return true;
- }
-
- public Iterator<E> iterator() {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- return new COWSubListIterator<E>(l, 0, offset, size);
+ int index = indexOf(o);
+ if (index == -1)
+ return false;
+ remove(index);
+ return true;
}
}
+ public Iterator<E> iterator() {
+ return listIterator(0);
+ }
+
+ public ListIterator<E> listIterator() {
+ return listIterator(0);
+ }
+
public ListIterator<E> listIterator(int index) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- if (index < 0 || index > size)
- throw new IndexOutOfBoundsException
- (outOfBounds(index, size));
- return new COWSubListIterator<E>(l, index, offset, size);
+ rangeCheckForAdd(index);
+ return new COWSubListIterator<E>(
+ CopyOnWriteArrayList.this, index, offset, size);
}
}
public List<E> subList(int fromIndex, int toIndex) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
throw new IndexOutOfBoundsException();
- return new COWSubList<E>(l, fromIndex + offset,
- toIndex + offset);
+ return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
}
}
public void forEach(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
- int lo = offset;
- int hi = offset + size;
- Object[] a = expectedArray;
- if (l.getArray() != a)
- throw new ConcurrentModificationException();
- if (lo < 0 || hi > a.length)
- throw new IndexOutOfBoundsException();
- for (int i = lo; i < hi; ++i) {
- @SuppressWarnings("unchecked") E e = (E) a[i];
- action.accept(e);
+ Objects.requireNonNull(action);
+ int i, end; final Object[] es;
+ synchronized (lock) {
+ es = getArrayChecked();
+ i = offset;
+ end = i + size;
}
+ for (; i < end; i++)
+ action.accept(elementAt(es, i));
}
public void replaceAll(UnaryOperator<E> operator) {
- if (operator == null) throw new NullPointerException();
- synchronized (l.lock) {
- int lo = offset;
- int hi = offset + size;
- Object[] elements = expectedArray;
- if (l.getArray() != elements)
- throw new ConcurrentModificationException();
- int len = elements.length;
- if (lo < 0 || hi > len)
- throw new IndexOutOfBoundsException();
- Object[] newElements = Arrays.copyOf(elements, len);
- for (int i = lo; i < hi; ++i) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- newElements[i] = operator.apply(e);
- }
- l.setArray(expectedArray = newElements);
+ synchronized (lock) {
+ checkForComodification();
+ replaceAllRange(operator, offset, offset + size);
+ expectedArray = getArray();
}
}
public void sort(Comparator<? super E> c) {
- synchronized (l.lock) {
- int lo = offset;
- int hi = offset + size;
- Object[] elements = expectedArray;
- if (l.getArray() != elements)
- throw new ConcurrentModificationException();
- int len = elements.length;
- if (lo < 0 || hi > len)
- throw new IndexOutOfBoundsException();
- Object[] newElements = Arrays.copyOf(elements, len);
- @SuppressWarnings("unchecked") E[] es = (E[])newElements;
- Arrays.sort(es, lo, hi, c);
- l.setArray(expectedArray = newElements);
+ synchronized (lock) {
+ checkForComodification();
+ sortRange(c, offset, offset + size);
+ expectedArray = getArray();
}
}
public boolean removeAll(Collection<?> c) {
- if (c == null) throw new NullPointerException();
- boolean removed = false;
- synchronized (l.lock) {
- int n = size;
- if (n > 0) {
- int lo = offset;
- int hi = offset + n;
- Object[] elements = expectedArray;
- if (l.getArray() != elements)
- throw new ConcurrentModificationException();
- int len = elements.length;
- if (lo < 0 || hi > len)
- throw new IndexOutOfBoundsException();
- int newSize = 0;
- Object[] temp = new Object[n];
- for (int i = lo; i < hi; ++i) {
- Object element = elements[i];
- if (!c.contains(element))
- temp[newSize++] = element;
- }
- if (newSize != n) {
- Object[] newElements = new Object[len - n + newSize];
- System.arraycopy(elements, 0, newElements, 0, lo);
- System.arraycopy(temp, 0, newElements, lo, newSize);
- System.arraycopy(elements, hi, newElements,
- lo + newSize, len - hi);
- size = newSize;
- removed = true;
- l.setArray(expectedArray = newElements);
- }
- }
- }
- return removed;
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> c.contains(e));
}
public boolean retainAll(Collection<?> c) {
- if (c == null) throw new NullPointerException();
- boolean removed = false;
- synchronized (l.lock) {
- int n = size;
- if (n > 0) {
- int lo = offset;
- int hi = offset + n;
- Object[] elements = expectedArray;
- if (l.getArray() != elements)
- throw new ConcurrentModificationException();
- int len = elements.length;
- if (lo < 0 || hi > len)
- throw new IndexOutOfBoundsException();
- int newSize = 0;
- Object[] temp = new Object[n];
- for (int i = lo; i < hi; ++i) {
- Object element = elements[i];
- if (c.contains(element))
- temp[newSize++] = element;
- }
- if (newSize != n) {
- Object[] newElements = new Object[len - n + newSize];
- System.arraycopy(elements, 0, newElements, 0, lo);
- System.arraycopy(temp, 0, newElements, lo, newSize);
- System.arraycopy(elements, hi, newElements,
- lo + newSize, len - hi);
- size = newSize;
- removed = true;
- l.setArray(expectedArray = newElements);
- }
- }
- }
- return removed;
+ Objects.requireNonNull(c);
+ return bulkRemove(e -> !c.contains(e));
}
public boolean removeIf(Predicate<? super E> filter) {
- if (filter == null) throw new NullPointerException();
- boolean removed = false;
- synchronized (l.lock) {
- int n = size;
- if (n > 0) {
- int lo = offset;
- int hi = offset + n;
- Object[] elements = expectedArray;
- if (l.getArray() != elements)
- throw new ConcurrentModificationException();
- int len = elements.length;
- if (lo < 0 || hi > len)
- throw new IndexOutOfBoundsException();
- int newSize = 0;
- Object[] temp = new Object[n];
- for (int i = lo; i < hi; ++i) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- if (!filter.test(e))
- temp[newSize++] = e;
- }
- if (newSize != n) {
- Object[] newElements = new Object[len - n + newSize];
- System.arraycopy(elements, 0, newElements, 0, lo);
- System.arraycopy(temp, 0, newElements, lo, newSize);
- System.arraycopy(elements, hi, newElements,
- lo + newSize, len - hi);
- size = newSize;
- removed = true;
- l.setArray(expectedArray = newElements);
- }
- }
+ Objects.requireNonNull(filter);
+ return bulkRemove(filter);
+ }
+
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ synchronized (lock) {
+ final Object[] oldArray = getArrayChecked();
+ boolean modified = CopyOnWriteArrayList.this.bulkRemove(
+ filter, offset, offset + size);
+ size += (expectedArray = getArray()).length - oldArray.length;
+ return modified;
}
- return removed;
}
public Spliterator<E> spliterator() {
- int lo = offset;
- int hi = offset + size;
- Object[] a = expectedArray;
- if (l.getArray() != a)
- throw new ConcurrentModificationException();
- if (lo < 0 || hi > a.length)
- throw new IndexOutOfBoundsException();
- return Spliterators.spliterator
- (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+ synchronized (lock) {
+ return Spliterators.spliterator(
+ getArrayChecked(), offset, offset + size,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED);
+ }
}
}
@@ -1483,7 +1531,7 @@
COWSubListIterator(List<E> l, int index, int offset, int size) {
this.offset = offset;
this.size = size;
- it = l.listIterator(index+offset);
+ it = l.listIterator(index + offset);
}
public boolean hasNext() {
@@ -1532,23 +1580,27 @@
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
- while (nextIndex() < size) {
+ while (hasNext()) {
action.accept(it.next());
}
}
}
- // Support for resetting lock while deserializing
+ /** Initializes the lock; for use when deserializing or cloning. */
private void resetLock() {
- U.putObjectVolatile(this, LOCK, new Object());
- }
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long LOCK;
- static {
+ Field lockField = java.security.AccessController.doPrivileged(
+ (java.security.PrivilegedAction<Field>) () -> {
+ try {
+ Field f = CopyOnWriteArrayList.class
+ .getDeclaredField("lock");
+ f.setAccessible(true);
+ return f;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }});
try {
- LOCK = U.objectFieldOffset
- (CopyOnWriteArrayList.class.getDeclaredField("lock"));
- } catch (ReflectiveOperationException e) {
+ lockField.set(this, new Object());
+ } catch (IllegalAccessException e) {
throw new Error(e);
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
index fb707dd..b14a3e8 100644
--- a/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/ojluni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
@@ -45,13 +45,8 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
-// BEGIN android-note
-// removed link to collections framework docs
-// fixed framework docs link to "Collection#optional"
-// END android-note
-
/**
- * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
+ * A {@link Set} that uses an internal {@link CopyOnWriteArrayList}
* for all of its operations. Thus, it shares the same basic properties:
* <ul>
* <li>It is best suited for applications in which set sizes generally
@@ -91,6 +86,10 @@
* }
* }}</pre>
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @see CopyOnWriteArrayList
* @since 1.5
* @author Doug Lea
@@ -341,10 +340,10 @@
* @return {@code true} if this set changed as a result of the call
* @throws ClassCastException if the class of an element of this set
* is incompatible with the specified collection
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this set contains a null element and the
* specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -364,10 +363,10 @@
* @return {@code true} if this set changed as a result of the call
* @throws ClassCastException if the class of an element of this set
* is incompatible with the specified collection
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this set contains a null element and the
* specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -412,10 +411,16 @@
&& compareSets(al.getArray(), (Set<?>) o) == 0);
}
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
public boolean removeIf(Predicate<? super E> filter) {
return al.removeIf(filter);
}
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
public void forEach(Consumer<? super E> action) {
al.forEach(action);
}
diff --git a/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java b/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
index a29208e..a91d12d 100644
--- a/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
+++ b/ojluni/src/main/java/java/util/concurrent/CountedCompleter.java
@@ -35,6 +35,9 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* A {@link ForkJoinTask} with a completion action performed when
* triggered and there are no remaining pending actions.
@@ -54,8 +57,7 @@
* decremented; otherwise, the completion action is performed, and if
* this completer itself has a completer, the process is continued
* with its completer. As is the case with related synchronization
- * components such as {@link java.util.concurrent.Phaser Phaser} and
- * {@link java.util.concurrent.Semaphore Semaphore}, these methods
+ * components such as {@link Phaser} and {@link Semaphore}, these methods
* affect only internal counts; they do not establish any further
* internal bookkeeping. In particular, the identities of pending
* tasks are not maintained. As illustrated below, you can create
@@ -117,102 +119,114 @@
* to complete for some elements than others, either because of
* intrinsic variation (for example I/O) or auxiliary effects such as
* garbage collection. Because CountedCompleters provide their own
- * continuations, other threads need not block waiting to perform
- * them.
+ * continuations, other tasks need not block waiting to perform them.
*
- * <p>For example, here is an initial version of a class that uses
- * divide-by-two recursive decomposition to divide work into single
- * pieces (leaf tasks). Even when work is split into individual calls,
- * tree-based techniques are usually preferable to directly forking
- * leaf tasks, because they reduce inter-thread communication and
- * improve load balancing. In the recursive case, the second of each
- * pair of subtasks to finish triggers completion of its parent
+ * <p>For example, here is an initial version of a utility method that
+ * uses divide-by-two recursive decomposition to divide work into
+ * single pieces (leaf tasks). Even when work is split into individual
+ * calls, tree-based techniques are usually preferable to directly
+ * forking leaf tasks, because they reduce inter-thread communication
+ * and improve load balancing. In the recursive case, the second of
+ * each pair of subtasks to finish triggers completion of their parent
* (because no result combination is performed, the default no-op
* implementation of method {@code onCompletion} is not overridden).
- * A static utility method sets up the base task and invokes it
- * (here, implicitly using the {@link ForkJoinPool#commonPool()}).
+ * The utility method sets up the root task and invokes it (here,
+ * implicitly using the {@link ForkJoinPool#commonPool()}). It is
+ * straightforward and reliable (but not optimal) to always set the
+ * pending count to the number of child tasks and call {@code
+ * tryComplete()} immediately before returning.
*
* <pre> {@code
- * class MyOperation<E> { void apply(E e) { ... } }
- *
- * class ForEach<E> extends CountedCompleter<Void> {
- *
- * public static <E> void forEach(E[] array, MyOperation<E> op) {
- * new ForEach<E>(null, array, op, 0, array.length).invoke();
- * }
- *
- * final E[] array; final MyOperation<E> op; final int lo, hi;
- * ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
- * super(p);
- * this.array = array; this.op = op; this.lo = lo; this.hi = hi;
- * }
- *
- * public void compute() { // version 1
- * if (hi - lo >= 2) {
- * int mid = (lo + hi) >>> 1;
- * setPendingCount(2); // must set pending count before fork
- * new ForEach(this, array, op, mid, hi).fork(); // right child
- * new ForEach(this, array, op, lo, mid).fork(); // left child
+ * public static <E> void forEach(E[] array, Consumer<E> action) {
+ * class Task extends CountedCompleter<Void> {
+ * final int lo, hi;
+ * Task(Task parent, int lo, int hi) {
+ * super(parent); this.lo = lo; this.hi = hi;
* }
- * else if (hi > lo)
- * op.apply(array[lo]);
- * tryComplete();
+ *
+ * public void compute() {
+ * if (hi - lo >= 2) {
+ * int mid = (lo + hi) >>> 1;
+ * // must set pending count before fork
+ * setPendingCount(2);
+ * new Task(this, mid, hi).fork(); // right child
+ * new Task(this, lo, mid).fork(); // left child
+ * }
+ * else if (hi > lo)
+ * action.accept(array[lo]);
+ * tryComplete();
+ * }
* }
+ * new Task(null, 0, array.length).invoke();
* }}</pre>
*
* This design can be improved by noticing that in the recursive case,
* the task has nothing to do after forking its right task, so can
* directly invoke its left task before returning. (This is an analog
- * of tail recursion removal.) Also, because the task returns upon
- * executing its left task (rather than falling through to invoke
- * {@code tryComplete}) the pending count is set to one:
+ * of tail recursion removal.) Also, when the last action in a task
+ * is to fork or invoke a subtask (a "tail call"), the call to {@code
+ * tryComplete()} can be optimized away, at the cost of making the
+ * pending count look "off by one".
*
* <pre> {@code
- * class ForEach<E> ... {
- * ...
- * public void compute() { // version 2
- * if (hi - lo >= 2) {
- * int mid = (lo + hi) >>> 1;
- * setPendingCount(1); // only one pending
- * new ForEach(this, array, op, mid, hi).fork(); // right child
- * new ForEach(this, array, op, lo, mid).compute(); // direct invoke
- * }
- * else {
- * if (hi > lo)
- * op.apply(array[lo]);
- * tryComplete();
- * }
- * }
- * }}</pre>
+ * public void compute() {
+ * if (hi - lo >= 2) {
+ * int mid = (lo + hi) >>> 1;
+ * setPendingCount(1); // looks off by one, but correct!
+ * new Task(this, mid, hi).fork(); // right child
+ * new Task(this, lo, mid).compute(); // direct invoke
+ * } else {
+ * if (hi > lo)
+ * action.accept(array[lo]);
+ * tryComplete();
+ * }
+ * }}</pre>
*
* As a further optimization, notice that the left task need not even exist.
- * Instead of creating a new one, we can iterate using the original task,
+ * Instead of creating a new one, we can continue using the original task,
* and add a pending count for each fork. Additionally, because no task
* in this tree implements an {@link #onCompletion(CountedCompleter)} method,
- * {@code tryComplete()} can be replaced with {@link #propagateCompletion}.
+ * {@code tryComplete} can be replaced with {@link #propagateCompletion}.
*
* <pre> {@code
- * class ForEach<E> ... {
- * ...
- * public void compute() { // version 3
- * int l = lo, h = hi;
- * while (h - l >= 2) {
- * int mid = (l + h) >>> 1;
- * addToPendingCount(1);
- * new ForEach(this, array, op, mid, h).fork(); // right child
- * h = mid;
+ * public void compute() {
+ * int n = hi - lo;
+ * for (; n >= 2; n /= 2) {
+ * addToPendingCount(1);
+ * new Task(this, lo + n/2, lo + n).fork();
+ * }
+ * if (n > 0)
+ * action.accept(array[lo]);
+ * propagateCompletion();
+ * }}</pre>
+ *
+ * When pending counts can be precomputed, they can be established in
+ * the constructor:
+ *
+ * <pre> {@code
+ * public static <E> void forEach(E[] array, Consumer<E> action) {
+ * class Task extends CountedCompleter<Void> {
+ * final int lo, hi;
+ * Task(Task parent, int lo, int hi) {
+ * super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
+ * this.lo = lo; this.hi = hi;
* }
- * if (h > l)
- * op.apply(array[l]);
- * propagateCompletion();
+ *
+ * public void compute() {
+ * for (int n = hi - lo; n >= 2; n /= 2)
+ * new Task(this, lo + n/2, lo + n).fork();
+ * action.accept(array[lo]);
+ * propagateCompletion();
+ * }
* }
+ * if (array.length > 0)
+ * new Task(null, 0, array.length).invoke();
* }}</pre>
*
- * Additional optimizations of such classes might entail precomputing
- * pending counts so that they can be established in constructors,
- * specializing classes for leaf steps, subdividing by say, four,
- * instead of two per iteration, and using an adaptive threshold
- * instead of always subdividing down to single elements.
+ * Additional optimizations of such classes might entail specializing
+ * classes for leaf steps, subdividing by say, four, instead of two
+ * per iteration, and using an adaptive threshold instead of always
+ * subdividing down to single elements.
*
* <p><b>Searching.</b> A tree of CountedCompleters can search for a
* value or property in different parts of a data structure, and
@@ -524,7 +538,7 @@
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
- U.getAndAddInt(this, PENDING, delta);
+ PENDING.getAndAdd(this, delta);
}
/**
@@ -536,7 +550,7 @@
* @return {@code true} if successful
*/
public final boolean compareAndSetPendingCount(int expected, int count) {
- return U.compareAndSwapInt(this, PENDING, expected, count);
+ return PENDING.compareAndSet(this, expected, count);
}
/**
@@ -548,7 +562,7 @@
public final int decrementPendingCountUnlessZero() {
int c;
do {} while ((c = pending) != 0 &&
- !U.compareAndSwapInt(this, PENDING, c, c - 1));
+ !PENDING.weakCompareAndSet(this, c, c - 1));
return c;
}
@@ -581,7 +595,7 @@
return;
}
}
- else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSet(a, c, c - 1))
return;
}
}
@@ -596,7 +610,7 @@
* not, be invoked for each completer in a computation.
*/
public final void propagateCompletion() {
- CountedCompleter<?> a = this, s = a;
+ CountedCompleter<?> a = this, s;
for (int c;;) {
if ((c = a.pending) == 0) {
if ((a = (s = a).completer) == null) {
@@ -604,7 +618,7 @@
return;
}
}
- else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSet(a, c, c - 1))
return;
}
}
@@ -649,7 +663,7 @@
for (int c;;) {
if ((c = pending) == 0)
return this;
- else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSet(this, c, c - 1))
return null;
}
}
@@ -721,7 +735,7 @@
CountedCompleter<?> a = this, s = a;
while (a.onExceptionalCompletion(ex, s) &&
(a = (s = a).completer) != null && a.status >= 0 &&
- a.recordExceptionalCompletion(ex) == EXCEPTIONAL)
+ isExceptionalStatus(a.recordExceptionalCompletion(ex)))
;
}
@@ -753,15 +767,15 @@
*/
protected void setRawResult(T t) { }
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PENDING;
+ // VarHandle mechanics
+ private static final VarHandle PENDING;
static {
try {
- PENDING = U.objectFieldOffset
- (CountedCompleter.class.getDeclaredField("pending"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
+
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java b/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
index 5e018f1..269bec4 100644
--- a/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
+++ b/ojluni/src/main/java/java/util/concurrent/CyclicBarrier.java
@@ -82,8 +82,7 @@
* public Solver(float[][] matrix) {
* data = matrix;
* N = matrix.length;
- * Runnable barrierAction =
- * new Runnable() { public void run() { mergeRows(...); }};
+ * Runnable barrierAction = () -> mergeRows(...);
* barrier = new CyclicBarrier(N, barrierAction);
*
* List<Thread> threads = new ArrayList<>(N);
@@ -132,10 +131,10 @@
* <i>happen-before</i> actions following a successful return from the
* corresponding {@code await()} in other threads.
*
- * @since 1.5
* @see CountDownLatch
*
* @author Doug Lea
+ * @since 1.5
*/
public class CyclicBarrier {
/**
@@ -150,7 +149,8 @@
* but no subsequent reset.
*/
private static class Generation {
- boolean broken; // initially false
+ Generation() {} // prevent access constructor creation
+ boolean broken; // initially false
}
/** The lock for guarding barrier entry */
diff --git a/ojluni/src/main/java/java/util/concurrent/DelayQueue.java b/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
index 04a83d9..bf0858d 100644
--- a/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/DelayQueue.java
@@ -41,14 +41,11 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
/**
* An unbounded {@linkplain BlockingQueue blocking queue} of
* {@code Delayed} elements, in which an element can only be taken
@@ -63,11 +60,15 @@
* returns the count of both expired and unexpired elements.
* This queue does not permit null elements.
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces. The Iterator provided in method {@link
- * #iterator()} is <em>not</em> guaranteed to traverse the elements of
- * the DelayQueue in any particular order.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * The Iterator provided in method {@link #iterator()} is <em>not</em>
+ * guaranteed to traverse the elements of the DelayQueue in any
+ * particular order.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
*
* @since 1.5
* @author Doug Lea
@@ -322,40 +323,13 @@
}
/**
- * Returns first element only if it is expired.
- * Used only by drainTo. Call only when holding lock.
- */
- private E peekExpired() {
- // assert lock.isHeldByCurrentThread();
- E first = q.peek();
- return (first == null || first.getDelay(NANOSECONDS) > 0) ?
- null : first;
- }
-
- /**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
- if (c == null)
- throw new NullPointerException();
- if (c == this)
- throw new IllegalArgumentException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- int n = 0;
- for (E e; (e = peekExpired()) != null;) {
- c.add(e); // In this order, in case add() throws.
- q.poll();
- ++n;
- }
- return n;
- } finally {
- lock.unlock();
- }
+ return drainTo(c, Integer.MAX_VALUE);
}
/**
@@ -365,8 +339,7 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -375,8 +348,11 @@
lock.lock();
try {
int n = 0;
- for (E e; n < maxElements && (e = peekExpired()) != null;) {
- c.add(e); // In this order, in case add() throws.
+ for (E first;
+ n < maxElements
+ && (first = q.peek()) != null
+ && first.getDelay(NANOSECONDS) <= 0;) {
+ c.add(first); // In this order, in case add() throws.
q.poll();
++n;
}
@@ -547,8 +523,7 @@
public E next() {
if (cursor >= array.length)
throw new NoSuchElementException();
- lastRet = cursor;
- return (E)array[cursor++];
+ return (E)array[lastRet = cursor++];
}
public void remove() {
diff --git a/ojluni/src/main/java/java/util/concurrent/Exchanger.java b/ojluni/src/main/java/java/util/concurrent/Exchanger.java
index f01a705..c55e5ac 100644
--- a/ojluni/src/main/java/java/util/concurrent/Exchanger.java
+++ b/ojluni/src/main/java/java/util/concurrent/Exchanger.java
@@ -36,6 +36,10 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.locks.LockSupport;
+
/**
* A synchronization point at which threads can pair and swap elements
* within pairs. Each thread presents some object on entry to the
@@ -155,9 +159,7 @@
* a value that is enough for common platforms. Additionally,
* extra care elsewhere is taken to avoid other false/unintended
* sharing and to enhance locality, including adding padding (via
- * @Contended) to Nodes, embedding "bound" as an Exchanger field,
- * and reworking some park/unpark mechanics compared to
- * LockSupport versions.
+ * @Contended) to Nodes, embedding "bound" as an Exchanger field.
*
* The arena starts out with only one used slot. We expand the
* effective arena size by tracking collisions; i.e., failed CASes
@@ -233,29 +235,23 @@
* As is too common in this sort of code, methods are monolithic
* because most of the logic relies on reads of fields that are
* maintained as local variables so can't be nicely factored --
- * mainly, here, bulky spin->yield->block/cancel code), and
- * heavily dependent on intrinsics (Unsafe) to use inlined
- * embedded CAS and related memory access operations (that tend
- * not to be as readily inlined by dynamic compilers when they are
- * hidden behind other methods that would more nicely name and
- * encapsulate the intended effects). This includes the use of
- * putOrderedX to clear fields of the per-thread Nodes between
- * uses. Note that field Node.item is not declared as volatile
- * even though it is read by releasing threads, because they only
- * do so after CAS operations that must precede access, and all
- * uses by the owning thread are otherwise acceptably ordered by
- * other operations. (Because the actual points of atomicity are
- * slot CASes, it would also be legal for the write to Node.match
- * in a release to be weaker than a full volatile write. However,
- * this is not done because it could allow further postponement of
- * the write, delaying progress.)
+ * mainly, here, bulky spin->yield->block/cancel code. Note that
+ * field Node.item is not declared as volatile even though it is
+ * read by releasing threads, because they only do so after CAS
+ * operations that must precede access, and all uses by the owning
+ * thread are otherwise acceptably ordered by other operations.
+ * (Because the actual points of atomicity are slot CASes, it
+ * would also be legal for the write to Node.match in a release to
+ * be weaker than a full volatile write. However, this is not done
+ * because it could allow further postponement of the write,
+ * delaying progress.)
*/
/**
- * The byte distance (as a shift value) between any two used slots
- * in the arena. 1 << ASHIFT should be at least cacheline size.
+ * The index distance (as a shift value) between any two used slots
+ * in the arena, spacing them out to avoid false sharing.
*/
- private static final int ASHIFT = 7;
+ private static final int ASHIFT = 5;
/**
* The maximum supported arena index. The maximum allocatable
@@ -306,8 +302,7 @@
* Nodes hold partially exchanged data, plus other per-thread
* bookkeeping. Padded via @Contended to reduce memory contention.
*/
- // Android-removed: @Contended, this hint is not used by the Android runtime.
- //@jdk.internal.vm.annotation.Contended
+ @jdk.internal.vm.annotation.Contended
static final class Node {
int index; // Arena index
int bound; // Last recorded value of Exchanger.bound
@@ -358,27 +353,31 @@
*/
private final Object arenaExchange(Object item, boolean timed, long ns) {
Node[] a = arena;
+ int alen = a.length;
Node p = participant.get();
for (int i = p.index;;) { // access slot at i
- int b, m, c; long j; // j is raw array offset
- Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
- if (q != null && U.compareAndSwapObject(a, j, q, null)) {
+ int b, m, c;
+ int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
+ if (j < 0 || j >= alen)
+ j = alen - 1;
+ Node q = (Node)AA.getAcquire(a, j);
+ if (q != null && AA.compareAndSet(a, j, q, null)) {
Object v = q.item; // release
q.match = item;
Thread w = q.parked;
if (w != null)
- U.unpark(w);
+ LockSupport.unpark(w);
return v;
}
else if (i <= (m = (b = bound) & MMASK) && q == null) {
p.item = item; // offer
- if (U.compareAndSwapObject(a, j, null, p)) {
+ if (AA.compareAndSet(a, j, null, p)) {
long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
Thread t = Thread.currentThread(); // wait
for (int h = p.hash, spins = SPINS;;) {
Object v = p.match;
if (v != null) {
- U.putOrderedObject(p, MATCH, null);
+ MATCH.setRelease(p, null);
p.item = null; // clear for next use
p.hash = h;
return v;
@@ -391,22 +390,24 @@
(--spins & ((SPINS >>> 1) - 1)) == 0)
Thread.yield(); // two yields per wait
}
- else if (U.getObjectVolatile(a, j) != p)
+ else if (AA.getAcquire(a, j) != p)
spins = SPINS; // releaser hasn't set match yet
else if (!t.isInterrupted() && m == 0 &&
(!timed ||
(ns = end - System.nanoTime()) > 0L)) {
- U.putObject(t, BLOCKER, this); // emulate LockSupport
p.parked = t; // minimize window
- if (U.getObjectVolatile(a, j) == p)
- U.park(false, ns);
+ if (AA.getAcquire(a, j) == p) {
+ if (ns == 0L)
+ LockSupport.park(this);
+ else
+ LockSupport.parkNanos(this, ns);
+ }
p.parked = null;
- U.putObject(t, BLOCKER, null);
}
- else if (U.getObjectVolatile(a, j) == p &&
- U.compareAndSwapObject(a, j, p, null)) {
+ else if (AA.getAcquire(a, j) == p &&
+ AA.compareAndSet(a, j, p, null)) {
if (m != 0) // try to shrink
- U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
+ BOUND.compareAndSet(this, b, b + SEQ - 1);
p.item = null;
p.hash = h;
i = p.index >>>= 1; // descend
@@ -428,7 +429,7 @@
i = (i != m || m == 0) ? m : m - 1;
}
else if ((c = p.collides) < m || m == FULL ||
- !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
+ !BOUND.compareAndSet(this, b, b + SEQ + 1)) {
p.collides = c + 1;
i = (i == 0) ? m : i - 1; // cyclically traverse
}
@@ -457,24 +458,24 @@
for (Node q;;) {
if ((q = slot) != null) {
- if (U.compareAndSwapObject(this, SLOT, q, null)) {
+ if (SLOT.compareAndSet(this, q, null)) {
Object v = q.item;
q.match = item;
Thread w = q.parked;
if (w != null)
- U.unpark(w);
+ LockSupport.unpark(w);
return v;
}
// create arena on contention, but continue until slot null
if (NCPU > 1 && bound == 0 &&
- U.compareAndSwapInt(this, BOUND, 0, SEQ))
+ BOUND.compareAndSet(this, 0, SEQ))
arena = new Node[(FULL + 2) << ASHIFT];
}
else if (arena != null)
return null; // caller must reroute to arenaExchange
else {
p.item = item;
- if (U.compareAndSwapObject(this, SLOT, null, p))
+ if (SLOT.compareAndSet(this, null, p))
break;
p.item = null;
}
@@ -497,19 +498,21 @@
spins = SPINS;
else if (!t.isInterrupted() && arena == null &&
(!timed || (ns = end - System.nanoTime()) > 0L)) {
- U.putObject(t, BLOCKER, this);
p.parked = t;
- if (slot == p)
- U.park(false, ns);
+ if (slot == p) {
+ if (ns == 0L)
+ LockSupport.park(this);
+ else
+ LockSupport.parkNanos(this, ns);
+ }
p.parked = null;
- U.putObject(t, BLOCKER, null);
}
- else if (U.compareAndSwapObject(this, SLOT, p, null)) {
+ else if (SLOT.compareAndSet(this, p, null)) {
v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
break;
}
}
- U.putOrderedObject(p, MATCH, null);
+ MATCH.setRelease(p, null);
p.item = null;
p.hash = h;
return v;
@@ -558,8 +561,9 @@
@SuppressWarnings("unchecked")
public V exchange(V x) throws InterruptedException {
Object v;
+ Node[] a;
Object item = (x == null) ? NULL_ITEM : x; // translate null args
- if ((arena != null ||
+ if (((a = arena) != null ||
(v = slotExchange(item, false, 0L)) == null) &&
((Thread.interrupted() || // disambiguates null return
(v = arenaExchange(item, false, 0L)) == null)))
@@ -625,33 +629,20 @@
return (v == NULL_ITEM) ? null : (V)v;
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long BOUND;
- private static final long SLOT;
- private static final long MATCH;
- private static final long BLOCKER;
- private static final int ABASE;
+ // VarHandle mechanics
+ private static final VarHandle BOUND;
+ private static final VarHandle SLOT;
+ private static final VarHandle MATCH;
+ private static final VarHandle AA;
static {
try {
- BOUND = U.objectFieldOffset
- (Exchanger.class.getDeclaredField("bound"));
- SLOT = U.objectFieldOffset
- (Exchanger.class.getDeclaredField("slot"));
-
- MATCH = U.objectFieldOffset
- (Node.class.getDeclaredField("match"));
-
- BLOCKER = U.objectFieldOffset
- (Thread.class.getDeclaredField("parkBlocker"));
-
- int scale = U.arrayIndexScale(Node[].class);
- if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
- throw new Error("Unsupported array scale");
- // ABASE absorbs padding in front of element 0
- ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
+ SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
+ MATCH = l.findVarHandle(Node.class, "match", Object.class);
+ AA = MethodHandles.arrayElementVarHandle(Node[].class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/Executor.java b/ojluni/src/main/java/java/util/concurrent/Executor.java
index a615705..378cacd 100644
--- a/ojluni/src/main/java/java/util/concurrent/Executor.java
+++ b/ojluni/src/main/java/java/util/concurrent/Executor.java
@@ -87,14 +87,12 @@
* this.executor = executor;
* }
*
- * public synchronized void execute(final Runnable r) {
- * tasks.add(new Runnable() {
- * public void run() {
- * try {
- * r.run();
- * } finally {
- * scheduleNext();
- * }
+ * public synchronized void execute(Runnable r) {
+ * tasks.add(() -> {
+ * try {
+ * r.run();
+ * } finally {
+ * scheduleNext();
* }
* });
* if (active == null) {
diff --git a/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index a093844..d60d3dd 100644
--- a/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -56,13 +56,11 @@
* void solve(Executor e,
* Collection<Callable<Result>> solvers)
* throws InterruptedException, ExecutionException {
- * CompletionService<Result> ecs
- * = new ExecutorCompletionService<Result>(e);
- * for (Callable<Result> s : solvers)
- * ecs.submit(s);
- * int n = solvers.size();
- * for (int i = 0; i < n; ++i) {
- * Result r = ecs.take().get();
+ * CompletionService<Result> cs
+ * = new ExecutorCompletionService<>(e);
+ * solvers.forEach(cs::submit);
+ * for (int i = solvers.size(); i > 0; i--) {
+ * Result r = cs.take().get();
* if (r != null)
* use(r);
* }
@@ -76,32 +74,31 @@
* void solve(Executor e,
* Collection<Callable<Result>> solvers)
* throws InterruptedException {
- * CompletionService<Result> ecs
- * = new ExecutorCompletionService<Result>(e);
+ * CompletionService<Result> cs
+ * = new ExecutorCompletionService<>(e);
* int n = solvers.size();
* List<Future<Result>> futures = new ArrayList<>(n);
* Result result = null;
* try {
- * for (Callable<Result> s : solvers)
- * futures.add(ecs.submit(s));
- * for (int i = 0; i < n; ++i) {
+ * solvers.forEach(solver -> futures.add(cs.submit(solver)));
+ * for (int i = n; i > 0; i--) {
* try {
- * Result r = ecs.take().get();
+ * Result r = cs.take().get();
* if (r != null) {
* result = r;
* break;
* }
* } catch (ExecutionException ignore) {}
* }
- * }
- * finally {
- * for (Future<Result> f : futures)
- * f.cancel(true);
+ * } finally {
+ * futures.forEach(future -> future.cancel(true));
* }
*
* if (result != null)
* use(result);
* }}</pre>
+ *
+ * @since 1.5
*/
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Executor executor;
@@ -177,6 +174,10 @@
this.completionQueue = completionQueue;
}
+ /**
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
@@ -184,6 +185,10 @@
return f;
}
+ /**
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
diff --git a/ojluni/src/main/java/java/util/concurrent/Executors.java b/ojluni/src/main/java/java/util/concurrent/Executors.java
index 565fdeb..e8cc0c1 100644
--- a/ojluni/src/main/java/java/util/concurrent/Executors.java
+++ b/ojluni/src/main/java/java/util/concurrent/Executors.java
@@ -35,6 +35,7 @@
package java.util.concurrent;
+import static java.lang.ref.Reference.reachabilityFence;
import dalvik.annotation.optimization.ReachabilitySensitive;
import java.security.AccessControlContext;
import java.security.AccessControlException;
@@ -190,9 +191,7 @@
* returned executor is guaranteed not to be reconfigurable to use
* additional threads.
*
- * @param threadFactory the factory to use when creating new
- * threads
- *
+ * @param threadFactory the factory to use when creating new threads
* @return the newly created single-threaded Executor
* @throws NullPointerException if threadFactory is null
*/
@@ -231,6 +230,7 @@
* will reuse previously constructed threads when they are
* available, and uses the provided
* ThreadFactory to create new threads when needed.
+ *
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
@@ -253,6 +253,7 @@
* given time. Unlike the otherwise equivalent
* {@code newScheduledThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
+ *
* @return the newly created scheduled executor
*/
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
@@ -271,9 +272,9 @@
* equivalent {@code newScheduledThreadPool(1, threadFactory)}
* the returned executor is guaranteed not to be reconfigurable to
* use additional threads.
- * @param threadFactory the factory to use when creating new
- * threads
- * @return a newly created scheduled executor
+ *
+ * @param threadFactory the factory to use when creating new threads
+ * @return the newly created scheduled executor
* @throws NullPointerException if threadFactory is null
*/
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
@@ -286,7 +287,7 @@
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
- * @return a newly created scheduled thread pool
+ * @return the newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
@@ -300,7 +301,7 @@
* even if they are idle
* @param threadFactory the factory to use when the executor
* creates a new thread
- * @return a newly created scheduled thread pool
+ * @return the newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @throws NullPointerException if threadFactory is null
*/
@@ -462,6 +463,9 @@
task.run();
return result;
}
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + task + "]";
+ }
}
/**
@@ -488,6 +492,10 @@
throw e.getException();
}
}
+
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + task + "]";
+ }
}
/**
@@ -543,6 +551,10 @@
throw e.getException();
}
}
+
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + task + "]";
+ }
}
/**
@@ -604,7 +616,7 @@
public Thread newThread(final Runnable r) {
return super.newThread(new Runnable() {
public void run() {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ AccessController.doPrivileged(new PrivilegedAction<>() {
public Void run() {
Thread.currentThread().setContextClassLoader(ccl);
r.run();
@@ -621,47 +633,79 @@
* of an ExecutorService implementation.
*/
private static class DelegatedExecutorService
- extends AbstractExecutorService {
+ implements ExecutorService {
// Android-added: @ReachabilitySensitive
// Needed for FinalizableDelegatedExecutorService below.
@ReachabilitySensitive
private final ExecutorService e;
DelegatedExecutorService(ExecutorService executor) { e = executor; }
- public void execute(Runnable command) { e.execute(command); }
+ public void execute(Runnable command) {
+ try {
+ e.execute(command);
+ } finally { reachabilityFence(this); }
+ }
public void shutdown() { e.shutdown(); }
- public List<Runnable> shutdownNow() { return e.shutdownNow(); }
- public boolean isShutdown() { return e.isShutdown(); }
- public boolean isTerminated() { return e.isTerminated(); }
+ public List<Runnable> shutdownNow() {
+ try {
+ return e.shutdownNow();
+ } finally { reachabilityFence(this); }
+ }
+ public boolean isShutdown() {
+ try {
+ return e.isShutdown();
+ } finally { reachabilityFence(this); }
+ }
+ public boolean isTerminated() {
+ try {
+ return e.isTerminated();
+ } finally { reachabilityFence(this); }
+ }
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
- return e.awaitTermination(timeout, unit);
+ try {
+ return e.awaitTermination(timeout, unit);
+ } finally { reachabilityFence(this); }
}
public Future<?> submit(Runnable task) {
- return e.submit(task);
+ try {
+ return e.submit(task);
+ } finally { reachabilityFence(this); }
}
public <T> Future<T> submit(Callable<T> task) {
- return e.submit(task);
+ try {
+ return e.submit(task);
+ } finally { reachabilityFence(this); }
}
public <T> Future<T> submit(Runnable task, T result) {
- return e.submit(task, result);
+ try {
+ return e.submit(task, result);
+ } finally { reachabilityFence(this); }
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
- return e.invokeAll(tasks);
+ try {
+ return e.invokeAll(tasks);
+ } finally { reachabilityFence(this); }
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
- return e.invokeAll(tasks, timeout, unit);
+ try {
+ return e.invokeAll(tasks, timeout, unit);
+ } finally { reachabilityFence(this); }
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
- return e.invokeAny(tasks);
+ try {
+ return e.invokeAny(tasks);
+ } finally { reachabilityFence(this); }
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- return e.invokeAny(tasks, timeout, unit);
+ try {
+ return e.invokeAny(tasks, timeout, unit);
+ } finally { reachabilityFence(this); }
}
}
@@ -670,6 +714,7 @@
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
+ @SuppressWarnings("deprecation")
protected void finalize() {
super.shutdown();
}
diff --git a/ojluni/src/main/java/java/util/concurrent/Flow.java b/ojluni/src/main/java/java/util/concurrent/Flow.java
index 0231790..727a507 100644
--- a/ojluni/src/main/java/java/util/concurrent/Flow.java
+++ b/ojluni/src/main/java/java/util/concurrent/Flow.java
@@ -85,9 +85,9 @@
* this.executor = executor;
* }
* public synchronized void request(long n) {
- * if (n != 0 && !completed) {
+ * if (!completed) {
* completed = true;
- * if (n < 0) {
+ * if (n <= 0) {
* IllegalArgumentException ex = new IllegalArgumentException();
* executor.execute(() -> subscriber.onError(ex));
* } else {
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 04ad7d7..109a63c 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -36,15 +36,19 @@
package java.util.concurrent;
import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.security.AccessController;
import java.security.AccessControlContext;
+import java.security.Permission;
import java.security.Permissions;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Predicate;
import java.util.concurrent.locks.LockSupport;
/**
@@ -63,7 +67,8 @@
* tasks are submitted to the pool from external clients. Especially
* when setting <em>asyncMode</em> to true in constructors, {@code
* ForkJoinPool}s may also be appropriate for use with event-style
- * tasks that are never joined.
+ * tasks that are never joined. All worker threads are initialized
+ * with {@link Thread#isDaemon} set {@code true}.
*
* <p>A static {@link #commonPool()} is available and appropriate for
* most applications. The common pool is used by any ForkJoinTask that
@@ -81,7 +86,9 @@
* However, no such adjustments are guaranteed in the face of blocked
* I/O or other unmanaged synchronization. The nested {@link
* ManagedBlocker} interface enables extension of the kinds of
- * synchronization accommodated.
+ * synchronization accommodated. The default policies may be
+ * overridden using a constructor with parameters corresponding to
+ * those documented in class {@link ThreadPoolExecutor}.
*
* <p>In addition to execution and lifecycle control methods, this
* class provides status check methods (for example
@@ -102,48 +109,54 @@
* async event-style tasks that are not usually joined, in which case
* there is little difference among choice of methods.
*
- * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <table class="plain">
* <caption>Summary of task execution methods</caption>
* <tr>
* <td></td>
- * <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
- * <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
+ * <th scope="col"> Call from non-fork/join clients</th>
+ * <th scope="col"> Call from within fork/join computations</th>
* </tr>
* <tr>
- * <td> <b>Arrange async execution</b></td>
+ * <th scope="row" style="text-align:left"> Arrange async execution</th>
* <td> {@link #execute(ForkJoinTask)}</td>
* <td> {@link ForkJoinTask#fork}</td>
* </tr>
* <tr>
- * <td> <b>Await and obtain result</b></td>
+ * <th scope="row" style="text-align:left"> Await and obtain result</th>
* <td> {@link #invoke(ForkJoinTask)}</td>
* <td> {@link ForkJoinTask#invoke}</td>
* </tr>
* <tr>
- * <td> <b>Arrange exec and obtain Future</b></td>
+ * <th scope="row" style="text-align:left"> Arrange exec and obtain Future</th>
* <td> {@link #submit(ForkJoinTask)}</td>
* <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
* </tr>
* </table>
*
- * <p>The common pool is by default constructed with default
- * parameters, but these may be controlled by setting three
- * {@linkplain System#getProperty system properties}:
+ * <p>The parameters used to construct the common pool may be controlled by
+ * setting the following {@linkplain System#getProperty system properties}:
* <ul>
* <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism}
* - the parallelism level, a non-negative integer
* <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
- * - the class name of a {@link ForkJoinWorkerThreadFactory}
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
* <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
- * - the class name of a {@link UncaughtExceptionHandler}
+ * - the class name of a {@link UncaughtExceptionHandler}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
* <li>{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
* - the maximum number of allowed extra threads to maintain target
* parallelism (default 256).
* </ul>
- * If a {@link SecurityManager} is present and no factory is
- * specified, then the default pool uses a factory supplying
- * threads that have no {@link Permissions} enabled.
- * The system class loader is used to load these classes.
+ * If no thread factory is supplied via a system property, then the
+ * common pool uses a factory that uses the system class loader as the
+ * {@linkplain Thread#getContextClassLoader() thread context class loader}.
+ * In addition, if a {@link SecurityManager} is present, then
+ * the common pool uses a factory supplying threads that have no
+ * {@link Permissions} enabled.
+ *
* Upon any error in establishing these settings, default parameters
* are used. It is possible to disable or limit the use of threads in
* the common pool by setting the parallelism property to zero, and/or
@@ -162,8 +175,7 @@
* @since 1.7
* @author Doug Lea
*/
-// Android-removed: @Contended, this hint is not used by the Android runtime.
-//@jdk.internal.vm.annotation.Contended
+@jdk.internal.vm.annotation.Contended
public class ForkJoinPool extends AbstractExecutorService {
/*
@@ -173,17 +185,22 @@
* functionality and control for a set of worker threads:
* Submissions from non-FJ threads enter into submission queues.
* Workers take these tasks and typically split them into subtasks
- * that may be stolen by other workers. Preference rules give
- * first priority to processing tasks from their own queues (LIFO
- * or FIFO, depending on mode), then to randomized FIFO steals of
- * tasks in other queues. This framework began as vehicle for
- * supporting tree-structured parallelism using work-stealing.
- * Over time, its scalability advantages led to extensions and
- * changes to better support more diverse usage contexts. Because
- * most internal methods and nested classes are interrelated,
- * their main rationale and descriptions are presented here;
- * individual methods and nested classes contain only brief
- * comments about details.
+ * that may be stolen by other workers. Work-stealing based on
+ * randomized scans generally leads to better throughput than
+ * "work dealing" in which producers assign tasks to idle threads,
+ * in part because threads that have finished other tasks before
+ * the signalled thread wakes up (which can be a long time) can
+ * take the task instead. Preference rules give first priority to
+ * processing tasks from their own queues (LIFO or FIFO, depending
+ * on mode), then to randomized FIFO steals of tasks in other
+ * queues. This framework began as vehicle for supporting
+ * tree-structured parallelism using work-stealing. Over time,
+ * its scalability advantages led to extensions and changes to
+ * better support more diverse usage contexts. Because most
+ * internal methods and nested classes are interrelated, their
+ * main rationale and descriptions are presented here; individual
+ * methods and nested classes contain only brief comments about
+ * details.
*
* WorkQueues
* ==========
@@ -216,9 +233,10 @@
*
* (The actual code needs to null-check and size-check the array,
* uses masking, not mod, for indexing a power-of-two-sized array,
- * properly fences accesses, and possibly signals waiting workers
- * to start scanning -- see below.) Both a successful pop and
- * poll mainly entail a CAS of a slot from non-null to null.
+ * adds a release fence for publication, and possibly signals
+ * waiting workers to start scanning -- see below.) Both a
+ * successful pop and poll mainly entail a CAS of a slot from
+ * non-null to null.
*
* The pop operation (always performed by owner) is:
* if ((the task at top slot is not null) and
@@ -230,10 +248,14 @@
* (CAS slot to null))
* increment base and return task;
*
- * There are several variants of each of these; for example most
- * versions of poll pre-screen the CAS by rechecking that the base
- * has not changed since reading the slot, and most methods only
- * attempt the CAS if base appears not to be equal to top.
+ * There are several variants of each of these. Most uses occur
+ * within operations that also interleave contention or emptiness
+ * tracking or inspection of elements before extracting them, so
+ * must interleave these with the above code. When performed by
+ * owner, getAndSet is used instead of CAS (see for example method
+ * nextLocalTask) which is usually more efficient, and possible
+ * because the top index cannot independently change during the
+ * operation.
*
* Memory ordering. See "Correct and Efficient Work-Stealing for
* Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
@@ -242,33 +264,37 @@
* algorithms similar to (but different than) the one used here.
* Extracting tasks in array slots via (fully fenced) CAS provides
* primary synchronization. The base and top indices imprecisely
- * guide where to extract from. We do not always require strict
- * orderings of array and index updates, so sometimes let them be
- * subject to compiler and processor reorderings. However, the
- * volatile "base" index also serves as a basis for memory
- * ordering: Slot accesses are preceded by a read of base,
- * ensuring happens-before ordering with respect to stealers (so
- * the slots themselves can be read via plain array reads.) The
- * only other memory orderings relied on are maintained in the
- * course of signalling and activation (see below). A check that
- * base == top indicates (momentary) emptiness, but otherwise may
- * err on the side of possibly making the queue appear nonempty
- * when a push, pop, or poll have not fully committed, or making
- * it appear empty when an update of top has not yet been visibly
- * written. (Method isEmpty() checks the case of a partially
- * completed removal of the last element.) Because of this, the
- * poll operation, considered individually, is not wait-free. One
- * thief cannot successfully continue until another in-progress
- * one (or, if previously empty, a push) visibly completes.
- * However, in the aggregate, we ensure at least probabilistic
+ * guide where to extract from. We do not usually require strict
+ * orderings of array and index updates. Many index accesses use
+ * plain mode, with ordering constrained by surrounding context
+ * (usually with respect to element CASes or the two WorkQueue
+ * volatile fields source and phase). When not otherwise already
+ * constrained, reads of "base" by queue owners use acquire-mode,
+ * and some externally callable methods preface accesses with
+ * acquire fences. Additionally, to ensure that index update
+ * writes are not coalesced or postponed in loops etc, "opaque"
+ * mode is used in a few cases where timely writes are not
+ * otherwise ensured. The "locked" versions of push- and pop-
+ * based methods for shared queues differ from owned versions
+ * because locking already forces some of the ordering.
+ *
+ * Because indices and slot contents cannot always be consistent,
+ * a check that base == top indicates (momentary) emptiness, but
+ * otherwise may err on the side of possibly making the queue
+ * appear nonempty when a push, pop, or poll have not fully
+ * committed, or making it appear empty when an update of top has
+ * not yet been visibly written. (Method isEmpty() checks the
+ * case of a partially completed removal of the last element.)
+ * Because of this, the poll operation, considered individually,
+ * is not wait-free. One thief cannot successfully continue until
+ * another in-progress one (or, if previously empty, a push)
+ * visibly completes. This can stall threads when required to
+ * consume from a given queue (see method poll()). However, in
+ * the aggregate, we ensure at least probabilistic
* non-blockingness. If an attempted steal fails, a scanning
* thief chooses a different random victim target to try next. So,
* in order for one thief to progress, it suffices for any
- * in-progress poll or new push on any empty queue to
- * complete. (This is why we normally use method pollAt and its
- * variants that try once at the apparent base index, else
- * consider alternative actions, rather than method poll, which
- * retries.)
+ * in-progress poll or new push on any empty queue to complete.
*
* This approach also enables support of a user mode in which
* local task processing is in FIFO, not LIFO order, simply by
@@ -283,16 +309,13 @@
* choosing existing queues, and may be randomly repositioned upon
* contention with other submitters. In essence, submitters act
* like workers except that they are restricted to executing local
- * tasks that they submitted (or in the case of CountedCompleters,
- * others with the same root task). Insertion of tasks in shared
- * mode requires a lock but we use only a simple spinlock (using
- * field qlock), because submitters encountering a busy queue move
- * on to try or create other queues -- they block only when
- * creating and registering new queues. Because it is used only as
- * a spinlock, unlocking requires only a "releasing" store (using
- * putOrderedInt). The qlock is also used during termination
- * detection, in which case it is forced to a negative
- * non-lockable value.
+ * tasks that they submitted. Insertion of tasks in shared mode
+ * requires a lock but we use only a simple spinlock (using field
+ * phase), because submitters encountering a busy queue move to a
+ * different position to use or create other queues -- they block
+ * only when creating and registering new queues. Because it is
+ * used only as a spinlock, unlocking requires only a "releasing"
+ * store (using setRelease) unless otherwise signalling.
*
* Management
* ==========
@@ -306,43 +329,36 @@
* There are only a few properties that we can globally track or
* maintain, so we pack them into a small number of variables,
* often maintaining atomicity without blocking or locking.
- * Nearly all essentially atomic control state is held in two
+ * Nearly all essentially atomic control state is held in a few
* volatile variables that are by far most often read (not
- * written) as status and consistency checks. (Also, field
- * "config" holds unchanging configuration state.)
+ * written) as status and consistency checks. We pack as much
+ * information into them as we can.
*
* Field "ctl" contains 64 bits holding information needed to
- * atomically decide to add, inactivate, enqueue (on an event
- * queue), dequeue, and/or re-activate workers. To enable this
- * packing, we restrict maximum parallelism to (1<<15)-1 (which is
- * far in excess of normal operating range) to allow ids, counts,
- * and their negations (used for thresholding) to fit into 16bit
+ * atomically decide to add, enqueue (on an event queue), and
+ * dequeue and release workers. To enable this packing, we
+ * restrict maximum parallelism to (1<<15)-1 (which is far in
+ * excess of normal operating range) to allow ids, counts, and
+ * their negations (used for thresholding) to fit into 16bit
* subfields.
*
- * Field "runState" holds lifetime status, atomically and
- * monotonically setting STARTED, SHUTDOWN, STOP, and finally
- * TERMINATED bits.
- *
- * Field "auxState" is a ReentrantLock subclass that also
- * opportunistically holds some other bookkeeping fields accessed
- * only when locked. It is mainly used to lock (infrequent)
- * updates to workQueues. The auxState instance is itself lazily
- * constructed (see tryInitialize), requiring a double-check-style
- * bootstrapping use of field runState, and locking a private
- * static.
+ * Field "mode" holds configuration parameters as well as lifetime
+ * status, atomically and monotonically setting SHUTDOWN, STOP,
+ * and finally TERMINATED bits.
*
* Field "workQueues" holds references to WorkQueues. It is
- * updated (only during worker creation and termination) under the
- * lock, but is otherwise concurrently readable, and accessed
- * directly. We also ensure that reads of the array reference
- * itself never become too stale (for example, re-reading before
- * each scan). To simplify index-based operations, the array size
- * is always a power of two, and all readers must tolerate null
- * slots. Worker queues are at odd indices. Shared (submission)
- * queues are at even indices, up to a maximum of 64 slots, to
- * limit growth even if array needs to expand to add more
- * workers. Grouping them together in this way simplifies and
- * speeds up task scanning.
+ * updated (only during worker creation and termination) under
+ * lock (using field workerNamePrefix as lock), but is otherwise
+ * concurrently readable, and accessed directly. We also ensure
+ * that uses of the array reference itself never become too stale
+ * in case of resizing, by arranging that (re-)reads are separated
+ * by at least one acquiring read access. To simplify index-based
+ * operations, the array size is always a power of two, and all
+ * readers must tolerate null slots. Worker queues are at odd
+ * indices. Shared (submission) queues are at even indices, up to
+ * a maximum of 64 slots, to limit growth even if the array needs
+ * to expand to add more workers. Grouping them together in this
+ * way simplifies and speeds up task scanning.
*
* All worker thread creation is on-demand, triggered by task
* submissions, replacement of terminated workers, and/or
@@ -361,30 +377,37 @@
* workers unless there appear to be tasks available. On the
* other hand, we must quickly prod them into action when new
* tasks are submitted or generated. In many usages, ramp-up time
- * to activate workers is the main limiting factor in overall
- * performance, which is compounded at program start-up by JIT
- * compilation and allocation. So we streamline this as much as
- * possible.
+ * is the main limiting factor in overall performance, which is
+ * compounded at program start-up by JIT compilation and
+ * allocation. So we streamline this as much as possible.
*
- * The "ctl" field atomically maintains active and total worker
- * counts as well as a queue to place waiting threads so they can
- * be located for signalling. Active counts also play the role of
- * quiescence indicators, so are decremented when workers believe
- * that there are no more tasks to execute. The "queue" is
- * actually a form of Treiber stack. A stack is ideal for
- * activating threads in most-recently used order. This improves
+ * The "ctl" field atomically maintains total worker and
+ * "released" worker counts, plus the head of the available worker
+ * queue (actually stack, represented by the lower 32bit subfield
+ * of ctl). Released workers are those known to be scanning for
+ * and/or running tasks. Unreleased ("available") workers are
+ * recorded in the ctl stack. These workers are made available for
+ * signalling by enqueuing in ctl (see method runWorker). The
+ * "queue" is a form of Treiber stack. This is ideal for
+ * activating threads in most-recently used order, and improves
* performance and locality, outweighing the disadvantages of
* being prone to contention and inability to release a worker
- * unless it is topmost on stack. We block/unblock workers after
- * pushing on the idle worker stack (represented by the lower
- * 32bit subfield of ctl) when they cannot find work. The top
- * stack state holds the value of the "scanState" field of the
- * worker: its index and status, plus a version counter that, in
- * addition to the count subfields (also serving as version
- * stamps) provide protection against Treiber stack ABA effects.
+ * unless it is topmost on stack. To avoid missed signal problems
+ * inherent in any wait/signal design, available workers rescan
+ * for (and if found run) tasks after enqueuing. Normally their
+ * release status will be updated while doing so, but the released
+ * worker ctl count may underestimate the number of active
+ * threads. (However, it is still possible to determine quiescence
+ * via a validation traversal -- see isQuiescent). After an
+ * unsuccessful rescan, available workers are blocked until
+ * signalled (see signalWork). The top stack state holds the
+ * value of the "phase" field of the worker: its index and status,
+ * plus a version counter that, in addition to the count subfields
+ * (also serving as version stamps) provide protection against
+ * Treiber stack ABA effects.
*
- * Creating workers. To create a worker, we pre-increment total
- * count (serving as a reservation), and attempt to construct a
+ * Creating workers. To create a worker, we pre-increment counts
+ * (serving as a reservation), and attempt to construct a
* ForkJoinWorkerThread via its factory. Upon construction, the
* new thread invokes registerWorker, where it constructs a
* WorkQueue and is assigned an index in the workQueues array
@@ -406,15 +429,14 @@
* submission queues for existing external threads (see
* externalPush).
*
- * WorkQueue field scanState is used by both workers and the pool
- * to manage and track whether a worker is UNSIGNALLED (possibly
- * blocked waiting for a signal). When a worker is inactivated,
- * its scanState field is set, and is prevented from executing
- * tasks, even though it must scan once for them to avoid queuing
- * races. Note that scanState updates lag queue CAS releases so
- * usage requires care. When queued, the lower 16 bits of
- * scanState must hold its pool index. So we place the index there
- * upon initialization (see registerWorker) and otherwise keep it
+ * WorkQueue field "phase" is used by both workers and the pool to
+ * manage and track whether a worker is UNSIGNALLED (possibly
+ * blocked waiting for a signal). When a worker is enqueued its
+ * phase field is set. Note that phase field updates lag queue CAS
+ * releases so usage requires care -- seeing a negative phase does
+ * not guarantee that the worker is available. When queued, the
+ * lower 16 bits of scanState must hold its pool index. So we
+ * place the index there upon initialization and otherwise keep it
* there or restore it when necessary.
*
* The ctl field also serves as the basis for memory
@@ -423,85 +445,68 @@
* consumers sync with each other by both writing/CASing ctl (even
* if to its current value). This would be extremely costly. So
* we relax it in several ways: (1) Producers only signal when
- * their queue is empty. Other workers propagate this signal (in
- * method scan) when they find tasks. (2) Workers only enqueue
- * after scanning (see below) and not finding any tasks. (3)
- * Rather than CASing ctl to its current value in the common case
- * where no action is required, we reduce write contention by
- * equivalently prefacing signalWork when called by an external
- * task producer using a memory access with full-volatile
- * semantics or a "fullFence". (4) For internal task producers we
- * rely on the fact that even if no other workers awaken, the
- * producer itself will eventually see the task and execute it.
+ * their queue is possibly empty at some point during a push
+ * operation (which requires conservatively checking size zero or
+ * one to cover races). (2) Other workers propagate this signal
+ * when they find tasks in a queue with size greater than one. (3)
+ * Workers only enqueue after scanning (see below) and not finding
+ * any tasks. (4) Rather than CASing ctl to its current value in
+ * the common case where no action is required, we reduce write
+ * contention by equivalently prefacing signalWork when called by
+ * an external task producer using a memory access with
+ * full-volatile semantics or a "fullFence".
*
- * Almost always, too many signals are issued. A task producer
- * cannot in general tell if some existing worker is in the midst
- * of finishing one task (or already scanning) and ready to take
- * another without being signalled. So the producer might instead
- * activate a different worker that does not find any work, and
- * then inactivates. This scarcely matters in steady-state
- * computations involving all workers, but can create contention
- * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
- * computations involving only a few workers.
+ * Almost always, too many signals are issued, in part because a
+ * task producer cannot tell if some existing worker is in the
+ * midst of finishing one task (or already scanning) and ready to
+ * take another without being signalled. So the producer might
+ * instead activate a different worker that does not find any
+ * work, and then inactivates. This scarcely matters in
+ * steady-state computations involving all workers, but can create
+ * contention and bookkeeping bottlenecks during ramp-up,
+ * ramp-down, and small computations involving only a few workers.
*
- * Scanning. Method scan() performs top-level scanning for tasks.
- * Each scan traverses (and tries to poll from) each queue in
- * pseudorandom permutation order by randomly selecting an origin
- * index and a step value. (The pseudorandom generator need not
- * have high-quality statistical properties in the long term, but
- * just within computations; We use 64bit and 32bit Marsaglia
- * XorShifts, which are cheap and suffice here.) Scanning also
- * employs contention reduction: When scanning workers fail a CAS
- * polling for work, they soon restart with a different
- * pseudorandom scan order (thus likely retrying at different
- * intervals). This improves throughput when many threads are
- * trying to take tasks from few queues. Scans do not otherwise
- * explicitly take into account core affinities, loads, cache
- * localities, etc, However, they do exploit temporal locality
- * (which usually approximates these) by preferring to re-poll (up
- * to POLL_LIMIT times) from the same queue after a successful
- * poll before trying others. Restricted forms of scanning occur
- * in methods helpComplete and findNonEmptyStealQueue, and take
- * similar but simpler forms.
- *
- * Deactivation and waiting. Queuing encounters several intrinsic
- * races; most notably that an inactivating scanning worker can
- * miss seeing a task produced during a scan. So when a worker
- * cannot find a task to steal, it inactivates and enqueues, and
- * then rescans to ensure that it didn't miss one, reactivating
- * upon seeing one with probability approximately proportional to
- * probability of a miss. (In most cases, the worker will be
- * signalled before self-signalling, avoiding cascades of multiple
- * signals for the same task).
- *
- * Workers block (in method awaitWork) using park/unpark;
- * advertising the need for signallers to unpark by setting their
- * "parker" fields.
+ * Scanning. Method scan (from runWorker) performs top-level
+ * scanning for tasks. (Similar scans appear in helpQuiesce and
+ * pollScan.) Each scan traverses and tries to poll from each
+ * queue starting at a random index. Scans are not performed in
+ * ideal random permutation order, to reduce cacheline
+ * contention. The pseudorandom generator need not have
+ * high-quality statistical properties in the long term, but just
+ * within computations; We use Marsaglia XorShifts (often via
+ * ThreadLocalRandom.nextSecondarySeed), which are cheap and
+ * suffice. Scanning also includes contention reduction: When
+ * scanning workers fail to extract an apparently existing task,
+ * they soon restart at a different pseudorandom index. This form
+ * of backoff improves throughput when many threads are trying to
+ * take tasks from few queues, which can be common in some usages.
+ * Scans do not otherwise explicitly take into account core
+ * affinities, loads, cache localities, etc, However, they do
+ * exploit temporal locality (which usually approximates these) by
+ * preferring to re-poll from the same queue after a successful
+ * poll before trying others (see method topLevelExec). However
+ * this preference is bounded (see TOP_BOUND_SHIFT) as a safeguard
+ * against infinitely unfair looping under unbounded user task
+ * recursion, and also to reduce long-term contention when many
+ * threads poll few queues holding many small tasks. The bound is
+ * high enough to avoid much impact on locality and scheduling
+ * overhead.
*
* Trimming workers. To release resources after periods of lack of
* use, a worker starting to wait when the pool is quiescent will
- * time out and terminate (see awaitWork) if the pool has remained
- * quiescent for period given by IDLE_TIMEOUT_MS, increasing the
- * period as the number of threads decreases, eventually removing
- * all workers.
+ * time out and terminate (see method runWorker) if the pool has
+ * remained quiescent for period given by field keepAlive.
*
* Shutdown and Termination. A call to shutdownNow invokes
* tryTerminate to atomically set a runState bit. The calling
* thread, as well as every other worker thereafter terminating,
- * helps terminate others by setting their (qlock) status,
- * cancelling their unprocessed tasks, and waking them up, doing
- * so repeatedly until stable. Calls to non-abrupt shutdown()
- * preface this by checking whether termination should commence.
- * This relies primarily on the active count bits of "ctl"
- * maintaining consensus -- tryTerminate is called from awaitWork
- * whenever quiescent. However, external submitters do not take
- * part in this consensus. So, tryTerminate sweeps through queues
- * (until stable) to ensure lack of in-flight submissions and
- * workers about to process them before triggering the "STOP"
- * phase of termination. (Note: there is an intrinsic conflict if
- * helpQuiescePool is called when shutdown is enabled. Both wait
- * for quiescence, but tryTerminate is biased to not trigger until
- * helpQuiescePool completes.)
+ * helps terminate others by cancelling their unprocessed tasks,
+ * and waking them up, doing so repeatedly until stable. Calls to
+ * non-abrupt shutdown() preface this by checking whether
+ * termination should commence by sweeping through queues (until
+ * stable) to ensure lack of in-flight submissions and workers
+ * about to process them before triggering the "STOP" phase of
+ * termination.
*
* Joining Tasks
* =============
@@ -509,12 +514,12 @@
* Any of several actions may be taken when one worker is waiting
* to join a task stolen (or always held) by another. Because we
* are multiplexing many tasks on to a pool of workers, we can't
- * just let them block (as in Thread.join). We also cannot just
- * reassign the joiner's run-time stack with another and replace
- * it later, which would be a form of "continuation", that even if
- * possible is not necessarily a good idea since we may need both
- * an unblocked task and its continuation to progress. Instead we
- * combine two tactics:
+ * always just let them block (as in Thread.join). We also cannot
+ * just reassign the joiner's run-time stack with another and
+ * replace it later, which would be a form of "continuation", that
+ * even if possible is not necessarily a good idea since we may
+ * need both an unblocked task and its continuation to progress.
+ * Instead we combine two tactics:
*
* Helping: Arranging for the joiner to execute some task that it
* would be running if the steal had not occurred.
@@ -527,79 +532,44 @@
* helping a hypothetical compensator: If we can readily tell that
* a possible action of a compensator is to steal and execute the
* task being joined, the joining thread can do so directly,
- * without the need for a compensation thread (although at the
- * expense of larger run-time stacks, but the tradeoff is
- * typically worthwhile).
+ * without the need for a compensation thread.
*
* The ManagedBlocker extension API can't use helping so relies
* only on compensation in method awaitBlocker.
*
- * The algorithm in helpStealer entails a form of "linear
- * helping". Each worker records (in field currentSteal) the most
- * recent task it stole from some other worker (or a submission).
- * It also records (in field currentJoin) the task it is currently
- * actively joining. Method helpStealer uses these markers to try
- * to find a worker to help (i.e., steal back a task from and
- * execute it) that could hasten completion of the actively joined
- * task. Thus, the joiner executes a task that would be on its
- * own local deque had the to-be-joined task not been stolen. This
- * is a conservative variant of the approach described in Wagner &
- * Calder "Leapfrogging: a portable technique for implementing
- * efficient futures" SIGPLAN Notices, 1993
- * (http://portal.acm.org/citation.cfm?id=155354). It differs in
- * that: (1) We only maintain dependency links across workers upon
- * steals, rather than use per-task bookkeeping. This sometimes
- * requires a linear scan of workQueues array to locate stealers,
- * but often doesn't because stealers leave hints (that may become
- * stale/wrong) of where to locate them. It is only a hint
- * because a worker might have had multiple steals and the hint
- * records only one of them (usually the most current). Hinting
- * isolates cost to when it is needed, rather than adding to
- * per-task overhead. (2) It is "shallow", ignoring nesting and
- * potentially cyclic mutual steals. (3) It is intentionally
- * racy: field currentJoin is updated only while actively joining,
- * which means that we miss links in the chain during long-lived
- * tasks, GC stalls etc (which is OK since blocking in such cases
- * is usually a good idea). (4) We bound the number of attempts
- * to find work using checksums and fall back to suspending the
- * worker and if necessary replacing it with another.
+ * The algorithm in awaitJoin entails a form of "linear helping".
+ * Each worker records (in field source) the id of the queue from
+ * which it last stole a task. The scan in method awaitJoin uses
+ * these markers to try to find a worker to help (i.e., steal back
+ * a task from and execute it) that could hasten completion of the
+ * actively joined task. Thus, the joiner executes a task that
+ * would be on its own local deque if the to-be-joined task had
+ * not been stolen. This is a conservative variant of the approach
+ * described in Wagner & Calder "Leapfrogging: a portable
+ * technique for implementing efficient futures" SIGPLAN Notices,
+ * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
+ * mainly in that we only record queue ids, not full dependency
+ * links. This requires a linear scan of the workQueues array to
+ * locate stealers, but isolates cost to when it is needed, rather
+ * than adding to per-task overhead. Searches can fail to locate
+ * stealers GC stalls and the like delay recording sources.
+ * Further, even when accurately identified, stealers might not
+ * ever produce a task that the joiner can in turn help with. So,
+ * compensation is tried upon failure to find tasks to run.
*
- * Helping actions for CountedCompleters do not require tracking
- * currentJoins: Method helpComplete takes and executes any task
- * with the same root as the task being waited on (preferring
- * local pops to non-local polls). However, this still entails
- * some traversal of completer chains, so is less efficient than
- * using CountedCompleters without explicit joins.
- *
- * Compensation does not aim to keep exactly the target
+ * Compensation does not by default aim to keep exactly the target
* parallelism number of unblocked threads running at any given
* time. Some previous versions of this class employed immediate
* compensations for any blocked join. However, in practice, the
* vast majority of blockages are transient byproducts of GC and
- * other JVM or OS activities that are made worse by replacement.
- * Currently, compensation is attempted only after validating that
- * all purportedly active threads are processing tasks by checking
- * field WorkQueue.scanState, which eliminates most false
- * positives. Also, compensation is bypassed (tolerating fewer
- * threads) in the most common case in which it is rarely
- * beneficial: when a worker with an empty queue (thus no
- * continuation tasks) blocks on a join and there still remain
- * enough threads to ensure liveness.
- *
- * Spare threads are removed as soon as they notice that the
- * target parallelism level has been exceeded, in method
- * tryDropSpare. (Method scan arranges returns for rechecks upon
- * each probe via the "bound" parameter.)
- *
- * The compensation mechanism may be bounded. Bounds for the
+ * other JVM or OS activities that are made worse by replacement
+ * when they cause longer-term oversubscription. Rather than
+ * impose arbitrary policies, we allow users to override the
+ * default of only adding threads upon apparent starvation. The
+ * compensation mechanism may also be bounded. Bounds for the
* commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
* with programming errors and abuse before running out of
- * resources to do so. In other cases, users may supply factories
- * that limit thread construction. The effects of bounding in this
- * pool (like all others) is imprecise. Total worker counts are
- * decremented when threads deregister, not when they exit and
- * resources are reclaimed by the JVM and OS. So the number of
- * simultaneously live threads may transiently exceed bounds.
+ * resources to do so.
*
* Common Pool
* ===========
@@ -607,9 +577,7 @@
* The static common pool always exists after static
* initialization. Since it (or any other created pool) need
* never be used, we minimize initial construction overhead and
- * footprint to the setup of about a dozen fields, with no nested
- * allocation. Most bootstrapping occurs within method
- * externalSubmit during the first submission to the pool.
+ * footprint to the setup of about a dozen fields.
*
* When external threads submit to the common pool, they can
* perform subtask processing (see externalHelpComplete and
@@ -629,31 +597,39 @@
* InnocuousForkJoinWorkerThread when there is a SecurityManager
* present. These workers have no permissions set, do not belong
* to any user-defined ThreadGroup, and erase all ThreadLocals
- * after executing any top-level task (see WorkQueue.runTask).
- * The associated mechanics (mainly in ForkJoinWorkerThread) may
- * be JVM-dependent and must access particular Thread class fields
- * to achieve this effect.
+ * after executing any top-level task (see
+ * WorkQueue.afterTopLevelExec). The associated mechanics (mainly
+ * in ForkJoinWorkerThread) may be JVM-dependent and must access
+ * particular Thread class fields to achieve this effect.
+ *
+ * Memory placement
+ * ================
+ *
+ * Performance can be very sensitive to placement of instances of
+ * ForkJoinPool and WorkQueues and their queue arrays. To reduce
+ * false-sharing impact, the @Contended annotation isolates
+ * adjacent WorkQueue instances, as well as the ForkJoinPool.ctl
+ * field. WorkQueue arrays are allocated (by their threads) with
+ * larger initial sizes than most ever need, mostly to reduce
+ * false sharing with current garbage collectors that use cardmark
+ * tables.
*
* Style notes
* ===========
*
- * Memory ordering relies mainly on Unsafe intrinsics that carry
- * the further responsibility of explicitly performing null- and
- * bounds- checks otherwise carried out implicitly by JVMs. This
- * can be awkward and ugly, but also reflects the need to control
+ * Memory ordering relies mainly on VarHandles. This can be
+ * awkward and ugly, but also reflects the need to control
* outcomes across the unusual cases that arise in very racy code
- * with very few invariants. So these explicit checks would exist
- * in some form anyway. All fields are read into locals before
- * use, and null-checked if they are references. This is usually
- * done in a "C"-like style of listing declarations at the heads
- * of methods or blocks, and using inline assignments on first
- * encounter. Array bounds-checks are usually performed by
- * masking with array.length-1, which relies on the invariant that
- * these arrays are created with positive lengths, which is itself
- * paranoically checked. Nearly all explicit checks lead to
- * bypass/return, not exception throws, because they may
- * legitimately arise due to cancellation/revocation during
- * shutdown.
+ * with very few invariants. All fields are read into locals
+ * before use, and null-checked if they are references. Array
+ * accesses using masked indices include checks (that are always
+ * true) that the array length is non-zero to avoid compilers
+ * inserting more expensive traps. This is usually done in a
+ * "C"-like style of listing declarations at the heads of methods
+ * or blocks, and using inline assignments on first encounter.
+ * Nearly all explicit checks lead to bypass/return, not exception
+ * throws, because they may legitimately arise due to
+ * cancellation/revocation during shutdown.
*
* There is a lot of representation-level coupling among classes
* ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask. The
@@ -663,10 +639,11 @@
* representations will need to be accompanied by algorithmic
* changes anyway. Several methods intrinsically sprawl because
* they must accumulate sets of consistent reads of fields held in
- * local variables. There are also other coding oddities
- * (including several unnecessary-looking hoisted null checks)
- * that help some methods perform reasonably even when interpreted
- * (not compiled).
+ * local variables. Some others are artificially broken up to
+ * reduce producer/consumer imbalances due to dynamic compilation.
+ * There are also other coding oddities (including several
+ * unnecessary-looking hoisted null checks) that help some methods
+ * perform reasonably even when interpreted (not compiled).
*
* The order of declarations in this file is (with a few exceptions):
* (1) Static utility functions
@@ -702,6 +679,13 @@
public static interface ForkJoinWorkerThreadFactory {
/**
* Returns a new worker thread operating in the given pool.
+ * Returning null or throwing an exception may result in tasks
+ * never being executed. If this method throws an exception,
+ * it is relayed to the caller of the method (for example
+ * {@code execute}) causing attempted thread creation. If this
+ * method returns null or throws an exception, it is not
+ * retried until the next attempted creation (for example
+ * another call to {@code execute}).
*
* @param pool the pool this thread works in
* @return the new worker thread, or {@code null} if the request
@@ -711,120 +695,97 @@
public ForkJoinWorkerThread newThread(ForkJoinPool pool);
}
+ static AccessControlContext contextWithPermissions(Permission ... perms) {
+ Permissions permissions = new Permissions();
+ for (Permission perm : perms)
+ permissions.add(perm);
+ return new AccessControlContext(
+ new ProtectionDomain[] { new ProtectionDomain(null, permissions) });
+ }
+
/**
* Default ForkJoinWorkerThreadFactory implementation; creates a
- * new ForkJoinWorkerThread.
+ * new ForkJoinWorkerThread using the system class loader as the
+ * thread context class loader.
*/
private static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
+ private static final AccessControlContext ACC = contextWithPermissions(
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
+
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
- return new ForkJoinWorkerThread(pool);
+ return AccessController.doPrivileged(
+ new PrivilegedAction<>() {
+ public ForkJoinWorkerThread run() {
+ return new ForkJoinWorkerThread(
+ pool, ClassLoader.getSystemClassLoader()); }},
+ ACC);
}
}
- /**
- * Class for artificial tasks that are used to replace the target
- * of local joins if they are removed from an interior queue slot
- * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
- * actually do anything beyond having a unique identity.
- */
- private static final class EmptyTask extends ForkJoinTask<Void> {
- private static final long serialVersionUID = -7721805057305804111L;
- EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
- public final Void getRawResult() { return null; }
- public final void setRawResult(Void x) {}
- public final boolean exec() { return true; }
- }
-
- /**
- * Additional fields and lock created upon initialization.
- */
- private static final class AuxState extends ReentrantLock {
- private static final long serialVersionUID = -6001602636862214147L;
- volatile long stealCount; // cumulative steal count
- long indexSeed; // index bits for registerWorker
- AuxState() {}
- }
-
// Constants shared across ForkJoinPool and WorkQueue
// Bounds
+ static final int SWIDTH = 16; // width of short
static final int SMASK = 0xffff; // short bits == max index
static final int MAX_CAP = 0x7fff; // max #workers - 1
- static final int EVENMASK = 0xfffe; // even short bits
static final int SQMASK = 0x007e; // max 64 (even) slots
- // Masks and units for WorkQueue.scanState and ctl sp subfield
+ // Masks and units for WorkQueue.phase and ctl sp subfield
static final int UNSIGNALLED = 1 << 31; // must be negative
static final int SS_SEQ = 1 << 16; // version count
+ static final int QLOCK = 1; // must be 1
- // Mode bits for ForkJoinPool.config and WorkQueue.config
- static final int MODE_MASK = 0xffff << 16; // top half of int
- static final int SPARE_WORKER = 1 << 17; // set if tc > 0 on creation
- static final int UNREGISTERED = 1 << 18; // to skip some of deregister
- static final int FIFO_QUEUE = 1 << 31; // must be negative
- static final int LIFO_QUEUE = 0; // for clarity
- static final int IS_OWNED = 1; // low bit 0 if shared
+ // Mode bits and sentinels, some also used in WorkQueue id and.source fields
+ static final int OWNED = 1; // queue has owner thread
+ static final int FIFO = 1 << 16; // fifo queue or access mode
+ static final int SHUTDOWN = 1 << 18;
+ static final int TERMINATED = 1 << 19;
+ static final int STOP = 1 << 31; // must be negative
+ static final int QUIET = 1 << 30; // not scanning or working
+ static final int DORMANT = QUIET | UNSIGNALLED;
/**
- * The maximum number of task executions from the same queue
- * before checking other queues, bounding unfairness and impact of
- * infinite user task recursion. Must be a power of two minus 1.
+ * Initial capacity of work-stealing queue array.
+ * Must be a power of two, at least 2.
*/
- static final int POLL_LIMIT = (1 << 10) - 1;
+ static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+ /**
+ * Maximum capacity for queue arrays. Must be a power of two less
+ * than or equal to 1 << (31 - width of array entry) to ensure
+ * lack of wraparound of index calculations, but defined to a
+ * value a bit less than this to help users trap runaway programs
+ * before saturating systems.
+ */
+ static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+ /**
+ * The maximum number of top-level polls per worker before
+ * checking other queues, expressed as a bit shift to, in effect,
+ * multiply by pool size, and then use as random value mask, so
+ * average bound is about poolSize*(1<<TOP_BOUND_SHIFT). See
+ * above for rationale.
+ */
+ static final int TOP_BOUND_SHIFT = 10;
/**
* Queues supporting work-stealing as well as external task
* submission. See above for descriptions and algorithms.
- * Performance on most platforms is very sensitive to placement of
- * instances of both WorkQueues and their arrays -- we absolutely
- * do not want multiple WorkQueue instances or multiple queue
- * arrays sharing cache lines. The @Contended annotation alerts
- * JVMs to try to keep instances apart.
*/
- // Android-removed: @Contended, this hint is not used by the Android runtime.
- //@jdk.internal.vm.annotation.Contended
+ @jdk.internal.vm.annotation.Contended
static final class WorkQueue {
-
- /**
- * Capacity of work-stealing queue array upon initialization.
- * Must be a power of two; at least 4, but should be larger to
- * reduce or eliminate cacheline sharing among queues.
- * Currently, it is much larger, as a partial workaround for
- * the fact that JVMs often place arrays in locations that
- * share GC bookkeeping (especially cardmarks) such that
- * per-write accesses encounter serious memory contention.
- */
- static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
-
- /**
- * Maximum size for queue arrays. Must be a power of two less
- * than or equal to 1 << (31 - width of array entry) to ensure
- * lack of wraparound of index calculations, but defined to a
- * value a bit less than this to help users trap runaway
- * programs before saturating systems.
- */
- static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
-
- // Instance fields
-
- volatile int scanState; // versioned, negative if inactive
- int stackPred; // pool stack (ctl) predecessor
- int nsteals; // number of steals
- int hint; // randomization and stealer index hint
- int config; // pool index and mode
- volatile int qlock; // 1: locked, < 0: terminate; else 0
- volatile int base; // index of next slot for poll
+ volatile int source; // source queue id, or sentinel
+ int id; // pool index, mode, tag
+ int base; // index of next slot for poll
int top; // index of next slot for push
- ForkJoinTask<?>[] array; // the elements (initially unallocated)
+ volatile int phase; // versioned, negative: queued, 1: locked
+ int stackPred; // pool stack (ctl) predecessor link
+ int nsteals; // number of steals
+ ForkJoinTask<?>[] array; // the queued tasks; power of 2 size
final ForkJoinPool pool; // the containing pool (may be null)
final ForkJoinWorkerThread owner; // owning thread or null if shared
- volatile Thread parker; // == owner during call to park; else null
- volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
-
- // Android-removed: @Contended, this hint is not used by the Android runtime.
- // @jdk.internal.vm.annotation.Contended("group2") // segregate
- volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
this.pool = pool;
@@ -834,17 +795,28 @@
}
/**
+ * Tries to lock shared queue by CASing phase field.
+ */
+ final boolean tryLockPhase() {
+ return PHASE.compareAndSet(this, 0, 1);
+ }
+
+ final void releasePhaseLock() {
+ PHASE.setRelease(this, 0);
+ }
+
+ /**
* Returns an exportable index (used by ForkJoinWorkerThread).
*/
final int getPoolIndex() {
- return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+ return (id & 0xffff) >>> 1; // ignore odd/even tag bit
}
/**
* Returns the approximate number of tasks in the queue.
*/
final int queueSize() {
- int n = base - top; // read base first
+ int n = (int)BASE.getAcquire(this) - top;
return (n >= 0) ? 0 : -n; // ignore transient negative
}
@@ -854,11 +826,12 @@
* near-empty queue has at least one unclaimed task.
*/
final boolean isEmpty() {
- ForkJoinTask<?>[] a; int n, al, s;
- return ((n = base - (s = top)) >= 0 || // possibly one task
+ ForkJoinTask<?>[] a; int n, cap, b;
+ VarHandle.acquireFence(); // needed by external callers
+ return ((n = (b = base) - top) >= 0 || // possibly one task
(n == -1 && ((a = array) == null ||
- (al = a.length) == 0 ||
- a[(al - 1) & (s - 1)] == null)));
+ (cap = a.length) == 0 ||
+ a[(cap - 1) & b] == null)));
}
/**
@@ -868,116 +841,99 @@
* @throws RejectedExecutionException if array cannot be resized
*/
final void push(ForkJoinTask<?> task) {
- U.storeFence(); // ensure safe publication
- int s = top, al, d; ForkJoinTask<?>[] a;
- if ((a = array) != null && (al = a.length) > 0) {
- a[(al - 1) & s] = task; // relaxed writes OK
+ ForkJoinTask<?>[] a;
+ int s = top, d, cap, m;
+ ForkJoinPool p = pool;
+ if ((a = array) != null && (cap = a.length) > 0) {
+ QA.setRelease(a, (m = cap - 1) & s, task);
top = s + 1;
- ForkJoinPool p = pool;
- if ((d = base - s) == 0 && p != null) {
- U.fullFence();
+ if (((d = s - (int)BASE.getAcquire(this)) & ~1) == 0 &&
+ p != null) { // size 0 or 1
+ VarHandle.fullFence();
p.signalWork();
}
- else if (al + d == 1)
- growArray();
+ else if (d == m)
+ growArray(false);
}
}
/**
- * Initializes or doubles the capacity of array. Call either
- * by owner or with lock held -- it is OK for base, but not
- * top, to move while resizings are in progress.
+ * Version of push for shared queues. Call only with phase lock held.
+ * @return true if should signal work
*/
- final ForkJoinTask<?>[] growArray() {
- ForkJoinTask<?>[] oldA = array;
- int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
- if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
+ final boolean lockedPush(ForkJoinTask<?> task) {
+ ForkJoinTask<?>[] a;
+ boolean signal = false;
+ int s = top, b = base, cap, d;
+ if ((a = array) != null && (cap = a.length) > 0) {
+ a[(cap - 1) & s] = task;
+ top = s + 1;
+ if (b - s + cap - 1 == 0)
+ growArray(true);
+ else {
+ phase = 0; // full volatile unlock
+ if (((s - base) & ~1) == 0) // size 0 or 1
+ signal = true;
+ }
+ }
+ return signal;
+ }
+
+ /**
+ * Doubles the capacity of array. Call either by owner or with
+ * lock held -- it is OK for base, but not top, to move while
+ * resizings are in progress.
+ */
+ final void growArray(boolean locked) {
+ ForkJoinTask<?>[] newA = null;
+ try {
+ ForkJoinTask<?>[] oldA; int oldSize, newSize;
+ if ((oldA = array) != null && (oldSize = oldA.length) > 0 &&
+ (newSize = oldSize << 1) <= MAXIMUM_QUEUE_CAPACITY &&
+ newSize > 0) {
+ try {
+ newA = new ForkJoinTask<?>[newSize];
+ } catch (OutOfMemoryError ex) {
+ }
+ if (newA != null) { // poll from old array, push to new
+ int oldMask = oldSize - 1, newMask = newSize - 1;
+ for (int s = top - 1, k = oldMask; k >= 0; --k) {
+ ForkJoinTask<?> x = (ForkJoinTask<?>)
+ QA.getAndSet(oldA, s & oldMask, null);
+ if (x != null)
+ newA[s-- & newMask] = x;
+ else
+ break;
+ }
+ array = newA;
+ VarHandle.releaseFence();
+ }
+ }
+ } finally {
+ if (locked)
+ phase = 0;
+ }
+ if (newA == null)
throw new RejectedExecutionException("Queue capacity exceeded");
- int oldMask, t, b;
- ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
- if (oldA != null && (oldMask = oldA.length - 1) > 0 &&
- (t = top) - (b = base) > 0) {
- int mask = size - 1;
- do { // emulate poll from old array, push to new array
- int index = b & oldMask;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> x = (ForkJoinTask<?>)
- U.getObjectVolatile(oldA, offset);
- if (x != null &&
- U.compareAndSwapObject(oldA, offset, x, null))
- a[b & mask] = x;
- } while (++b != t);
- U.storeFence();
- }
- return a;
- }
-
- /**
- * Takes next task, if one exists, in LIFO order. Call only
- * by owner in unshared queues.
- */
- final ForkJoinTask<?> pop() {
- int b = base, s = top, al, i; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & --s;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getObject(a, offset);
- if (t != null &&
- U.compareAndSwapObject(a, offset, t, null)) {
- top = s;
- return t;
- }
- }
- return null;
- }
-
- /**
- * Takes a task in FIFO order if b is base of queue and a task
- * can be claimed without contention. Specialized versions
- * appear in ForkJoinPool methods scan and helpStealer.
- */
- final ForkJoinTask<?> pollAt(int b) {
- ForkJoinTask<?>[] a; int al;
- if ((a = array) != null && (al = a.length) > 0) {
- int index = (al - 1) & b;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (t != null && b++ == base &&
- U.compareAndSwapObject(a, offset, t, null)) {
- base = b;
- return t;
- }
- }
- return null;
}
/**
* Takes next task, if one exists, in FIFO order.
*/
final ForkJoinTask<?> poll() {
- for (;;) {
- int b = base, s = top, d, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && (d = b - s) < 0 &&
- (al = a.length) > 0) {
- int index = (al - 1) & b;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (b++ == base) {
- if (t != null) {
- if (U.compareAndSwapObject(a, offset, t, null)) {
- base = b;
- return t;
- }
- }
- else if (d == -1)
- break; // now empty
+ int b, k, cap; ForkJoinTask<?>[] a;
+ while ((a = array) != null && (cap = a.length) > 0 &&
+ top - (b = base) > 0) {
+ ForkJoinTask<?> t = (ForkJoinTask<?>)
+ QA.getAcquire(a, k = (cap - 1) & b);
+ if (base == b++) {
+ if (t == null)
+ Thread.yield(); // await index advance
+ else if (QA.compareAndSet(a, k, t, null)) {
+ BASE.setOpaque(this, b);
+ return t;
}
}
- else
- break;
}
return null;
}
@@ -986,96 +942,59 @@
* Takes next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> nextLocalTask() {
- return (config < 0) ? poll() : pop();
+ ForkJoinTask<?> t = null;
+ int md = id, b, s, d, cap; ForkJoinTask<?>[] a;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ (d = (s = top) - (b = base)) > 0) {
+ if ((md & FIFO) == 0 || d == 1) {
+ if ((t = (ForkJoinTask<?>)
+ QA.getAndSet(a, (cap - 1) & --s, null)) != null)
+ TOP.setOpaque(this, s);
+ }
+ else if ((t = (ForkJoinTask<?>)
+ QA.getAndSet(a, (cap - 1) & b++, null)) != null) {
+ BASE.setOpaque(this, b);
+ }
+ else // on contention in FIFO mode, use regular poll
+ t = poll();
+ }
+ return t;
}
/**
* Returns next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> peek() {
- int al; ForkJoinTask<?>[] a;
- return ((a = array) != null && (al = a.length) > 0) ?
- a[(al - 1) & (config < 0 ? base : top - 1)] : null;
+ int cap; ForkJoinTask<?>[] a;
+ return ((a = array) != null && (cap = a.length) > 0) ?
+ a[(cap - 1) & ((id & FIFO) != 0 ? base : top - 1)] : null;
}
/**
* Pops the given task only if it is at the current top.
*/
final boolean tryUnpush(ForkJoinTask<?> task) {
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & --s;
- long offset = ((long)index << ASHIFT) + ABASE;
- if (U.compareAndSwapObject(a, offset, task, null)) {
- top = s;
- return true;
- }
- }
- return false;
- }
-
- /**
- * Shared version of push. Fails if already locked.
- *
- * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty
- */
- final int sharedPush(ForkJoinTask<?> task) {
- int stat;
- if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
- int b = base, s = top, al, d; ForkJoinTask<?>[] a;
- if ((a = array) != null && (al = a.length) > 0 &&
- al - 1 + (d = b - s) > 0) {
- a[(al - 1) & s] = task;
- top = s + 1; // relaxed writes OK here
- qlock = 0;
- stat = (d < 0 && b == base) ? d : 0;
- }
- else {
- growAndSharedPush(task);
- stat = 0;
- }
- }
- else
- stat = 1;
- return stat;
- }
-
- /**
- * Helper for sharedPush; called only when locked and resize
- * needed.
- */
- private void growAndSharedPush(ForkJoinTask<?> task) {
- try {
- growArray();
- int s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && (al = a.length) > 0) {
- a[(al - 1) & s] = task;
- top = s + 1;
- }
- } finally {
- qlock = 0;
- }
+ boolean popped = false;
+ int s, cap; ForkJoinTask<?>[] a;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ (s = top) != base &&
+ (popped = QA.compareAndSet(a, (cap - 1) & --s, task, null)))
+ TOP.setOpaque(this, s);
+ return popped;
}
/**
* Shared version of tryUnpush.
*/
- final boolean trySharedUnpush(ForkJoinTask<?> task) {
+ final boolean tryLockedUnpush(ForkJoinTask<?> task) {
boolean popped = false;
- int s = top - 1, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && (al = a.length) > 0) {
- int index = (al - 1) & s;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset);
- if (t == task &&
- U.compareAndSwapInt(this, QLOCK, 0, 1)) {
- if (top == s + 1 && array == a &&
- U.compareAndSwapObject(a, offset, task, null)) {
- popped = true;
- top = s;
- }
- U.putOrderedInt(this, QLOCK, 0);
- }
+ int s = top - 1, k, cap; ForkJoinTask<?>[] a;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ a[k = (cap - 1) & s] == task && tryLockPhase()) {
+ if (top == s + 1 && array == a &&
+ (popped = QA.compareAndSet(a, k, task, null)))
+ top = s;
+ releasePhaseLock();
}
return popped;
}
@@ -1084,252 +1003,150 @@
* Removes and cancels all known tasks, ignoring any exceptions.
*/
final void cancelAll() {
- ForkJoinTask<?> t;
- if ((t = currentJoin) != null) {
- currentJoin = null;
- ForkJoinTask.cancelIgnoringExceptions(t);
- }
- if ((t = currentSteal) != null) {
- currentSteal = null;
- ForkJoinTask.cancelIgnoringExceptions(t);
- }
- while ((t = poll()) != null)
+ for (ForkJoinTask<?> t; (t = poll()) != null; )
ForkJoinTask.cancelIgnoringExceptions(t);
}
// Specialized execution methods
/**
- * Pops and executes up to POLL_LIMIT tasks or until empty.
+ * Runs the given (stolen) task if nonnull, as well as
+ * remaining local tasks and others available from the given
+ * queue, up to bound n (to avoid infinite unfairness).
*/
- final void localPopAndExec() {
- for (int nexec = 0;;) {
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & --s;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getAndSetObject(a, offset, null);
- if (t != null) {
- top = s;
- (currentSteal = t).doExec();
- if (++nexec > POLL_LIMIT)
- break;
- }
- else
+ final void topLevelExec(ForkJoinTask<?> t, WorkQueue q, int n) {
+ if (t != null && q != null) { // hoist checks
+ int nstolen = 1;
+ for (;;) {
+ t.doExec();
+ if (n-- < 0)
break;
- }
- else
- break;
- }
- }
-
- /**
- * Polls and executes up to POLL_LIMIT tasks or until empty.
- */
- final void localPollAndExec() {
- for (int nexec = 0;;) {
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & b++;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getAndSetObject(a, offset, null);
- if (t != null) {
- base = b;
- t.doExec();
- if (++nexec > POLL_LIMIT)
+ else if ((t = nextLocalTask()) == null) {
+ if ((t = q.poll()) == null)
break;
+ else
+ ++nstolen;
}
}
- else
- break;
- }
- }
-
- /**
- * Executes the given task and (some) remaining local tasks.
- */
- final void runTask(ForkJoinTask<?> task) {
- if (task != null) {
- task.doExec();
- if (config < 0)
- localPollAndExec();
- else
- localPopAndExec();
- int ns = ++nsteals;
ForkJoinWorkerThread thread = owner;
- currentSteal = null;
- if (ns < 0) // collect on overflow
- transferStealCount(pool);
+ nsteals += nstolen;
+ source = 0;
if (thread != null)
thread.afterTopLevelExec();
}
}
/**
- * Adds steal count to pool steal count if it exists, and resets.
+ * If present, removes task from queue and executes it.
*/
- final void transferStealCount(ForkJoinPool p) {
- AuxState aux;
- if (p != null && (aux = p.auxState) != null) {
- long s = nsteals;
- nsteals = 0; // if negative, correct for overflow
- if (s < 0) s = Integer.MAX_VALUE;
- aux.lock();
- try {
- aux.stealCount += s;
- } finally {
- aux.unlock();
- }
- }
- }
-
- /**
- * If present, removes from queue and executes the given task,
- * or any other cancelled task. Used only by awaitJoin.
- *
- * @return true if queue empty and task not known to be done
- */
- final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
- if (task != null && task.status >= 0) {
- int b, s, d, al; ForkJoinTask<?>[] a;
- while ((d = (b = base) - (s = top)) < 0 &&
- (a = array) != null && (al = a.length) > 0) {
- for (;;) { // traverse from s to b
- int index = --s & (al - 1);
- long offset = (index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (t == null)
- break; // restart
- else if (t == task) {
- boolean removed = false;
- if (s + 1 == top) { // pop
- if (U.compareAndSwapObject(a, offset, t, null)) {
- top = s;
- removed = true;
- }
+ final void tryRemoveAndExec(ForkJoinTask<?> task) {
+ ForkJoinTask<?>[] a; int s, cap;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ (s = top) - base > 0) { // traverse from top
+ for (int m = cap - 1, ns = s - 1, i = ns; ; --i) {
+ int index = i & m;
+ ForkJoinTask<?> t = (ForkJoinTask<?>)QA.get(a, index);
+ if (t == null)
+ break;
+ else if (t == task) {
+ if (QA.compareAndSet(a, index, t, null)) {
+ top = ns; // safely shift down
+ for (int j = i; j != ns; ++j) {
+ ForkJoinTask<?> f;
+ int pindex = (j + 1) & m;
+ f = (ForkJoinTask<?>)QA.get(a, pindex);
+ QA.setVolatile(a, pindex, null);
+ int jindex = j & m;
+ QA.setRelease(a, jindex, f);
}
- else if (base == b) // replace with proxy
- removed = U.compareAndSwapObject(a, offset, t,
- new EmptyTask());
- if (removed) {
- ForkJoinTask<?> ps = currentSteal;
- (currentSteal = task).doExec();
- currentSteal = ps;
- }
- break;
+ VarHandle.releaseFence();
+ t.doExec();
}
- else if (t.status < 0 && s + 1 == top) {
- if (U.compareAndSwapObject(a, offset, t, null)) {
- top = s;
- }
- break; // was cancelled
- }
- else if (++d == 0) {
- if (base != b) // rescan
- break;
- return false;
- }
+ break;
}
- if (task.status < 0)
- return false;
}
}
- return true;
}
/**
- * Pops task if in the same CC computation as the given task,
- * in either shared or owned mode. Used only by helpComplete.
+ * Tries to pop and run tasks within the target's computation
+ * until done, not found, or limit exceeded.
+ *
+ * @param task root of CountedCompleter computation
+ * @param limit max runs, or zero for no limit
+ * @param shared true if must lock to extract task
+ * @return task status on exit
*/
- final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & (s - 1);
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> o = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (o instanceof CountedCompleter) {
- CountedCompleter<?> t = (CountedCompleter<?>)o;
- for (CountedCompleter<?> r = t;;) {
- if (r == task) {
- if ((mode & IS_OWNED) == 0) {
- boolean popped = false;
- if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+ final int helpCC(CountedCompleter<?> task, int limit, boolean shared) {
+ int status = 0;
+ if (task != null && (status = task.status) >= 0) {
+ int s, k, cap; ForkJoinTask<?>[] a;
+ while ((a = array) != null && (cap = a.length) > 0 &&
+ (s = top) - base > 0) {
+ CountedCompleter<?> v = null;
+ ForkJoinTask<?> o = a[k = (cap - 1) & (s - 1)];
+ if (o instanceof CountedCompleter) {
+ CountedCompleter<?> t = (CountedCompleter<?>)o;
+ for (CountedCompleter<?> f = t;;) {
+ if (f != task) {
+ if ((f = f.completer) == null)
+ break;
+ }
+ else if (shared) {
+ if (tryLockPhase()) {
if (top == s && array == a &&
- U.compareAndSwapObject(a, offset,
- t, null)) {
- popped = true;
+ QA.compareAndSet(a, k, t, null)) {
top = s - 1;
+ v = t;
}
- U.putOrderedInt(this, QLOCK, 0);
- if (popped)
- return t;
+ releasePhaseLock();
}
+ break;
}
- else if (U.compareAndSwapObject(a, offset,
- t, null)) {
- top = s - 1;
- return t;
+ else {
+ if (QA.compareAndSet(a, k, t, null)) {
+ top = s - 1;
+ v = t;
+ }
+ break;
}
- break;
}
- else if ((r = r.completer) == null) // try parent
- break;
}
+ if (v != null)
+ v.doExec();
+ if ((status = task.status) < 0 || v == null ||
+ (limit != 0 && --limit == 0))
+ break;
}
}
- return null;
+ return status;
}
/**
- * Steals and runs a task in the same CC computation as the
- * given task if one exists and can be taken without
- * contention. Otherwise returns a checksum/control value for
- * use by method helpComplete.
+ * Tries to poll and run AsynchronousCompletionTasks until
+ * none found or blocker is released
*
- * @return 1 if successful, 2 if retryable (lost to another
- * stealer), -1 if non-empty but no matching task found, else
- * the base index, forced negative.
+ * @param blocker the blocker
*/
- final int pollAndExecCC(CountedCompleter<?> task) {
- ForkJoinTask<?>[] a;
- int b = base, s = top, al, h;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & b;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> o = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (o == null)
- h = 2; // retryable
- else if (!(o instanceof CountedCompleter))
- h = -1; // unmatchable
- else {
- CountedCompleter<?> t = (CountedCompleter<?>)o;
- for (CountedCompleter<?> r = t;;) {
- if (r == task) {
- if (b++ == base &&
- U.compareAndSwapObject(a, offset, t, null)) {
- base = b;
- t.doExec();
- h = 1; // success
- }
- else
- h = 2; // lost CAS
+ final void helpAsyncBlocker(ManagedBlocker blocker) {
+ if (blocker != null) {
+ int b, k, cap; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+ while ((a = array) != null && (cap = a.length) > 0 &&
+ top - (b = base) > 0) {
+ t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+ if (blocker.isReleasable())
+ break;
+ else if (base == b++ && t != null) {
+ if (!(t instanceof CompletableFuture.
+ AsynchronousCompletionTask))
break;
- }
- else if ((r = r.completer) == null) {
- h = -1; // unmatched
- break;
+ else if (QA.compareAndSet(a, k, t, null)) {
+ BASE.setOpaque(this, b);
+ t.doExec();
}
}
}
}
- else
- h = b | Integer.MIN_VALUE; // to sense movement on re-poll
- return h;
}
/**
@@ -1337,29 +1154,24 @@
*/
final boolean isApparentlyUnblocked() {
Thread wt; Thread.State s;
- return (scanState >= 0 &&
- (wt = owner) != null &&
+ return ((wt = owner) != null &&
(s = wt.getState()) != Thread.State.BLOCKED &&
s != Thread.State.WAITING &&
s != Thread.State.TIMED_WAITING);
}
- // Unsafe mechanics. Note that some are (and must be) the same as in FJP
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long QLOCK;
- private static final int ABASE;
- private static final int ASHIFT;
+ // VarHandle mechanics.
+ static final VarHandle PHASE;
+ static final VarHandle BASE;
+ static final VarHandle TOP;
static {
try {
- QLOCK = U.objectFieldOffset
- (WorkQueue.class.getDeclaredField("qlock"));
- ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
- int scale = U.arrayIndexScale(ForkJoinTask[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PHASE = l.findVarHandle(WorkQueue.class, "phase", int.class);
+ BASE = l.findVarHandle(WorkQueue.class, "base", int.class);
+ TOP = l.findVarHandle(WorkQueue.class, "top", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -1375,7 +1187,7 @@
/**
* Permission required for callers of methods that may start or
- * kill threads. Also used as a static lock in tryInitialize.
+ * kill threads.
*/
static final RuntimePermission modifyThreadPermission;
@@ -1416,18 +1228,15 @@
// static configuration constants
/**
- * Initial timeout value (in milliseconds) for the thread
- * triggering quiescence to park waiting for new work. On timeout,
- * the thread will instead try to shrink the number of workers.
- * The value should be large enough to avoid overly aggressive
- * shrinkage during most transient stalls (long GCs etc).
+ * Default idle timeout value (in milliseconds) for the thread
+ * triggering quiescence to park waiting for new work
*/
- private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec
+ private static final long DEFAULT_KEEPALIVE = 60_000L;
/**
- * Tolerance for idle timeouts, to cope with timer undershoots.
+ * Undershoot tolerance for idle timeouts
*/
- private static final long TIMEOUT_SLOP_MS = 20L; // 20ms
+ private static final long TIMEOUT_SLOP = 20L;
/**
* The default value for COMMON_MAX_SPARES. Overridable using the
@@ -1447,7 +1256,7 @@
/*
* Bits and masks for field ctl, packed with 4 16 bit subfields:
- * AC: Number of active running workers minus target parallelism
+ * RC: Number of released (unqueued) workers minus target parallelism
* TC: Number of total workers minus target parallelism
* SS: version count and status of top waiting thread
* ID: poolIndex of top of Treiber stack of waiters
@@ -1456,26 +1265,30 @@
* (including version bits) as sp=(int)ctl. The offsets of counts
* by the target parallelism and the positionings of fields makes
* it possible to perform the most common checks via sign tests of
- * fields: When ac is negative, there are not enough active
+ * fields: When ac is negative, there are not enough unqueued
* workers, when tc is negative, there are not enough total
* workers. When sp is non-zero, there are waiting workers. To
* deal with possibly negative fields, we use casts in and out of
* "short" and/or signed shifts to maintain signedness.
*
- * Because it occupies uppermost bits, we can add one active count
- * using getAndAddLong of AC_UNIT, rather than CAS, when returning
+ * Because it occupies uppermost bits, we can add one release count
+ * using getAndAddLong of RC_UNIT, rather than CAS, when returning
* from a blocked join. Other updates entail multiple subfields
* and masking, requiring CAS.
+ *
+ * The limits packed in field "bounds" are also offset by the
+ * parallelism level to make them comparable to the ctl rc and tc
+ * fields.
*/
// Lower and upper word masks
private static final long SP_MASK = 0xffffffffL;
private static final long UC_MASK = ~SP_MASK;
- // Active counts
- private static final int AC_SHIFT = 48;
- private static final long AC_UNIT = 0x0001L << AC_SHIFT;
- private static final long AC_MASK = 0xffffL << AC_SHIFT;
+ // Release counts
+ private static final int RC_SHIFT = 48;
+ private static final long RC_UNIT = 0x0001L << RC_SHIFT;
+ private static final long RC_MASK = 0xffffL << RC_SHIFT;
// Total counts
private static final int TC_SHIFT = 32;
@@ -1483,52 +1296,21 @@
private static final long TC_MASK = 0xffffL << TC_SHIFT;
private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
- // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
- private static final int STARTED = 1;
- private static final int STOP = 1 << 1;
- private static final int TERMINATED = 1 << 2;
- private static final int SHUTDOWN = 1 << 31;
-
// Instance fields
- volatile long ctl; // main pool control
- volatile int runState;
- final int config; // parallelism, mode
- AuxState auxState; // lock, steal counts
- volatile WorkQueue[] workQueues; // main registry
- final String workerNamePrefix; // to create worker name string
+
+ volatile long stealCount; // collects worker nsteals
+ final long keepAlive; // milliseconds before dropping if idle
+ int indexSeed; // next worker index
+ final int bounds; // min, max threads packed as shorts
+ volatile int mode; // parallelism, runstate, queue mode
+ WorkQueue[] workQueues; // main registry
+ final String workerNamePrefix; // for worker thread string; sync lock
final ForkJoinWorkerThreadFactory factory;
final UncaughtExceptionHandler ueh; // per-worker UEH
+ final Predicate<? super ForkJoinPool> saturate;
- /**
- * Instantiates fields upon first submission, or upon shutdown if
- * no submissions. If checkTermination true, also responds to
- * termination by external calls submitting tasks.
- */
- private void tryInitialize(boolean checkTermination) {
- if (runState == 0) { // bootstrap by locking static field
- int p = config & SMASK;
- int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
- n |= n >>> 1; // create workQueues array with size a power of two
- n |= n >>> 2;
- n |= n >>> 4;
- n |= n >>> 8;
- n |= n >>> 16;
- n = ((n + 1) << 1) & SMASK;
- AuxState aux = new AuxState();
- WorkQueue[] ws = new WorkQueue[n];
- synchronized (modifyThreadPermission) { // double-check
- if (runState == 0) {
- workQueues = ws;
- auxState = aux;
- runState = STARTED;
- }
- }
- }
- if (checkTermination && runState < 0) {
- tryTerminate(false, false); // help terminate
- throw new RejectedExecutionException();
- }
- }
+ @jdk.internal.vm.annotation.Contended("fjpctl") // segregate
+ volatile long ctl; // main pool control
// Creating, registering and deregistering workers
@@ -1537,18 +1319,14 @@
* count has already been incremented as a reservation. Invokes
* deregisterWorker on any failure.
*
- * @param isSpare true if this is a spare thread
* @return true if successful
*/
- private boolean createWorker(boolean isSpare) {
+ private boolean createWorker() {
ForkJoinWorkerThreadFactory fac = factory;
Throwable ex = null;
ForkJoinWorkerThread wt = null;
- WorkQueue q;
try {
if (fac != null && (wt = fac.newThread(this)) != null) {
- if (isSpare && (q = wt.workQueue) != null)
- q.config |= SPARE_WORKER;
wt.start();
return true;
}
@@ -1569,10 +1347,10 @@
*/
private void tryAddWorker(long c) {
do {
- long nc = ((AC_MASK & (c + AC_UNIT)) |
+ long nc = ((RC_MASK & (c + RC_UNIT)) |
(TC_MASK & (c + TC_UNIT)));
- if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
- createWorker(false);
+ if (ctl == c && CTL.compareAndSet(this, c, nc)) {
+ createWorker();
break;
}
} while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
@@ -1587,41 +1365,55 @@
*/
final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
UncaughtExceptionHandler handler;
- AuxState aux;
- wt.setDaemon(true); // configure thread
+ wt.setDaemon(true); // configure thread
if ((handler = ueh) != null)
wt.setUncaughtExceptionHandler(handler);
+ int tid = 0; // for thread name
+ int idbits = mode & FIFO;
+ String prefix = workerNamePrefix;
WorkQueue w = new WorkQueue(this, wt);
- int i = 0; // assign a pool index
- int mode = config & MODE_MASK;
- if ((aux = auxState) != null) {
- aux.lock();
- try {
- int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m;
- WorkQueue[] ws = workQueues;
- if (ws != null && (n = ws.length) > 0) {
- i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices
- if (ws[i] != null) { // collision
- int probes = 0; // step by approx half n
- int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
- while (ws[i = (i + step) & m] != null) {
- if (++probes >= n) {
- workQueues = ws = Arrays.copyOf(ws, n <<= 1);
- m = n - 1;
- probes = 0;
- }
+ if (prefix != null) {
+ synchronized (prefix) {
+ WorkQueue[] ws = workQueues; int n;
+ int s = indexSeed += SEED_INCREMENT;
+ idbits |= (s & ~(SMASK | FIFO | DORMANT));
+ if (ws != null && (n = ws.length) > 1) {
+ int m = n - 1;
+ tid = m & ((s << 1) | 1); // odd-numbered indices
+ for (int probes = n >>> 1;;) { // find empty slot
+ WorkQueue q;
+ if ((q = ws[tid]) == null || q.phase == QUIET)
+ break;
+ else if (--probes == 0) {
+ tid = n | 1; // resize below
+ break;
}
+ else
+ tid = (tid + 2) & m;
}
- w.hint = s; // use as random seed
- w.config = i | mode;
- w.scanState = i | (s & 0x7fff0000); // random seq bits
- ws[i] = w;
+ w.phase = w.id = tid | idbits; // now publishable
+
+ if (tid < n)
+ ws[tid] = w;
+ else { // expand array
+ int an = n << 1;
+ WorkQueue[] as = new WorkQueue[an];
+ as[tid] = w;
+ int am = an - 1;
+ for (int j = 0; j < n; ++j) {
+ WorkQueue v; // copy external queue
+ if ((v = ws[j]) != null) // position may change
+ as[v.id & am & SQMASK] = v;
+ if (++j >= n)
+ break;
+ as[j] = ws[j]; // copy worker
+ }
+ workQueues = as;
+ }
}
- } finally {
- aux.unlock();
}
+ wt.setName(prefix.concat(Integer.toString(tid)));
}
- wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
return w;
}
@@ -1636,64 +1428,48 @@
*/
final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
WorkQueue w = null;
+ int phase = 0;
if (wt != null && (w = wt.workQueue) != null) {
- AuxState aux; WorkQueue[] ws; // remove index from array
- int idx = w.config & SMASK;
- int ns = w.nsteals;
- if ((aux = auxState) != null) {
- aux.lock();
- try {
- if ((ws = workQueues) != null && ws.length > idx &&
- ws[idx] == w)
- ws[idx] = null;
- aux.stealCount += ns;
- } finally {
- aux.unlock();
+ Object lock = workerNamePrefix;
+ int wid = w.id;
+ long ns = (long)w.nsteals & 0xffffffffL;
+ if (lock != null) {
+ synchronized (lock) {
+ WorkQueue[] ws; int n, i; // remove index from array
+ if ((ws = workQueues) != null && (n = ws.length) > 0 &&
+ ws[i = wid & (n - 1)] == w)
+ ws[i] = null;
+ stealCount += ns;
}
}
+ phase = w.phase;
}
- if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
+ if (phase != QUIET) { // else pre-adjusted
long c; // decrement counts
- do {} while (!U.compareAndSwapLong
- (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
- (TC_MASK & (c - TC_UNIT)) |
- (SP_MASK & c))));
+ do {} while (!CTL.weakCompareAndSet
+ (this, c = ctl, ((RC_MASK & (c - RC_UNIT)) |
+ (TC_MASK & (c - TC_UNIT)) |
+ (SP_MASK & c))));
}
- if (w != null) {
- w.currentSteal = null;
- w.qlock = -1; // ensure set
+ if (w != null)
w.cancelAll(); // cancel remaining tasks
- }
- while (tryTerminate(false, false) >= 0) { // possibly replace
- WorkQueue[] ws; int wl, sp; long c;
- if (w == null || w.array == null ||
- (ws = workQueues) == null || (wl = ws.length) <= 0)
- break;
- else if ((sp = (int)(c = ctl)) != 0) { // wake up replacement
- if (tryRelease(c, ws[(wl - 1) & sp], AC_UNIT))
- break;
- }
- else if (ex != null && (c & ADD_WORKER) != 0L) {
- tryAddWorker(c); // create replacement
- break;
- }
- else // don't need replacement
- break;
- }
+
+ if (!tryTerminate(false, false) && // possibly replace worker
+ w != null && w.array != null) // avoid repeated failures
+ signalWork();
+
if (ex == null) // help clean on way out
ForkJoinTask.helpExpungeStaleExceptions();
else // rethrow
ForkJoinTask.rethrow(ex);
}
- // Signalling
-
/**
- * Tries to create or activate a worker if too few are active.
+ * Tries to create or release a worker if too few are running.
*/
final void signalWork() {
for (;;) {
- long c; int sp, i; WorkQueue v; WorkQueue[] ws;
+ long c; int sp; WorkQueue[] ws; int i; WorkQueue v;
if ((c = ctl) >= 0L) // enough workers
break;
else if ((sp = (int)c) == 0) { // no idle workers
@@ -1708,12 +1484,14 @@
else if ((v = ws[i]) == null)
break; // terminating
else {
- int ns = sp & ~UNSIGNALLED;
- int vs = v.scanState;
- long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
- if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
- v.scanState = ns;
- LockSupport.unpark(v.parker);
+ int np = sp & ~UNSIGNALLED;
+ int vp = v.phase;
+ long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + RC_UNIT));
+ Thread vt = v.owner;
+ if (sp == vp && CTL.compareAndSet(this, c, nc)) {
+ v.phase = np;
+ if (vt != null && v.source < 0)
+ LockSupport.unpark(vt);
break;
}
}
@@ -1721,502 +1499,181 @@
}
/**
- * Signals and releases worker v if it is top of idle worker
- * stack. This performs a one-shot version of signalWork only if
- * there is (apparently) at least one idle worker.
+ * Tries to decrement counts (sometimes implicitly) and possibly
+ * arrange for a compensating worker in preparation for blocking:
+ * If not all core workers yet exist, creates one, else if any are
+ * unreleased (possibly including caller) releases one, else if
+ * fewer than the minimum allowed number of workers running,
+ * checks to see that they are all active, and if so creates an
+ * extra worker unless over maximum limit and policy is to
+ * saturate. Most of these steps can fail due to interference, in
+ * which case 0 is returned so caller will retry. A negative
+ * return value indicates that the caller doesn't need to
+ * re-adjust counts when later unblocked.
*
- * @param c incoming ctl value
- * @param v if non-null, a worker
- * @param inc the increment to active count (zero when compensating)
- * @return true if successful
+ * @return 1: block then adjust, -1: block without adjust, 0 : retry
*/
- private boolean tryRelease(long c, WorkQueue v, long inc) {
- int sp = (int)c, ns = sp & ~UNSIGNALLED;
- if (v != null) {
- int vs = v.scanState;
- long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + inc));
- if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
- v.scanState = ns;
- LockSupport.unpark(v.parker);
- return true;
- }
- }
- return false;
- }
-
- /**
- * With approx probability of a missed signal, tries (once) to
- * reactivate worker w (or some other worker), failing if stale or
- * known to be already active.
- *
- * @param w the worker
- * @param ws the workQueue array to use
- * @param r random seed
- */
- private void tryReactivate(WorkQueue w, WorkQueue[] ws, int r) {
- long c; int sp, wl; WorkQueue v;
- if ((sp = (int)(c = ctl)) != 0 && w != null &&
- ws != null && (wl = ws.length) > 0 &&
- ((sp ^ r) & SS_SEQ) == 0 &&
- (v = ws[(wl - 1) & sp]) != null) {
- long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
- int ns = sp & ~UNSIGNALLED;
- if (w.scanState < 0 &&
- v.scanState == sp &&
- U.compareAndSwapLong(this, CTL, c, nc)) {
- v.scanState = ns;
- LockSupport.unpark(v.parker);
- }
- }
- }
-
- /**
- * If worker w exists and is active, enqueues and sets status to inactive.
- *
- * @param w the worker
- * @param ss current (non-negative) scanState
- */
- private void inactivate(WorkQueue w, int ss) {
- int ns = (ss + SS_SEQ) | UNSIGNALLED;
- long lc = ns & SP_MASK, nc, c;
- if (w != null) {
- w.scanState = ns;
- do {
- nc = lc | (UC_MASK & ((c = ctl) - AC_UNIT));
- w.stackPred = (int)c;
- } while (!U.compareAndSwapLong(this, CTL, c, nc));
- }
- }
-
- /**
- * Possibly blocks worker w waiting for signal, or returns
- * negative status if the worker should terminate. May return
- * without status change if multiple stale unparks and/or
- * interrupts occur.
- *
- * @param w the calling worker
- * @return negative if w should terminate
- */
- private int awaitWork(WorkQueue w) {
- int stat = 0;
- if (w != null && w.scanState < 0) {
- long c = ctl;
- if ((int)(c >> AC_SHIFT) + (config & SMASK) <= 0)
- stat = timedAwaitWork(w, c); // possibly quiescent
- else if ((runState & STOP) != 0)
- stat = w.qlock = -1; // pool terminating
- else if (w.scanState < 0) {
- w.parker = Thread.currentThread();
- if (w.scanState < 0) // recheck after write
- LockSupport.park(this);
- w.parker = null;
- if ((runState & STOP) != 0)
- stat = w.qlock = -1; // recheck
- else if (w.scanState < 0)
- Thread.interrupted(); // clear status
- }
- }
- return stat;
- }
-
- /**
- * Possibly triggers shutdown and tries (once) to block worker
- * when pool is (or may be) quiescent. Waits up to a duration
- * determined by number of workers. On timeout, if ctl has not
- * changed, terminates the worker, which will in turn wake up
- * another worker to possibly repeat this process.
- *
- * @param w the calling worker
- * @return negative if w should terminate
- */
- private int timedAwaitWork(WorkQueue w, long c) {
- int stat = 0;
- int scale = 1 - (short)(c >>> TC_SHIFT);
- long deadline = (((scale <= 0) ? 1 : scale) * IDLE_TIMEOUT_MS +
- System.currentTimeMillis());
- if ((runState >= 0 || (stat = tryTerminate(false, false)) > 0) &&
- w != null && w.scanState < 0) {
- int ss; AuxState aux;
- w.parker = Thread.currentThread();
- if (w.scanState < 0)
- LockSupport.parkUntil(this, deadline);
- w.parker = null;
- if ((runState & STOP) != 0)
- stat = w.qlock = -1; // pool terminating
- else if ((ss = w.scanState) < 0 && !Thread.interrupted() &&
- (int)c == ss && (aux = auxState) != null && ctl == c &&
- deadline - System.currentTimeMillis() <= TIMEOUT_SLOP_MS) {
- aux.lock();
- try { // pre-deregister
- WorkQueue[] ws;
- int cfg = w.config, idx = cfg & SMASK;
- long nc = ((UC_MASK & (c - TC_UNIT)) |
- (SP_MASK & w.stackPred));
- if ((runState & STOP) == 0 &&
- (ws = workQueues) != null &&
- idx < ws.length && idx >= 0 && ws[idx] == w &&
- U.compareAndSwapLong(this, CTL, c, nc)) {
- ws[idx] = null;
- w.config = cfg | UNREGISTERED;
- stat = w.qlock = -1;
+ private int tryCompensate(WorkQueue w) {
+ int t, n, sp;
+ long c = ctl;
+ WorkQueue[] ws = workQueues;
+ if ((t = (short)(c >>> TC_SHIFT)) >= 0) {
+ if (ws == null || (n = ws.length) <= 0 || w == null)
+ return 0; // disabled
+ else if ((sp = (int)c) != 0) { // replace or release
+ WorkQueue v = ws[sp & (n - 1)];
+ int wp = w.phase;
+ long uc = UC_MASK & ((wp < 0) ? c + RC_UNIT : c);
+ int np = sp & ~UNSIGNALLED;
+ if (v != null) {
+ int vp = v.phase;
+ Thread vt = v.owner;
+ long nc = ((long)v.stackPred & SP_MASK) | uc;
+ if (vp == sp && CTL.compareAndSet(this, c, nc)) {
+ v.phase = np;
+ if (vt != null && v.source < 0)
+ LockSupport.unpark(vt);
+ return (wp < 0) ? -1 : 1;
}
- } finally {
- aux.unlock();
}
+ return 0;
}
- }
- return stat;
- }
-
- /**
- * If the given worker is a spare with no queued tasks, and there
- * are enough existing workers, drops it from ctl counts and sets
- * its state to terminated.
- *
- * @param w the calling worker -- must be a spare
- * @return true if dropped (in which case it must not process more tasks)
- */
- private boolean tryDropSpare(WorkQueue w) {
- if (w != null && w.isEmpty()) { // no local tasks
- long c; int sp, wl; WorkQueue[] ws; WorkQueue v;
- while ((short)((c = ctl) >> TC_SHIFT) > 0 &&
- ((sp = (int)c) != 0 || (int)(c >> AC_SHIFT) > 0) &&
- (ws = workQueues) != null && (wl = ws.length) > 0) {
- boolean dropped, canDrop;
- if (sp == 0) { // no queued workers
- long nc = ((AC_MASK & (c - AC_UNIT)) |
- (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c));
- dropped = U.compareAndSwapLong(this, CTL, c, nc);
+ else if ((int)(c >> RC_SHIFT) - // reduce parallelism
+ (short)(bounds & SMASK) > 0) {
+ long nc = ((RC_MASK & (c - RC_UNIT)) | (~RC_MASK & c));
+ return CTL.compareAndSet(this, c, nc) ? 1 : 0;
+ }
+ else { // validate
+ int md = mode, pc = md & SMASK, tc = pc + t, bc = 0;
+ boolean unstable = false;
+ for (int i = 1; i < n; i += 2) {
+ WorkQueue q; Thread wt; Thread.State ts;
+ if ((q = ws[i]) != null) {
+ if (q.source == 0) {
+ unstable = true;
+ break;
+ }
+ else {
+ --tc;
+ if ((wt = q.owner) != null &&
+ ((ts = wt.getState()) == Thread.State.BLOCKED ||
+ ts == Thread.State.WAITING))
+ ++bc; // worker is blocking
+ }
+ }
}
- else if (
- (v = ws[(wl - 1) & sp]) == null || v.scanState != sp)
- dropped = false; // stale; retry
- else {
- long nc = v.stackPred & SP_MASK;
- if (w == v || w.scanState >= 0) {
- canDrop = true; // w unqueued or topmost
- nc |= ((AC_MASK & c) | // ensure replacement
- (TC_MASK & (c - TC_UNIT)));
- }
- else { // w may be queued
- canDrop = false; // help uncover
- nc |= ((AC_MASK & (c + AC_UNIT)) |
- (TC_MASK & c));
- }
- if (U.compareAndSwapLong(this, CTL, c, nc)) {
- v.scanState = sp & ~UNSIGNALLED;
- LockSupport.unpark(v.parker);
- dropped = canDrop;
+ if (unstable || tc != 0 || ctl != c)
+ return 0; // inconsistent
+ else if (t + pc >= MAX_CAP || t >= (bounds >>> SWIDTH)) {
+ Predicate<? super ForkJoinPool> sat;
+ if ((sat = saturate) != null && sat.test(this))
+ return -1;
+ else if (bc < pc) { // lagging
+ Thread.yield(); // for retry spins
+ return 0;
}
else
- dropped = false;
- }
- if (dropped) { // pre-deregister
- int cfg = w.config, idx = cfg & SMASK;
- if (idx >= 0 && idx < ws.length && ws[idx] == w)
- ws[idx] = null;
- w.config = cfg | UNREGISTERED;
- w.qlock = -1;
- return true;
+ throw new RejectedExecutionException(
+ "Thread limit exceeded replacing blocked worker");
}
}
}
- return false;
+
+ long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK); // expand pool
+ return CTL.compareAndSet(this, c, nc) && createWorker() ? 1 : 0;
}
/**
* Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+ * See above for explanation.
*/
final void runWorker(WorkQueue w) {
- w.growArray(); // allocate queue
- int bound = (w.config & SPARE_WORKER) != 0 ? 0 : POLL_LIMIT;
- long seed = w.hint * 0xdaba0b6eb09322e3L; // initial random seed
- if ((runState & STOP) == 0) {
- for (long r = (seed == 0L) ? 1L : seed;;) { // ensure nonzero
- if (bound == 0 && tryDropSpare(w))
- break;
- // high bits of prev seed for step; current low bits for idx
- int step = (int)(r >>> 48) | 1;
- r ^= r >>> 12; r ^= r << 25; r ^= r >>> 27; // xorshift
- if (scan(w, bound, step, (int)r) < 0 && awaitWork(w) < 0)
- break;
+ int r = (w.id ^ ThreadLocalRandom.nextSecondarySeed()) | FIFO; // rng
+ w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; // initialize
+ for (;;) {
+ int phase;
+ if (scan(w, r)) { // scan until apparently empty
+ r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // move (xorshift)
}
- }
- }
-
- // Scanning for tasks
-
- /**
- * Repeatedly scans for and tries to steal and execute (via
- * workQueue.runTask) a queued task. Each scan traverses queues in
- * pseudorandom permutation. Upon finding a non-empty queue, makes
- * at most the given bound attempts to re-poll (fewer if
- * contended) on the same queue before returning (impossible
- * scanState value) 0 to restart scan. Else returns after at least
- * 1 and at most 32 full scans.
- *
- * @param w the worker (via its WorkQueue)
- * @param bound repoll bound as bitmask (0 if spare)
- * @param step (circular) index increment per iteration (must be odd)
- * @param r a random seed for origin index
- * @return negative if should await signal
- */
- private int scan(WorkQueue w, int bound, int step, int r) {
- int stat = 0, wl; WorkQueue[] ws;
- if ((ws = workQueues) != null && w != null && (wl = ws.length) > 0) {
- for (int m = wl - 1,
- origin = m & r, idx = origin,
- npolls = 0,
- ss = w.scanState;;) { // negative if inactive
- WorkQueue q; ForkJoinTask<?>[] a; int b, al;
- if ((q = ws[idx]) != null && (b = q.base) - q.top < 0 &&
- (a = q.array) != null && (al = a.length) > 0) {
- int index = (al - 1) & b;
- long offset = ((long)index << ASHIFT) + ABASE;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (t == null)
- break; // empty or busy
- else if (b++ != q.base)
- break; // busy
- else if (ss < 0) {
- tryReactivate(w, ws, r);
- break; // retry upon rescan
- }
- else if (!U.compareAndSwapObject(a, offset, t, null))
- break; // contended
- else {
- q.base = b;
- w.currentSteal = t;
- if (b != q.top) // propagate signal
- signalWork();
- w.runTask(t);
- if (++npolls > bound)
- break;
- }
- }
- else if (npolls != 0) // rescan
+ else if ((phase = w.phase) >= 0) { // enqueue, then rescan
+ long np = (w.phase = (phase + SS_SEQ) | UNSIGNALLED) & SP_MASK;
+ long c, nc;
+ do {
+ w.stackPred = (int)(c = ctl);
+ nc = ((c - RC_UNIT) & UC_MASK) | np;
+ } while (!CTL.weakCompareAndSet(this, c, nc));
+ }
+ else { // already queued
+ int pred = w.stackPred;
+ Thread.interrupted(); // clear before park
+ w.source = DORMANT; // enable signal
+ long c = ctl;
+ int md = mode, rc = (md & SMASK) + (int)(c >> RC_SHIFT);
+ if (md < 0) // terminating
break;
- else if ((idx = (idx + step) & m) == origin) {
- if (ss < 0) { // await signal
- stat = ss;
+ else if (rc <= 0 && (md & SHUTDOWN) != 0 &&
+ tryTerminate(false, false))
+ break; // quiescent shutdown
+ else if (rc <= 0 && pred != 0 && phase == (int)c) {
+ long nc = (UC_MASK & (c - TC_UNIT)) | (SP_MASK & pred);
+ long d = keepAlive + System.currentTimeMillis();
+ LockSupport.parkUntil(this, d);
+ if (ctl == c && // drop on timeout if all idle
+ d - System.currentTimeMillis() <= TIMEOUT_SLOP &&
+ CTL.compareAndSet(this, c, nc)) {
+ w.phase = QUIET;
break;
}
- else if (r >= 0) {
- inactivate(w, ss);
- break;
- }
- else
- r <<= 1; // at most 31 rescans
}
+ else if (w.phase < 0)
+ LockSupport.park(this); // OK if spuriously woken
+ w.source = 0; // disable signal
}
}
- return stat;
}
- // Joining tasks
-
/**
- * Tries to steal and run tasks within the target's computation.
- * Uses a variant of the top-level algorithm, restricted to tasks
- * with the given task as ancestor: It prefers taking and running
- * eligible tasks popped from the worker's own queue (via
- * popCC). Otherwise it scans others, randomly moving on
- * contention or execution, deciding to give up based on a
- * checksum (via return codes from pollAndExecCC). The maxTasks
- * argument supports external usages; internal calls use zero,
- * allowing unbounded steps (external calls trap non-positive
- * values).
+ * Scans for and if found executes one or more top-level tasks from a queue.
*
- * @param w caller
- * @param maxTasks if non-zero, the maximum number of other tasks to run
- * @return task status on exit
+ * @return true if found an apparently non-empty queue, and
+ * possibly ran task(s).
*/
- final int helpComplete(WorkQueue w, CountedCompleter<?> task,
- int maxTasks) {
- WorkQueue[] ws; int s = 0, wl;
- if ((ws = workQueues) != null && (wl = ws.length) > 1 &&
- task != null && w != null) {
- for (int m = wl - 1,
- mode = w.config,
- r = ~mode, // scanning seed
- origin = r & m, k = origin, // first queue to scan
- step = 3, // first scan step
- h = 1, // 1:ran, >1:contended, <0:hash
- oldSum = 0, checkSum = 0;;) {
- CountedCompleter<?> p; WorkQueue q; int i;
- if ((s = task.status) < 0)
+ private boolean scan(WorkQueue w, int r) {
+ WorkQueue[] ws; int n;
+ if ((ws = workQueues) != null && (n = ws.length) > 0 && w != null) {
+ for (int m = n - 1, j = r & m;;) {
+ WorkQueue q; int b;
+ if ((q = ws[j]) != null && q.top != (b = q.base)) {
+ int qid = q.id;
+ ForkJoinTask<?>[] a; int cap, k; ForkJoinTask<?> t;
+ if ((a = q.array) != null && (cap = a.length) > 0) {
+ t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+ if (q.base == b++ && t != null &&
+ QA.compareAndSet(a, k, t, null)) {
+ q.base = b;
+ w.source = qid;
+ if (q.top - b > 0)
+ signalWork();
+ w.topLevelExec(t, q, // random fairness bound
+ r & ((n << TOP_BOUND_SHIFT) - 1));
+ }
+ }
+ return true;
+ }
+ else if (--n > 0)
+ j = (j + 1) & m;
+ else
break;
- if (h == 1 && (p = w.popCC(task, mode)) != null) {
- p.doExec(); // run local task
- if (maxTasks != 0 && --maxTasks == 0)
- break;
- origin = k; // reset
- oldSum = checkSum = 0;
- }
- else { // poll other worker queues
- if ((i = k | 1) < 0 || i > m || (q = ws[i]) == null)
- h = 0;
- else if ((h = q.pollAndExecCC(task)) < 0)
- checkSum += h;
- if (h > 0) {
- if (h == 1 && maxTasks != 0 && --maxTasks == 0)
- break;
- step = (r >>> 16) | 3;
- r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
- k = origin = r & m; // move and restart
- oldSum = checkSum = 0;
- }
- else if ((k = (k + step) & m) == origin) {
- if (oldSum == (oldSum = checkSum))
- break;
- checkSum = 0;
- }
- }
}
}
- return s;
- }
-
- /**
- * Tries to locate and execute tasks for a stealer of the given
- * task, or in turn one of its stealers. Traces currentSteal ->
- * currentJoin links looking for a thread working on a descendant
- * of the given task and with a non-empty queue to steal back and
- * execute tasks from. The first call to this method upon a
- * waiting join will often entail scanning/search, (which is OK
- * because the joiner has nothing better to do), but this method
- * leaves hints in workers to speed up subsequent calls.
- *
- * @param w caller
- * @param task the task to join
- */
- private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
- if (task != null && w != null) {
- ForkJoinTask<?> ps = w.currentSteal;
- WorkQueue[] ws; int wl, oldSum = 0;
- outer: while (w.tryRemoveAndExec(task) && task.status >= 0 &&
- (ws = workQueues) != null && (wl = ws.length) > 0) {
- ForkJoinTask<?> subtask;
- int m = wl - 1, checkSum = 0; // for stability check
- WorkQueue j = w, v; // v is subtask stealer
- descent: for (subtask = task; subtask.status >= 0; ) {
- for (int h = j.hint | 1, k = 0, i;;) {
- if ((v = ws[i = (h + (k << 1)) & m]) != null) {
- if (v.currentSteal == subtask) {
- j.hint = i;
- break;
- }
- checkSum += v.base;
- }
- if (++k > m) // can't find stealer
- break outer;
- }
-
- for (;;) { // help v or descend
- ForkJoinTask<?>[] a; int b, al;
- if (subtask.status < 0) // too late to help
- break descent;
- checkSum += (b = v.base);
- ForkJoinTask<?> next = v.currentJoin;
- ForkJoinTask<?> t = null;
- if ((a = v.array) != null && (al = a.length) > 0) {
- int index = (al - 1) & b;
- long offset = ((long)index << ASHIFT) + ABASE;
- t = (ForkJoinTask<?>)
- U.getObjectVolatile(a, offset);
- if (t != null && b++ == v.base) {
- if (j.currentJoin != subtask ||
- v.currentSteal != subtask ||
- subtask.status < 0)
- break descent; // stale
- if (U.compareAndSwapObject(a, offset, t, null)) {
- v.base = b;
- w.currentSteal = t;
- for (int top = w.top;;) {
- t.doExec(); // help
- w.currentSteal = ps;
- if (task.status < 0)
- break outer;
- if (w.top == top)
- break; // run local tasks
- if ((t = w.pop()) == null)
- break descent;
- w.currentSteal = t;
- }
- }
- }
- }
- if (t == null && b == v.base && b - v.top >= 0) {
- if ((subtask = next) == null) { // try to descend
- if (next == v.currentJoin &&
- oldSum == (oldSum = checkSum))
- break outer;
- break descent;
- }
- j = v;
- break;
- }
- }
- }
- }
- }
- }
-
- /**
- * Tries to decrement active count (sometimes implicitly) and
- * possibly release or create a compensating worker in preparation
- * for blocking. Returns false (retryable by caller), on
- * contention, detected staleness, instability, or termination.
- *
- * @param w caller
- */
- private boolean tryCompensate(WorkQueue w) {
- boolean canBlock; int wl;
- long c = ctl;
- WorkQueue[] ws = workQueues;
- int pc = config & SMASK;
- int ac = pc + (int)(c >> AC_SHIFT);
- int tc = pc + (short)(c >> TC_SHIFT);
- if (w == null || w.qlock < 0 || pc == 0 || // terminating or disabled
- ws == null || (wl = ws.length) <= 0)
- canBlock = false;
- else {
- int m = wl - 1, sp;
- boolean busy = true; // validate ac
- for (int i = 0; i <= m; ++i) {
- int k; WorkQueue v;
- if ((k = (i << 1) | 1) <= m && k >= 0 && (v = ws[k]) != null &&
- v.scanState >= 0 && v.currentSteal == null) {
- busy = false;
- break;
- }
- }
- if (!busy || ctl != c)
- canBlock = false; // unstable or stale
- else if ((sp = (int)c) != 0) // release idle worker
- canBlock = tryRelease(c, ws[m & sp], 0L);
- else if (tc >= pc && ac > 1 && w.isEmpty()) {
- long nc = ((AC_MASK & (c - AC_UNIT)) |
- (~AC_MASK & c)); // uncompensated
- canBlock = U.compareAndSwapLong(this, CTL, c, nc);
- }
- else if (tc >= MAX_CAP ||
- (this == common && tc >= pc + COMMON_MAX_SPARES))
- throw new RejectedExecutionException(
- "Thread limit exceeded replacing blocked worker");
- else { // similar to tryAddWorker
- boolean isSpare = (tc >= pc);
- long nc = (AC_MASK & c) | (TC_MASK & (c + TC_UNIT));
- canBlock = (U.compareAndSwapLong(this, CTL, c, nc) &&
- createWorker(isSpare)); // throws on exception
- }
- }
- return canBlock;
+ return false;
}
/**
* Helps and/or blocks until the given task is done or timeout.
+ * First tries locally helping, then scans other queues for a task
+ * produced by one of w's stealers; compensating and blocking if
+ * none are found (rescanning if tryCompensate fails).
*
* @param w caller
* @param task the task
@@ -2225,62 +1682,165 @@
*/
final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
int s = 0;
- if (w != null) {
- ForkJoinTask<?> prevJoin = w.currentJoin;
- if (task != null && (s = task.status) >= 0) {
- w.currentJoin = task;
- CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
- (CountedCompleter<?>)task : null;
- for (;;) {
- if (cc != null)
- helpComplete(w, cc, 0);
- else
- helpStealer(w, task);
- if ((s = task.status) < 0)
+ int seed = ThreadLocalRandom.nextSecondarySeed();
+ if (w != null && task != null &&
+ (!(task instanceof CountedCompleter) ||
+ (s = w.helpCC((CountedCompleter<?>)task, 0, false)) >= 0)) {
+ w.tryRemoveAndExec(task);
+ int src = w.source, id = w.id;
+ int r = (seed >>> 16) | 1, step = (seed & ~1) | 2;
+ s = task.status;
+ while (s >= 0) {
+ WorkQueue[] ws;
+ int n = (ws = workQueues) == null ? 0 : ws.length, m = n - 1;
+ while (n > 0) {
+ WorkQueue q; int b;
+ if ((q = ws[r & m]) != null && q.source == id &&
+ q.top != (b = q.base)) {
+ ForkJoinTask<?>[] a; int cap, k;
+ int qid = q.id;
+ if ((a = q.array) != null && (cap = a.length) > 0) {
+ ForkJoinTask<?> t = (ForkJoinTask<?>)
+ QA.getAcquire(a, k = (cap - 1) & b);
+ if (q.source == id && q.base == b++ &&
+ t != null && QA.compareAndSet(a, k, t, null)) {
+ q.base = b;
+ w.source = qid;
+ t.doExec();
+ w.source = src;
+ }
+ }
break;
- long ms, ns;
- if (deadline == 0L)
- ms = 0L;
- else if ((ns = deadline - System.nanoTime()) <= 0L)
- break;
- else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
- ms = 1L;
- if (tryCompensate(w)) {
- task.internalWait(ms);
- U.getAndAddLong(this, CTL, AC_UNIT);
}
- if ((s = task.status) < 0)
- break;
+ else {
+ r += step;
+ --n;
+ }
}
- w.currentJoin = prevJoin;
+ if ((s = task.status) < 0)
+ break;
+ else if (n == 0) { // empty scan
+ long ms, ns; int block;
+ if (deadline == 0L)
+ ms = 0L; // untimed
+ else if ((ns = deadline - System.nanoTime()) <= 0L)
+ break; // timeout
+ else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
+ ms = 1L; // avoid 0 for timed wait
+ if ((block = tryCompensate(w)) != 0) {
+ task.internalWait(ms);
+ CTL.getAndAdd(this, (block > 0) ? RC_UNIT : 0L);
+ }
+ s = task.status;
+ }
}
}
return s;
}
- // Specialized scanning
+ /**
+ * Runs tasks until {@code isQuiescent()}. Rather than blocking
+ * when tasks cannot be found, rescans until all others cannot
+ * find tasks either.
+ */
+ final void helpQuiescePool(WorkQueue w) {
+ int prevSrc = w.source;
+ int seed = ThreadLocalRandom.nextSecondarySeed();
+ int r = seed >>> 16, step = r | 1;
+ for (int source = prevSrc, released = -1;;) { // -1 until known
+ ForkJoinTask<?> localTask; WorkQueue[] ws;
+ while ((localTask = w.nextLocalTask()) != null)
+ localTask.doExec();
+ if (w.phase >= 0 && released == -1)
+ released = 1;
+ boolean quiet = true, empty = true;
+ int n = (ws = workQueues) == null ? 0 : ws.length;
+ for (int m = n - 1; n > 0; r += step, --n) {
+ WorkQueue q; int b;
+ if ((q = ws[r & m]) != null) {
+ int qs = q.source;
+ if (q.top != (b = q.base)) {
+ quiet = empty = false;
+ ForkJoinTask<?>[] a; int cap, k;
+ int qid = q.id;
+ if ((a = q.array) != null && (cap = a.length) > 0) {
+ if (released == 0) { // increment
+ released = 1;
+ CTL.getAndAdd(this, RC_UNIT);
+ }
+ ForkJoinTask<?> t = (ForkJoinTask<?>)
+ QA.getAcquire(a, k = (cap - 1) & b);
+ if (q.base == b++ && t != null &&
+ QA.compareAndSet(a, k, t, null)) {
+ q.base = b;
+ w.source = qid;
+ t.doExec();
+ w.source = source = prevSrc;
+ }
+ }
+ break;
+ }
+ else if ((qs & QUIET) == 0)
+ quiet = false;
+ }
+ }
+ if (quiet) {
+ if (released == 0)
+ CTL.getAndAdd(this, RC_UNIT);
+ w.source = prevSrc;
+ break;
+ }
+ else if (empty) {
+ if (source != QUIET)
+ w.source = source = QUIET;
+ if (released == 1) { // decrement
+ released = 0;
+ CTL.getAndAdd(this, RC_MASK & -RC_UNIT);
+ }
+ }
+ }
+ }
/**
- * Returns a (probably) non-empty steal queue, if one is found
- * during a scan, else null. This method must be retried by
- * caller if, by the time it tries to use the queue, it is empty.
+ * Scans for and returns a polled task, if available.
+ * Used only for untracked polls.
+ *
+ * @param submissionsOnly if true, only scan submission queues
*/
- private WorkQueue findNonEmptyStealQueue() {
- WorkQueue[] ws; int wl; // one-shot version of scan loop
- int r = ThreadLocalRandom.nextSecondarySeed();
- if ((ws = workQueues) != null && (wl = ws.length) > 0) {
- int m = wl - 1, origin = r & m;
- for (int k = origin, oldSum = 0, checkSum = 0;;) {
- WorkQueue q; int b;
- if ((q = ws[k]) != null) {
- if ((b = q.base) - q.top < 0)
- return q;
- checkSum += b;
+ private ForkJoinTask<?> pollScan(boolean submissionsOnly) {
+ WorkQueue[] ws; int n;
+ rescan: while ((mode & STOP) == 0 && (ws = workQueues) != null &&
+ (n = ws.length) > 0) {
+ int m = n - 1;
+ int r = ThreadLocalRandom.nextSecondarySeed();
+ int h = r >>> 16;
+ int origin, step;
+ if (submissionsOnly) {
+ origin = (r & ~1) & m; // even indices and steps
+ step = (h & ~1) | 2;
+ }
+ else {
+ origin = r & m;
+ step = h | 1;
+ }
+ boolean nonempty = false;
+ for (int i = origin, oldSum = 0, checkSum = 0;;) {
+ WorkQueue q;
+ if ((q = ws[i]) != null) {
+ int b; ForkJoinTask<?> t;
+ if (q.top - (b = q.base) > 0) {
+ nonempty = true;
+ if ((t = q.poll()) != null)
+ return t;
+ }
+ else
+ checkSum += b + q.id;
}
- if ((k = (k + 1) & m) == origin) {
- if (oldSum == (oldSum = checkSum))
- break;
+ if ((i = (i + step) & m) == origin) {
+ if (!nonempty && oldSum == (oldSum = checkSum))
+ break rescan;
checkSum = 0;
+ nonempty = false;
}
}
}
@@ -2288,58 +1848,129 @@
}
/**
- * Runs tasks until {@code isQuiescent()}. We piggyback on
- * active count ctl maintenance, but rather than blocking
- * when tasks cannot be found, we rescan until all others cannot
- * find tasks either.
- */
- final void helpQuiescePool(WorkQueue w) {
- ForkJoinTask<?> ps = w.currentSteal; // save context
- int wc = w.config;
- for (boolean active = true;;) {
- long c; WorkQueue q; ForkJoinTask<?> t;
- if (wc >= 0 && (t = w.pop()) != null) { // run locals if LIFO
- (w.currentSteal = t).doExec();
- w.currentSteal = ps;
- }
- else if ((q = findNonEmptyStealQueue()) != null) {
- if (!active) { // re-establish active count
- active = true;
- U.getAndAddLong(this, CTL, AC_UNIT);
- }
- if ((t = q.pollAt(q.base)) != null) {
- (w.currentSteal = t).doExec();
- w.currentSteal = ps;
- if (++w.nsteals < 0)
- w.transferStealCount(this);
- }
- }
- else if (active) { // decrement active count without queuing
- long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
- if (U.compareAndSwapLong(this, CTL, c, nc))
- active = false;
- }
- else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
- U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
- break;
- }
- }
-
- /**
* Gets and removes a local or stolen task for the given worker.
*
* @return a task, if available
*/
final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
- for (ForkJoinTask<?> t;;) {
- WorkQueue q;
- if ((t = w.nextLocalTask()) != null)
- return t;
- if ((q = findNonEmptyStealQueue()) == null)
- return null;
- if ((t = q.pollAt(q.base)) != null)
- return t;
+ ForkJoinTask<?> t;
+ if (w == null || (t = w.nextLocalTask()) == null)
+ t = pollScan(false);
+ return t;
+ }
+
+ // External operations
+
+ /**
+ * Adds the given task to a submission queue at submitter's
+ * current queue, creating one if null or contended.
+ *
+ * @param task the task. Caller must ensure non-null.
+ */
+ final void externalPush(ForkJoinTask<?> task) {
+ int r; // initialize caller's probe
+ if ((r = ThreadLocalRandom.getProbe()) == 0) {
+ ThreadLocalRandom.localInit();
+ r = ThreadLocalRandom.getProbe();
}
+ for (;;) {
+ WorkQueue q;
+ int md = mode, n;
+ WorkQueue[] ws = workQueues;
+ if ((md & SHUTDOWN) != 0 || ws == null || (n = ws.length) <= 0)
+ throw new RejectedExecutionException();
+ else if ((q = ws[(n - 1) & r & SQMASK]) == null) { // add queue
+ int qid = (r | QUIET) & ~(FIFO | OWNED);
+ Object lock = workerNamePrefix;
+ ForkJoinTask<?>[] qa =
+ new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+ q = new WorkQueue(this, null);
+ q.array = qa;
+ q.id = qid;
+ q.source = QUIET;
+ if (lock != null) { // unless disabled, lock pool to install
+ synchronized (lock) {
+ WorkQueue[] vs; int i, vn;
+ if ((vs = workQueues) != null && (vn = vs.length) > 0 &&
+ vs[i = qid & (vn - 1) & SQMASK] == null)
+ vs[i] = q; // else another thread already installed
+ }
+ }
+ }
+ else if (!q.tryLockPhase()) // move if busy
+ r = ThreadLocalRandom.advanceProbe(r);
+ else {
+ if (q.lockedPush(task))
+ signalWork();
+ return;
+ }
+ }
+ }
+
+ /**
+ * Pushes a possibly-external submission.
+ */
+ private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+ Thread t; ForkJoinWorkerThread w; WorkQueue q;
+ if (task == null)
+ throw new NullPointerException();
+ if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+ (w = (ForkJoinWorkerThread)t).pool == this &&
+ (q = w.workQueue) != null)
+ q.push(task);
+ else
+ externalPush(task);
+ return task;
+ }
+
+ /**
+ * Returns common pool queue for an external thread.
+ */
+ static WorkQueue commonSubmitterQueue() {
+ ForkJoinPool p = common;
+ int r = ThreadLocalRandom.getProbe();
+ WorkQueue[] ws; int n;
+ return (p != null && (ws = p.workQueues) != null &&
+ (n = ws.length) > 0) ?
+ ws[(n - 1) & r & SQMASK] : null;
+ }
+
+ /**
+ * Performs tryUnpush for an external submitter.
+ */
+ final boolean tryExternalUnpush(ForkJoinTask<?> task) {
+ int r = ThreadLocalRandom.getProbe();
+ WorkQueue[] ws; WorkQueue w; int n;
+ return ((ws = workQueues) != null &&
+ (n = ws.length) > 0 &&
+ (w = ws[(n - 1) & r & SQMASK]) != null &&
+ w.tryLockedUnpush(task));
+ }
+
+ /**
+ * Performs helpComplete for an external submitter.
+ */
+ final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
+ int r = ThreadLocalRandom.getProbe();
+ WorkQueue[] ws; WorkQueue w; int n;
+ return ((ws = workQueues) != null && (n = ws.length) > 0 &&
+ (w = ws[(n - 1) & r & SQMASK]) != null) ?
+ w.helpCC(task, maxTasks, true) : 0;
+ }
+
+ /**
+ * Tries to steal and run tasks within the target's computation.
+ * The maxTasks argument supports external usages; internal calls
+ * use zero, allowing unbounded steps (external calls trap
+ * non-positive values).
+ *
+ * @param w caller
+ * @param maxTasks if non-zero, the maximum number of other tasks to run
+ * @return task status on exit
+ */
+ final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+ int maxTasks) {
+ return (w == null) ? 0 : w.helpCC(task, maxTasks, false);
}
/**
@@ -2386,10 +2017,12 @@
*/
static int getSurplusQueuedTaskCount() {
Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
- if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
- int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
- int n = (q = wt.workQueue).top - q.base;
- int a = (int)(pool.ctl >> AC_SHIFT) + p;
+ if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+ (pool = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+ (q = wt.workQueue) != null) {
+ int p = pool.mode & SMASK;
+ int a = p + (int)(pool.ctl >> RC_SHIFT);
+ int n = q.top - q.base;
return n - (a > (p >>>= 1) ? 0 :
a > (p >>>= 1) ? 1 :
a > (p >>>= 1) ? 2 :
@@ -2399,7 +2032,7 @@
return 0;
}
- // Termination
+ // Termination
/**
* Possibly initiates and/or completes termination.
@@ -2407,198 +2040,89 @@
* @param now if true, unconditionally terminate, else only
* if no work and no active workers
* @param enable if true, terminate when next possible
- * @return -1: terminating/terminated, 0: retry if internal caller, else 1
+ * @return true if terminating or terminated
*/
- private int tryTerminate(boolean now, boolean enable) {
- int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
+ private boolean tryTerminate(boolean now, boolean enable) {
+ int md; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
- while ((rs = runState) >= 0) {
+ while (((md = mode) & SHUTDOWN) == 0) {
if (!enable || this == common) // cannot shutdown
- return 1;
- else if (rs == 0)
- tryInitialize(false); // ensure initialized
+ return false;
else
- U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
+ MODE.compareAndSet(this, md, md | SHUTDOWN);
}
- if ((rs & STOP) == 0) { // try to initiate termination
- if (!now) { // check quiescence
+ while (((md = mode) & STOP) == 0) { // try to initiate termination
+ if (!now) { // check if quiescent & empty
for (long oldSum = 0L;;) { // repeat until stable
- WorkQueue[] ws; WorkQueue w; int b;
+ boolean running = false;
long checkSum = ctl;
- if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
- return 0; // still active workers
- if ((ws = workQueues) != null) {
+ WorkQueue[] ws = workQueues;
+ if ((md & SMASK) + (int)(checkSum >> RC_SHIFT) > 0)
+ running = true;
+ else if (ws != null) {
+ WorkQueue w;
for (int i = 0; i < ws.length; ++i) {
if ((w = ws[i]) != null) {
- checkSum += (b = w.base);
- if (w.currentSteal != null || b != w.top)
- return 0; // retry if internal caller
+ int s = w.source, p = w.phase;
+ int d = w.id, b = w.base;
+ if (b != w.top ||
+ ((d & 1) == 1 && (s >= 0 || p >= 0))) {
+ running = true;
+ break; // working, scanning, or have work
+ }
+ checkSum += (((long)s << 48) + ((long)p << 32) +
+ ((long)b << 16) + (long)d);
}
}
}
- if (oldSum == (oldSum = checkSum))
+ if (((md = mode) & STOP) != 0)
+ break; // already triggered
+ else if (running)
+ return false;
+ else if (workQueues == ws && oldSum == (oldSum = checkSum))
break;
}
}
- do {} while (!U.compareAndSwapInt(this, RUNSTATE,
- rs = runState, rs | STOP));
+ if ((md & STOP) == 0)
+ MODE.compareAndSet(this, md, md | STOP);
}
- for (long oldSum = 0L;;) { // repeat until stable
- WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt;
- long checkSum = ctl;
- if ((ws = workQueues) != null) { // help terminate others
- for (int i = 0; i < ws.length; ++i) {
- if ((w = ws[i]) != null) {
- w.cancelAll(); // clear queues
- checkSum += w.base;
- if (w.qlock >= 0) {
- w.qlock = -1; // racy set OK
- if ((wt = w.owner) != null) {
+ while (((md = mode) & TERMINATED) == 0) { // help terminate others
+ for (long oldSum = 0L;;) { // repeat until stable
+ WorkQueue[] ws; WorkQueue w;
+ long checkSum = ctl;
+ if ((ws = workQueues) != null) {
+ for (int i = 0; i < ws.length; ++i) {
+ if ((w = ws[i]) != null) {
+ ForkJoinWorkerThread wt = w.owner;
+ w.cancelAll(); // clear queues
+ if (wt != null) {
try { // unblock join or park
wt.interrupt();
} catch (Throwable ignore) {
}
}
+ checkSum += ((long)w.phase << 32) + w.base;
}
}
}
+ if (((md = mode) & TERMINATED) != 0 ||
+ (workQueues == ws && oldSum == (oldSum = checkSum)))
+ break;
}
- if (oldSum == (oldSum = checkSum))
+ if ((md & TERMINATED) != 0)
break;
- }
-
- if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
- runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
- synchronized (this) {
- notifyAll(); // for awaitTermination
- }
- }
-
- return -1;
- }
-
- // External operations
-
- /**
- * Constructs and tries to install a new external queue,
- * failing if the workQueues array already has a queue at
- * the given index.
- *
- * @param index the index of the new queue
- */
- private void tryCreateExternalQueue(int index) {
- AuxState aux;
- if ((aux = auxState) != null && index >= 0) {
- WorkQueue q = new WorkQueue(this, null);
- q.config = index;
- q.scanState = ~UNSIGNALLED;
- q.qlock = 1; // lock queue
- boolean installed = false;
- aux.lock();
- try { // lock pool to install
- WorkQueue[] ws;
- if ((ws = workQueues) != null && index < ws.length &&
- ws[index] == null) {
- ws[index] = q; // else throw away
- installed = true;
+ else if ((md & SMASK) + (short)(ctl >>> TC_SHIFT) > 0)
+ break;
+ else if (MODE.compareAndSet(this, md, md | TERMINATED)) {
+ synchronized (this) {
+ notifyAll(); // for awaitTermination
}
- } finally {
- aux.unlock();
- }
- if (installed) {
- try {
- q.growArray();
- } finally {
- q.qlock = 0;
- }
- }
- }
- }
-
- /**
- * Adds the given task to a submission queue at submitter's
- * current queue. Also performs secondary initialization upon the
- * first submission of the first task to the pool, and detects
- * first submission by an external thread and creates a new shared
- * queue if the one at index if empty or contended.
- *
- * @param task the task. Caller must ensure non-null.
- */
- final void externalPush(ForkJoinTask<?> task) {
- int r; // initialize caller's probe
- if ((r = ThreadLocalRandom.getProbe()) == 0) {
- ThreadLocalRandom.localInit();
- r = ThreadLocalRandom.getProbe();
- }
- for (;;) {
- WorkQueue q; int wl, k, stat;
- int rs = runState;
- WorkQueue[] ws = workQueues;
- if (rs <= 0 || ws == null || (wl = ws.length) <= 0)
- tryInitialize(true);
- else if ((q = ws[k = (wl - 1) & r & SQMASK]) == null)
- tryCreateExternalQueue(k);
- else if ((stat = q.sharedPush(task)) < 0)
- break;
- else if (stat == 0) {
- signalWork();
break;
}
- else // move if busy
- r = ThreadLocalRandom.advanceProbe(r);
}
- }
-
- /**
- * Pushes a possibly-external submission.
- */
- private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
- Thread t; ForkJoinWorkerThread w; WorkQueue q;
- if (task == null)
- throw new NullPointerException();
- if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
- (w = (ForkJoinWorkerThread)t).pool == this &&
- (q = w.workQueue) != null)
- q.push(task);
- else
- externalPush(task);
- return task;
- }
-
- /**
- * Returns common pool queue for an external thread.
- */
- static WorkQueue commonSubmitterQueue() {
- ForkJoinPool p = common;
- int r = ThreadLocalRandom.getProbe();
- WorkQueue[] ws; int wl;
- return (p != null && (ws = p.workQueues) != null &&
- (wl = ws.length) > 0) ?
- ws[(wl - 1) & r & SQMASK] : null;
- }
-
- /**
- * Performs tryUnpush for an external submitter.
- */
- final boolean tryExternalUnpush(ForkJoinTask<?> task) {
- int r = ThreadLocalRandom.getProbe();
- WorkQueue[] ws; WorkQueue w; int wl;
- return ((ws = workQueues) != null &&
- (wl = ws.length) > 0 &&
- (w = ws[(wl - 1) & r & SQMASK]) != null &&
- w.trySharedUnpush(task));
- }
-
- /**
- * Performs helpComplete for an external submitter.
- */
- final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
- WorkQueue[] ws; int wl;
- int r = ThreadLocalRandom.getProbe();
- return ((ws = workQueues) != null && (wl = ws.length) > 0) ?
- helpComplete(ws[(wl - 1) & r & SQMASK], task, maxTasks) : 0;
+ return true;
}
// Exported methods
@@ -2607,9 +2131,10 @@
/**
* Creates a {@code ForkJoinPool} with parallelism equal to {@link
- * java.lang.Runtime#availableProcessors}, using the {@linkplain
- * #defaultForkJoinWorkerThreadFactory default thread factory},
- * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+ * java.lang.Runtime#availableProcessors}, using defaults for all
+ * other parameters (see {@link #ForkJoinPool(int,
+ * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+ * int, int, int, Predicate, long, TimeUnit)}).
*
* @throws SecurityException if a security manager exists and
* the caller is not permitted to modify threads
@@ -2618,14 +2143,16 @@
*/
public ForkJoinPool() {
this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
- defaultForkJoinWorkerThreadFactory, null, false);
+ defaultForkJoinWorkerThreadFactory, null, false,
+ 0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
}
/**
* Creates a {@code ForkJoinPool} with the indicated parallelism
- * level, the {@linkplain
- * #defaultForkJoinWorkerThreadFactory default thread factory},
- * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+ * level, using defaults for all other parameters (see {@link
+ * #ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+ * UncaughtExceptionHandler, boolean, int, int, int, Predicate,
+ * long, TimeUnit)}).
*
* @param parallelism the parallelism level
* @throws IllegalArgumentException if parallelism less than or
@@ -2636,11 +2163,15 @@
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public ForkJoinPool(int parallelism) {
- this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
+ this(parallelism, defaultForkJoinWorkerThreadFactory, null, false,
+ 0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
}
/**
- * Creates a {@code ForkJoinPool} with the given parameters.
+ * Creates a {@code ForkJoinPool} with the given parameters (using
+ * defaults for others -- see {@link #ForkJoinPool(int,
+ * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+ * int, int, int, Predicate, long, TimeUnit)}).
*
* @param parallelism the parallelism level. For default value,
* use {@link java.lang.Runtime#availableProcessors}.
@@ -2667,43 +2198,186 @@
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
- this(checkParallelism(parallelism),
- checkFactory(factory),
- handler,
- asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
- "ForkJoinPool-" + nextPoolId() + "-worker-");
- checkPermission();
- }
-
- private static int checkParallelism(int parallelism) {
- if (parallelism <= 0 || parallelism > MAX_CAP)
- throw new IllegalArgumentException();
- return parallelism;
- }
-
- private static ForkJoinWorkerThreadFactory checkFactory
- (ForkJoinWorkerThreadFactory factory) {
- if (factory == null)
- throw new NullPointerException();
- return factory;
+ this(parallelism, factory, handler, asyncMode,
+ 0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
}
/**
- * Creates a {@code ForkJoinPool} with the given parameters, without
- * any security checks or parameter validation. Invoked directly by
- * makeCommonPool.
+ * Creates a {@code ForkJoinPool} with the given parameters.
+ *
+ * @param parallelism the parallelism level. For default value,
+ * use {@link java.lang.Runtime#availableProcessors}.
+ *
+ * @param factory the factory for creating new threads. For
+ * default value, use {@link #defaultForkJoinWorkerThreadFactory}.
+ *
+ * @param handler the handler for internal worker threads that
+ * terminate due to unrecoverable errors encountered while
+ * executing tasks. For default value, use {@code null}.
+ *
+ * @param asyncMode if true, establishes local first-in-first-out
+ * scheduling mode for forked tasks that are never joined. This
+ * mode may be more appropriate than default locally stack-based
+ * mode in applications in which worker threads only process
+ * event-style asynchronous tasks. For default value, use {@code
+ * false}.
+ *
+ * @param corePoolSize the number of threads to keep in the pool
+ * (unless timed out after an elapsed keep-alive). Normally (and
+ * by default) this is the same value as the parallelism level,
+ * but may be set to a larger value to reduce dynamic overhead if
+ * tasks regularly block. Using a smaller value (for example
+ * {@code 0}) has the same effect as the default.
+ *
+ * @param maximumPoolSize the maximum number of threads allowed.
+ * When the maximum is reached, attempts to replace blocked
+ * threads fail. (However, because creation and termination of
+ * different threads may overlap, and may be managed by the given
+ * thread factory, this value may be transiently exceeded.) To
+ * arrange the same value as is used by default for the common
+ * pool, use {@code 256} plus the {@code parallelism} level. (By
+ * default, the common pool allows a maximum of 256 spare
+ * threads.) Using a value (for example {@code
+ * Integer.MAX_VALUE}) larger than the implementation's total
+ * thread limit has the same effect as using this limit (which is
+ * the default).
+ *
+ * @param minimumRunnable the minimum allowed number of core
+ * threads not blocked by a join or {@link ManagedBlocker}. To
+ * ensure progress, when too few unblocked threads exist and
+ * unexecuted tasks may exist, new threads are constructed, up to
+ * the given maximumPoolSize. For the default value, use {@code
+ * 1}, that ensures liveness. A larger value might improve
+ * throughput in the presence of blocked activities, but might
+ * not, due to increased overhead. A value of zero may be
+ * acceptable when submitted tasks cannot have dependencies
+ * requiring additional threads.
+ *
+ * @param saturate if non-null, a predicate invoked upon attempts
+ * to create more than the maximum total allowed threads. By
+ * default, when a thread is about to block on a join or {@link
+ * ManagedBlocker}, but cannot be replaced because the
+ * maximumPoolSize would be exceeded, a {@link
+ * RejectedExecutionException} is thrown. But if this predicate
+ * returns {@code true}, then no exception is thrown, so the pool
+ * continues to operate with fewer than the target number of
+ * runnable threads, which might not ensure progress.
+ *
+ * @param keepAliveTime the elapsed time since last use before
+ * a thread is terminated (and then later replaced if needed).
+ * For the default value, use {@code 60, TimeUnit.SECONDS}.
+ *
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ *
+ * @throws IllegalArgumentException if parallelism is less than or
+ * equal to zero, or is greater than implementation limit,
+ * or if maximumPoolSize is less than parallelism,
+ * of if the keepAliveTime is less than or equal to zero.
+ * @throws NullPointerException if the factory is null
+ * @throws SecurityException if a security manager exists and
+ * the caller is not permitted to modify threads
+ * because it does not hold {@link
+ * java.lang.RuntimePermission}{@code ("modifyThread")}
+ * @since 9
*/
- private ForkJoinPool(int parallelism,
- ForkJoinWorkerThreadFactory factory,
- UncaughtExceptionHandler handler,
- int mode,
- String workerNamePrefix) {
- this.workerNamePrefix = workerNamePrefix;
+ public ForkJoinPool(int parallelism,
+ ForkJoinWorkerThreadFactory factory,
+ UncaughtExceptionHandler handler,
+ boolean asyncMode,
+ int corePoolSize,
+ int maximumPoolSize,
+ int minimumRunnable,
+ Predicate<? super ForkJoinPool> saturate,
+ long keepAliveTime,
+ TimeUnit unit) {
+ // check, encode, pack parameters
+ if (parallelism <= 0 || parallelism > MAX_CAP ||
+ maximumPoolSize < parallelism || keepAliveTime <= 0L)
+ throw new IllegalArgumentException();
+ if (factory == null)
+ throw new NullPointerException();
+ long ms = Math.max(unit.toMillis(keepAliveTime), TIMEOUT_SLOP);
+
+ int corep = Math.min(Math.max(corePoolSize, parallelism), MAX_CAP);
+ long c = ((((long)(-corep) << TC_SHIFT) & TC_MASK) |
+ (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
+ int m = parallelism | (asyncMode ? FIFO : 0);
+ int maxSpares = Math.min(maximumPoolSize, MAX_CAP) - parallelism;
+ int minAvail = Math.min(Math.max(minimumRunnable, 0), MAX_CAP);
+ int b = ((minAvail - parallelism) & SMASK) | (maxSpares << SWIDTH);
+ int n = (parallelism > 1) ? parallelism - 1 : 1; // at least 2 slots
+ n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+ n = (n + 1) << 1; // power of two, including space for submission queues
+
+ this.workerNamePrefix = "ForkJoinPool-" + nextPoolId() + "-worker-";
+ this.workQueues = new WorkQueue[n];
this.factory = factory;
this.ueh = handler;
- this.config = (parallelism & SMASK) | mode;
- long np = (long)(-parallelism); // offset ctl counts
- this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+ this.saturate = saturate;
+ this.keepAlive = ms;
+ this.bounds = b;
+ this.mode = m;
+ this.ctl = c;
+ checkPermission();
+ }
+
+ private static Object newInstanceFromSystemProperty(String property)
+ throws ReflectiveOperationException {
+ String className = System.getProperty(property);
+ return (className == null)
+ ? null
+ : ClassLoader.getSystemClassLoader().loadClass(className)
+ .getConstructor().newInstance();
+ }
+
+ /**
+ * Constructor for common pool using parameters possibly
+ * overridden by system properties
+ */
+ private ForkJoinPool(byte forCommonPoolOnly) {
+ int parallelism = -1;
+ ForkJoinWorkerThreadFactory fac = null;
+ UncaughtExceptionHandler handler = null;
+ try { // ignore exceptions in accessing/parsing properties
+ String pp = System.getProperty
+ ("java.util.concurrent.ForkJoinPool.common.parallelism");
+ if (pp != null)
+ parallelism = Integer.parseInt(pp);
+ fac = (ForkJoinWorkerThreadFactory) newInstanceFromSystemProperty(
+ "java.util.concurrent.ForkJoinPool.common.threadFactory");
+ handler = (UncaughtExceptionHandler) newInstanceFromSystemProperty(
+ "java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+ } catch (Exception ignore) {
+ }
+
+ if (fac == null) {
+ if (System.getSecurityManager() == null)
+ fac = defaultForkJoinWorkerThreadFactory;
+ else // use security-managed default
+ fac = new InnocuousForkJoinWorkerThreadFactory();
+ }
+ if (parallelism < 0 && // default 1 less than #cores
+ (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
+ parallelism = 1;
+ if (parallelism > MAX_CAP)
+ parallelism = MAX_CAP;
+
+ long c = ((((long)(-parallelism) << TC_SHIFT) & TC_MASK) |
+ (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
+ int b = ((1 - parallelism) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
+ int n = (parallelism > 1) ? parallelism - 1 : 1;
+ n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+ n = (n + 1) << 1;
+
+ this.workerNamePrefix = "ForkJoinPool.commonPool-worker-";
+ this.workQueues = new WorkQueue[n];
+ this.factory = fac;
+ this.ueh = handler;
+ this.saturate = null;
+ this.keepAlive = DEFAULT_KEEPALIVE;
+ this.bounds = b;
+ this.mode = parallelism;
+ this.ctl = c;
}
/**
@@ -2817,15 +2491,13 @@
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
*/
+ @SuppressWarnings("unchecked")
public ForkJoinTask<?> submit(Runnable task) {
if (task == null)
throw new NullPointerException();
- ForkJoinTask<?> job;
- if (task instanceof ForkJoinTask<?>) // avoid re-wrap
- job = (ForkJoinTask<?>) task;
- else
- job = new ForkJoinTask.AdaptedRunnableAction(task);
- return externalSubmit(job);
+ return externalSubmit((task instanceof ForkJoinTask<?>)
+ ? (ForkJoinTask<Void>) task // avoid re-wrap
+ : new ForkJoinTask.AdaptedRunnableAction(task));
}
/**
@@ -2879,8 +2551,8 @@
* @return the targeted parallelism level of this pool
*/
public int getParallelism() {
- int par;
- return ((par = config & SMASK) > 0) ? par : 1;
+ int par = mode & SMASK;
+ return (par > 0) ? par : 1;
}
/**
@@ -2902,7 +2574,7 @@
* @return the number of worker threads
*/
public int getPoolSize() {
- return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
+ return ((mode & SMASK) + (short)(ctl >>> TC_SHIFT));
}
/**
@@ -2912,7 +2584,7 @@
* @return {@code true} if this pool uses async mode
*/
public boolean getAsyncMode() {
- return (config & FIFO_QUEUE) != 0;
+ return (mode & FIFO) != 0;
}
/**
@@ -2924,8 +2596,9 @@
* @return the number of worker threads
*/
public int getRunningThreadCount() {
- int rc = 0;
WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
+ int rc = 0;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
if ((w = ws[i]) != null && w.isApparentlyUnblocked())
@@ -2943,7 +2616,7 @@
* @return the number of active threads
*/
public int getActiveThreadCount() {
- int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
+ int r = (mode & SMASK) + (int)(ctl >> RC_SHIFT);
return (r <= 0) ? 0 : r; // suppress momentarily negative values
}
@@ -2959,7 +2632,30 @@
* @return {@code true} if all threads are currently idle
*/
public boolean isQuiescent() {
- return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
+ for (;;) {
+ long c = ctl;
+ int md = mode, pc = md & SMASK;
+ int tc = pc + (short)(c >>> TC_SHIFT);
+ int rc = pc + (int)(c >> RC_SHIFT);
+ if ((md & (STOP | TERMINATED)) != 0)
+ return true;
+ else if (rc > 0)
+ return false;
+ else {
+ WorkQueue[] ws; WorkQueue v;
+ if ((ws = workQueues) != null) {
+ for (int i = 1; i < ws.length; i += 2) {
+ if ((v = ws[i]) != null) {
+ if (v.source > 0)
+ return false;
+ --tc;
+ }
+ }
+ }
+ if (tc == 0 && ctl == c)
+ return true;
+ }
+ }
}
/**
@@ -2974,13 +2670,12 @@
* @return the number of steals
*/
public long getStealCount() {
- AuxState sc = auxState;
- long count = (sc == null) ? 0L : sc.stealCount;
+ long count = stealCount;
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
if ((w = ws[i]) != null)
- count += w.nsteals;
+ count += (long)w.nsteals & 0xffffffffL;
}
}
return count;
@@ -2997,8 +2692,9 @@
* @return the number of queued tasks
*/
public long getQueuedTaskCount() {
- long count = 0;
WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
+ int count = 0;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
if ((w = ws[i]) != null)
@@ -3016,8 +2712,9 @@
* @return the number of queued submissions
*/
public int getQueuedSubmissionCount() {
- int count = 0;
WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
+ int count = 0;
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; i += 2) {
if ((w = ws[i]) != null)
@@ -3035,6 +2732,7 @@
*/
public boolean hasQueuedSubmissions() {
WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; i += 2) {
if ((w = ws[i]) != null && !w.isEmpty())
@@ -3052,15 +2750,7 @@
* @return the next submission, or {@code null} if none
*/
protected ForkJoinTask<?> pollSubmission() {
- WorkQueue[] ws; int wl; WorkQueue w; ForkJoinTask<?> t;
- int r = ThreadLocalRandom.nextSecondarySeed();
- if ((ws = workQueues) != null && (wl = ws.length) > 0) {
- for (int m = wl - 1, i = 0; i < wl; ++i) {
- if ((w = ws[(i << 1) & m]) != null && (t = w.poll()) != null)
- return t;
- }
- }
- return null;
+ return pollScan(true);
}
/**
@@ -3081,8 +2771,9 @@
* @return the number of elements transferred
*/
protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
- int count = 0;
WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+ VarHandle.acquireFence();
+ int count = 0;
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; ++i) {
if ((w = ws[i]) != null) {
@@ -3105,10 +2796,10 @@
*/
public String toString() {
// Use a single pass through workQueues to collect counts
- long qt = 0L, qs = 0L; int rc = 0;
- AuxState sc = auxState;
- long st = (sc == null) ? 0L : sc.stealCount;
+ int md = mode; // read volatile fields first
long c = ctl;
+ long st = stealCount;
+ long qt = 0L, qs = 0L; int rc = 0;
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; ++i) {
@@ -3118,22 +2809,22 @@
qs += size;
else {
qt += size;
- st += w.nsteals;
+ st += (long)w.nsteals & 0xffffffffL;
if (w.isApparentlyUnblocked())
++rc;
}
}
}
}
- int pc = (config & SMASK);
+
+ int pc = (md & SMASK);
int tc = pc + (short)(c >>> TC_SHIFT);
- int ac = pc + (int)(c >> AC_SHIFT);
+ int ac = pc + (int)(c >> RC_SHIFT);
if (ac < 0) // ignore transient negative
ac = 0;
- int rs = runState;
- String level = ((rs & TERMINATED) != 0 ? "Terminated" :
- (rs & STOP) != 0 ? "Terminating" :
- (rs & SHUTDOWN) != 0 ? "Shutting down" :
+ String level = ((md & TERMINATED) != 0 ? "Terminated" :
+ (md & STOP) != 0 ? "Terminating" :
+ (md & SHUTDOWN) != 0 ? "Shutting down" :
"Running");
return super.toString() +
"[" + level +
@@ -3196,7 +2887,7 @@
* @return {@code true} if all tasks have completed following shut down
*/
public boolean isTerminated() {
- return (runState & TERMINATED) != 0;
+ return (mode & TERMINATED) != 0;
}
/**
@@ -3213,8 +2904,8 @@
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
- int rs = runState;
- return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
+ int md = mode;
+ return (md & STOP) != 0 && (md & TERMINATED) == 0;
}
/**
@@ -3223,7 +2914,7 @@
* @return {@code true} if this pool has been shut down
*/
public boolean isShutdown() {
- return (runState & SHUTDOWN) != 0;
+ return (mode & SHUTDOWN) != 0;
}
/**
@@ -3287,30 +2978,19 @@
helpQuiescePool(wt.workQueue);
return true;
}
- long startTime = System.nanoTime();
- WorkQueue[] ws;
- int r = 0, wl;
- boolean found = true;
- while (!isQuiescent() && (ws = workQueues) != null &&
- (wl = ws.length) > 0) {
- if (!found) {
- if ((System.nanoTime() - startTime) > nanos)
+ else {
+ for (long startTime = System.nanoTime();;) {
+ ForkJoinTask<?> t;
+ if ((t = pollScan(false)) != null)
+ t.doExec();
+ else if (isQuiescent())
+ return true;
+ else if ((System.nanoTime() - startTime) > nanos)
return false;
- Thread.yield(); // cannot block
- }
- found = false;
- for (int m = wl - 1, j = (m + 1) << 2; j >= 0; --j) {
- ForkJoinTask<?> t; WorkQueue q; int b, k;
- if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
- (b = q.base) - q.top < 0) {
- found = true;
- if ((t = q.pollAt(b)) != null)
- t.doExec();
- break;
- }
+ else
+ Thread.yield(); // cannot block
}
}
- return true;
}
/**
@@ -3423,19 +3103,22 @@
*/
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
+ if (blocker == null) throw new NullPointerException();
ForkJoinPool p;
ForkJoinWorkerThread wt;
+ WorkQueue w;
Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) &&
- (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
- WorkQueue w = wt.workQueue;
+ (p = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+ (w = wt.workQueue) != null) {
+ int block;
while (!blocker.isReleasable()) {
- if (p.tryCompensate(w)) {
+ if ((block = p.tryCompensate(w)) != 0) {
try {
do {} while (!blocker.isReleasable() &&
!blocker.block());
} finally {
- U.getAndAddLong(p, CTL, AC_UNIT);
+ CTL.getAndAdd(p, (block > 0) ? RC_UNIT : 0L);
}
break;
}
@@ -3447,6 +3130,29 @@
}
}
+ /**
+ * If the given executor is a ForkJoinPool, poll and execute
+ * AsynchronousCompletionTasks from worker's queue until none are
+ * available or blocker is released.
+ */
+ static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
+ if (e instanceof ForkJoinPool) {
+ WorkQueue w; ForkJoinWorkerThread wt; WorkQueue[] ws; int r, n;
+ ForkJoinPool p = (ForkJoinPool)e;
+ Thread thread = Thread.currentThread();
+ if (thread instanceof ForkJoinWorkerThread &&
+ (wt = (ForkJoinWorkerThread)thread).pool == p)
+ w = wt.workQueue;
+ else if ((r = ThreadLocalRandom.getProbe()) != 0 &&
+ (ws = p.workQueues) != null && (n = ws.length) > 0)
+ w = ws[(n - 1) & r & SQMASK];
+ else
+ w = null;
+ if (w != null)
+ w.helpAsyncBlocker(blocker);
+ }
+ }
+
// AbstractExecutorService overrides. These rely on undocumented
// fact that ForkJoinTask.adapt returns ForkJoinTasks that also
// implement RunnableFuture.
@@ -3459,26 +3165,19 @@
return new ForkJoinTask.AdaptedCallable<T>(callable);
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long CTL;
- private static final long RUNSTATE;
- private static final int ABASE;
- private static final int ASHIFT;
+ // VarHandle mechanics
+ private static final VarHandle CTL;
+ private static final VarHandle MODE;
+ static final VarHandle QA;
static {
try {
- CTL = U.objectFieldOffset
- (ForkJoinPool.class.getDeclaredField("ctl"));
- RUNSTATE = U.objectFieldOffset
- (ForkJoinPool.class.getDeclaredField("runState"));
- ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
- int scale = U.arrayIndexScale(ForkJoinTask[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ CTL = l.findVarHandle(ForkJoinPool.class, "ctl", long.class);
+ MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
+ QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
@@ -3498,52 +3197,11 @@
new DefaultForkJoinWorkerThreadFactory();
modifyThreadPermission = new RuntimePermission("modifyThread");
- common = java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction<ForkJoinPool>() {
- public ForkJoinPool run() { return makeCommonPool(); }});
+ common = AccessController.doPrivileged(new PrivilegedAction<>() {
+ public ForkJoinPool run() {
+ return new ForkJoinPool((byte)0); }});
- // report 1 even if threads disabled
- COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
- }
-
- /**
- * Creates and returns the common pool, respecting user settings
- * specified via system properties.
- */
- static ForkJoinPool makeCommonPool() {
- int parallelism = -1;
- ForkJoinWorkerThreadFactory factory = null;
- UncaughtExceptionHandler handler = null;
- try { // ignore exceptions in accessing/parsing properties
- String pp = System.getProperty
- ("java.util.concurrent.ForkJoinPool.common.parallelism");
- String fp = System.getProperty
- ("java.util.concurrent.ForkJoinPool.common.threadFactory");
- String hp = System.getProperty
- ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
- if (pp != null)
- parallelism = Integer.parseInt(pp);
- if (fp != null)
- factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
- getSystemClassLoader().loadClass(fp).newInstance());
- if (hp != null)
- handler = ((UncaughtExceptionHandler)ClassLoader.
- getSystemClassLoader().loadClass(hp).newInstance());
- } catch (Exception ignore) {
- }
- if (factory == null) {
- if (System.getSecurityManager() == null)
- factory = defaultForkJoinWorkerThreadFactory;
- else // use security-managed default
- factory = new InnocuousForkJoinWorkerThreadFactory();
- }
- if (parallelism < 0 && // default 1 less than #cores
- (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
- parallelism = 1;
- if (parallelism > MAX_CAP)
- parallelism = MAX_CAP;
- return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
- "ForkJoinPool.commonPool-worker-");
+ COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
}
/**
@@ -3556,27 +3214,20 @@
* An ACC to restrict permissions for the factory itself.
* The constructed workers have no permissions set.
*/
- private static final AccessControlContext innocuousAcc;
- static {
- Permissions innocuousPerms = new Permissions();
- innocuousPerms.add(modifyThreadPermission);
- innocuousPerms.add(new RuntimePermission(
- "enableContextClassLoaderOverride"));
- innocuousPerms.add(new RuntimePermission(
- "modifyThreadGroup"));
- innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
- new ProtectionDomain(null, innocuousPerms)
- });
- }
+ private static final AccessControlContext ACC = contextWithPermissions(
+ modifyThreadPermission,
+ new RuntimePermission("enableContextClassLoaderOverride"),
+ new RuntimePermission("modifyThreadGroup"),
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
- return java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<>() {
public ForkJoinWorkerThread run() {
return new ForkJoinWorkerThread.
- InnocuousForkJoinWorkerThread(pool);
- }}, innocuousAcc);
+ InnocuousForkJoinWorkerThread(pool); }},
+ ACC);
}
}
-
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
index efccfa5..fd28e84 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -36,6 +36,8 @@
package java.util.concurrent;
import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
@@ -96,7 +98,7 @@
* encountering the exception; minimally only the latter.
*
* <p>It is possible to define and use ForkJoinTasks that may block,
- * but doing do requires three further considerations: (1) Completion
+ * but doing so requires three further considerations: (1) Completion
* of few if any <em>other</em> tasks should be dependent on a task
* that blocks on external synchronization or I/O. Event-style async
* tasks that are never joined (for example, those subclassing {@link
@@ -136,11 +138,11 @@
* {@link #isCompletedNormally} is true if a task completed without
* cancellation or encountering an exception; {@link #isCancelled} is
* true if the task was cancelled (in which case {@link #getException}
- * returns a {@link java.util.concurrent.CancellationException}); and
+ * returns a {@link CancellationException}); and
* {@link #isCompletedAbnormally} is true if a task was either
* cancelled or encountered an exception, in which case {@link
* #getException} will return either the encountered exception or
- * {@link java.util.concurrent.CancellationException}.
+ * {@link CancellationException}.
*
* <p>The ForkJoinTask class is not usually directly subclassed.
* Instead, you subclass one of the abstract classes that support a
@@ -221,52 +223,59 @@
* methods in a way that flows well in javadocs.
*/
- /*
+ /**
* The status field holds run control status bits packed into a
- * single int to minimize footprint and to ensure atomicity (via
- * CAS). Status is initially zero, and takes on nonnegative
- * values until completed, upon which status (anded with
- * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks
- * undergoing blocking waits by other threads have the SIGNAL bit
- * set. Completion of a stolen task with SIGNAL set awakens any
- * waiters via notifyAll. Even though suboptimal for some
- * purposes, we use basic builtin wait/notify to take advantage of
- * "monitor inflation" in JVMs that we would otherwise need to
- * emulate to avoid adding further per-task bookkeeping overhead.
- * We want these monitors to be "fat", i.e., not use biasing or
- * thin-lock techniques, so use some odd coding idioms that tend
- * to avoid them, mainly by arranging that every synchronized
- * block performs a wait, notifyAll or both.
+ * single int to ensure atomicity. Status is initially zero, and
+ * takes on nonnegative values until completed, upon which it
+ * holds (sign bit) DONE, possibly with ABNORMAL (cancelled or
+ * exceptional) and THROWN (in which case an exception has been
+ * stored). Tasks with dependent blocked waiting joiners have the
+ * SIGNAL bit set. Completion of a task with SIGNAL set awakens
+ * any waiters via notifyAll. (Waiters also help signal others
+ * upon completion.)
*
* These control bits occupy only (some of) the upper half (16
* bits) of status field. The lower bits are used for user-defined
* tags.
*/
-
- /** The run status of this task */
volatile int status; // accessed directly by pool and workers
- static final int DONE_MASK = 0xf0000000; // mask out non-completion bits
- static final int NORMAL = 0xf0000000; // must be negative
- static final int CANCELLED = 0xc0000000; // must be < NORMAL
- static final int EXCEPTIONAL = 0x80000000; // must be < CANCELLED
- static final int SIGNAL = 0x00010000; // must be >= 1 << 16
- static final int SMASK = 0x0000ffff; // short bits for tags
+
+ private static final int DONE = 1 << 31; // must be negative
+ private static final int ABNORMAL = 1 << 18; // set atomically with DONE
+ private static final int THROWN = 1 << 17; // set atomically with ABNORMAL
+ private static final int SIGNAL = 1 << 16; // true if joiner waiting
+ private static final int SMASK = 0xffff; // short bits for tags
+
+ static boolean isExceptionalStatus(int s) { // needed by subclasses
+ return (s & THROWN) != 0;
+ }
/**
- * Marks completion and wakes up threads waiting to join this
- * task.
+ * Sets DONE status and wakes up threads waiting to join this task.
*
- * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
- * @return completion status on exit
+ * @return status on exit
*/
- private int setCompletion(int completion) {
- for (int s;;) {
+ private int setDone() {
+ int s;
+ if (((s = (int)STATUS.getAndBitwiseOr(this, DONE)) & SIGNAL) != 0)
+ synchronized (this) { notifyAll(); }
+ return s | DONE;
+ }
+
+ /**
+ * Marks cancelled or exceptional completion unless already done.
+ *
+ * @param completion must be DONE | ABNORMAL, ORed with THROWN if exceptional
+ * @return status on exit
+ */
+ private int abnormalCompletion(int completion) {
+ for (int s, ns;;) {
if ((s = status) < 0)
return s;
- if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
- if ((s >>> 16) != 0)
+ else if (STATUS.weakCompareAndSet(this, s, ns = s | completion)) {
+ if ((s & SIGNAL) != 0)
synchronized (this) { notifyAll(); }
- return completion;
+ return ns;
}
}
}
@@ -284,10 +293,11 @@
try {
completed = exec();
} catch (Throwable rex) {
- return setExceptionalCompletion(rex);
+ completed = false;
+ s = setExceptionalCompletion(rex);
}
if (completed)
- s = setCompletion(NORMAL);
+ s = setDone();
}
return s;
}
@@ -299,9 +309,7 @@
* @param timeout using Object.wait conventions.
*/
final void internalWait(long timeout) {
- int s;
- if ((s = status) >= 0 && // force completer to issue notify
- U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ if ((int)STATUS.getAndBitwiseOr(this, SIGNAL) >= 0) {
synchronized (this) {
if (status >= 0)
try { wait(timeout); } catch (InterruptedException ie) { }
@@ -316,27 +324,24 @@
* @return status upon completion
*/
private int externalAwaitDone() {
- int s = ((this instanceof CountedCompleter) ? // try helping
- ForkJoinPool.common.externalHelpComplete(
- (CountedCompleter<?>)this, 0) :
- ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
- if (s >= 0 && (s = status) >= 0) {
+ int s = tryExternalHelp();
+ if (s >= 0 && (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
boolean interrupted = false;
- do {
- if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0) {
- try {
- wait(0L);
- } catch (InterruptedException ie) {
- interrupted = true;
- }
+ synchronized (this) {
+ for (;;) {
+ if ((s = status) >= 0) {
+ try {
+ wait(0L);
+ } catch (InterruptedException ie) {
+ interrupted = true;
}
- else
- notifyAll();
+ }
+ else {
+ notifyAll();
+ break;
}
}
- } while ((s = status) >= 0);
+ }
if (interrupted)
Thread.currentThread().interrupt();
}
@@ -347,30 +352,40 @@
* Blocks a non-worker-thread until completion or interruption.
*/
private int externalInterruptibleAwaitDone() throws InterruptedException {
- int s;
- if (Thread.interrupted())
- throw new InterruptedException();
- if ((s = status) >= 0 &&
- (s = ((this instanceof CountedCompleter) ?
- ForkJoinPool.common.externalHelpComplete(
- (CountedCompleter<?>)this, 0) :
- ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
- 0)) >= 0) {
- while ((s = status) >= 0) {
- if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0)
- wait(0L);
- else
- notifyAll();
+ int s = tryExternalHelp();
+ if (s >= 0 && (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
+ synchronized (this) {
+ for (;;) {
+ if ((s = status) >= 0)
+ wait(0L);
+ else {
+ notifyAll();
+ break;
}
}
}
}
+ else if (Thread.interrupted())
+ throw new InterruptedException();
return s;
}
/**
+ * Tries to help with tasks allowed for external callers.
+ *
+ * @return current status
+ */
+ private int tryExternalHelp() {
+ int s;
+ return ((s = status) < 0 ? s:
+ (this instanceof CountedCompleter) ?
+ ForkJoinPool.common.externalHelpComplete(
+ (CountedCompleter<?>)this, 0) :
+ ForkJoinPool.common.tryExternalUnpush(this) ?
+ doExec() : 0);
+ }
+
+ /**
* Implementation for join, get, quietlyJoin. Directly handles
* only cases of already-completed, external wait, and
* unfork+exec. Others are relayed to ForkJoinPool.awaitJoin.
@@ -404,22 +419,24 @@
// Exception table support
/**
- * Table of exceptions thrown by tasks, to enable reporting by
- * callers. Because exceptions are rare, we don't directly keep
+ * Hash table of exceptions thrown by tasks, to enable reporting
+ * by callers. Because exceptions are rare, we don't directly keep
* them with task objects, but instead use a weak ref table. Note
* that cancellation exceptions don't appear in the table, but are
* instead recorded as status values.
*
- * Note: These statics are initialized below in static block.
+ * The exception table has a fixed capacity.
*/
- private static final ExceptionNode[] exceptionTable;
- private static final ReentrantLock exceptionTableLock;
- private static final ReferenceQueue<Object> exceptionTableRefQueue;
+ private static final ExceptionNode[] exceptionTable
+ = new ExceptionNode[32];
- /**
- * Fixed capacity for exceptionTable.
- */
- private static final int EXCEPTION_MAP_CAPACITY = 32;
+ /** Lock protecting access to exceptionTable. */
+ private static final ReentrantLock exceptionTableLock
+ = new ReentrantLock();
+
+ /** Reference queue of stale exceptionally completed tasks. */
+ private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
+ = new ReferenceQueue<>();
/**
* Key-value nodes for exception table. The chained hash table
@@ -439,7 +456,7 @@
final long thrower; // use id not ref to avoid weak cycles
final int hashCode; // store task hashCode before weak ref disappears
ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
- ReferenceQueue<Object> exceptionTableRefQueue) {
+ ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue) {
super(task, exceptionTableRefQueue);
this.ex = ex;
this.next = next;
@@ -475,7 +492,7 @@
} finally {
lock.unlock();
}
- s = setCompletion(EXCEPTIONAL);
+ s = abnormalCompletion(DONE | ABNORMAL | THROWN);
}
return s;
}
@@ -487,7 +504,7 @@
*/
private int setExceptionalCompletion(Throwable ex) {
int s = recordExceptionalCompletion(ex);
- if ((s & DONE_MASK) == EXCEPTIONAL)
+ if ((s & THROWN) != 0)
internalPropagateException(ex);
return s;
}
@@ -603,9 +620,8 @@
private static void expungeStaleExceptions() {
for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
if (x instanceof ExceptionNode) {
- int hashCode = ((ExceptionNode)x).hashCode;
ExceptionNode[] t = exceptionTable;
- int i = hashCode & (t.length - 1);
+ int i = ((ExceptionNode)x).hashCode & (t.length - 1);
ExceptionNode e = t[i];
ExceptionNode pred = null;
while (e != null) {
@@ -663,10 +679,8 @@
* Throws exception, if any, associated with the given status.
*/
private void reportException(int s) {
- if (s == CANCELLED)
- throw new CancellationException();
- if (s == EXCEPTIONAL)
- rethrow(getThrowableException());
+ rethrow((s & THROWN) != 0 ? getThrowableException() :
+ new CancellationException());
}
// public methods
@@ -696,19 +710,19 @@
}
/**
- * Returns the result of the computation when it {@link #isDone is
- * done}. This method differs from {@link #get()} in that
- * abnormal completion results in {@code RuntimeException} or
- * {@code Error}, not {@code ExecutionException}, and that
- * interrupts of the calling thread do <em>not</em> cause the
- * method to abruptly return by throwing {@code
- * InterruptedException}.
+ * Returns the result of the computation when it
+ * {@linkplain #isDone is done}.
+ * This method differs from {@link #get()} in that abnormal
+ * completion results in {@code RuntimeException} or {@code Error},
+ * not {@code ExecutionException}, and that interrupts of the
+ * calling thread do <em>not</em> cause the method to abruptly
+ * return by throwing {@code InterruptedException}.
*
* @return the computed result
*/
public final V join() {
int s;
- if ((s = doJoin() & DONE_MASK) != NORMAL)
+ if (((s = doJoin()) & ABNORMAL) != 0)
reportException(s);
return getRawResult();
}
@@ -723,7 +737,7 @@
*/
public final V invoke() {
int s;
- if ((s = doInvoke() & DONE_MASK) != NORMAL)
+ if (((s = doInvoke()) & ABNORMAL) != 0)
reportException(s);
return getRawResult();
}
@@ -748,9 +762,9 @@
public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
int s1, s2;
t2.fork();
- if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
+ if (((s1 = t1.doInvoke()) & ABNORMAL) != 0)
t1.reportException(s1);
- if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
+ if (((s2 = t2.doJoin()) & ABNORMAL) != 0)
t2.reportException(s2);
}
@@ -780,7 +794,7 @@
}
else if (i != 0)
t.fork();
- else if (t.doInvoke() < NORMAL && ex == null)
+ else if ((t.doInvoke() & ABNORMAL) != 0 && ex == null)
ex = t.getException();
}
for (int i = 1; i <= last; ++i) {
@@ -788,7 +802,7 @@
if (t != null) {
if (ex != null)
t.cancel(false);
- else if (t.doJoin() < NORMAL)
+ else if ((t.doJoin() & ABNORMAL) != 0)
ex = t.getException();
}
}
@@ -816,7 +830,7 @@
*/
public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
- invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
+ invokeAll(tasks.toArray(new ForkJoinTask<?>[0]));
return tasks;
}
@SuppressWarnings("unchecked")
@@ -832,7 +846,7 @@
}
else if (i != 0)
t.fork();
- else if (t.doInvoke() < NORMAL && ex == null)
+ else if ((t.doInvoke() & ABNORMAL) != 0 && ex == null)
ex = t.getException();
}
for (int i = 1; i <= last; ++i) {
@@ -840,7 +854,7 @@
if (t != null) {
if (ex != null)
t.cancel(false);
- else if (t.doJoin() < NORMAL)
+ else if ((t.doJoin() & ABNORMAL) != 0)
ex = t.getException();
}
}
@@ -877,7 +891,8 @@
* @return {@code true} if this task is now cancelled
*/
public boolean cancel(boolean mayInterruptIfRunning) {
- return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
+ int s = abnormalCompletion(DONE | ABNORMAL);
+ return (s & (ABNORMAL | THROWN)) == ABNORMAL;
}
public final boolean isDone() {
@@ -885,7 +900,7 @@
}
public final boolean isCancelled() {
- return (status & DONE_MASK) == CANCELLED;
+ return (status & (ABNORMAL | THROWN)) == ABNORMAL;
}
/**
@@ -894,7 +909,7 @@
* @return {@code true} if this task threw an exception or was cancelled
*/
public final boolean isCompletedAbnormally() {
- return status < NORMAL;
+ return (status & ABNORMAL) != 0;
}
/**
@@ -905,7 +920,7 @@
* exception and was not cancelled
*/
public final boolean isCompletedNormally() {
- return (status & DONE_MASK) == NORMAL;
+ return (status & (DONE | ABNORMAL)) == DONE;
}
/**
@@ -916,9 +931,9 @@
* @return the exception, or {@code null} if none
*/
public final Throwable getException() {
- int s = status & DONE_MASK;
- return ((s >= NORMAL) ? null :
- (s == CANCELLED) ? new CancellationException() :
+ int s = status;
+ return ((s & ABNORMAL) == 0 ? null :
+ (s & THROWN) == 0 ? new CancellationException() :
getThrowableException());
}
@@ -962,7 +977,7 @@
setExceptionalCompletion(rex);
return;
}
- setCompletion(NORMAL);
+ setDone();
}
/**
@@ -974,7 +989,7 @@
* @since 1.8
*/
public final void quietlyComplete() {
- setCompletion(NORMAL);
+ setDone();
}
/**
@@ -991,11 +1006,12 @@
public final V get() throws InterruptedException, ExecutionException {
int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
doJoin() : externalInterruptibleAwaitDone();
- if ((s &= DONE_MASK) == CANCELLED)
- throw new CancellationException();
- if (s == EXCEPTIONAL)
+ if ((s & THROWN) != 0)
throw new ExecutionException(getThrowableException());
- return getRawResult();
+ else if ((s & ABNORMAL) != 0)
+ throw new CancellationException();
+ else
+ return getRawResult();
}
/**
@@ -1035,7 +1051,7 @@
while ((s = status) >= 0 &&
(ns = deadline - System.nanoTime()) > 0L) {
if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
- U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ (s = (int)STATUS.getAndBitwiseOr(this, SIGNAL)) >= 0) {
synchronized (this) {
if (status >= 0)
wait(ms); // OK to throw InterruptedException
@@ -1047,15 +1063,13 @@
}
}
if (s >= 0)
- s = status;
- if ((s &= DONE_MASK) != NORMAL) {
- if (s == CANCELLED)
- throw new CancellationException();
- if (s != EXCEPTIONAL)
- throw new TimeoutException();
+ throw new TimeoutException();
+ else if ((s & THROWN) != 0)
throw new ExecutionException(getThrowableException());
- }
- return getRawResult();
+ else if ((s & ABNORMAL) != 0)
+ throw new CancellationException();
+ else
+ return getRawResult();
}
/**
@@ -1111,7 +1125,7 @@
* setRawResult(null)}.
*/
public void reinitialize() {
- if ((status & DONE_MASK) == EXCEPTIONAL)
+ if ((status & THROWN) != 0)
clearExceptionalCompletion();
else
status = 0;
@@ -1329,8 +1343,8 @@
*/
public final short setForkJoinTaskTag(short newValue) {
for (int s;;) {
- if (U.compareAndSwapInt(this, STATUS, s = status,
- (s & ~SMASK) | (newValue & SMASK)))
+ if (STATUS.weakCompareAndSet(this, s = status,
+ (s & ~SMASK) | (newValue & SMASK)))
return (short)s;
}
}
@@ -1353,8 +1367,8 @@
for (int s;;) {
if ((short)(s = status) != expect)
return false;
- if (U.compareAndSwapInt(this, STATUS, s,
- (s & ~SMASK) | (update & SMASK)))
+ if (STATUS.weakCompareAndSet(this, s,
+ (s & ~SMASK) | (update & SMASK)))
return true;
}
}
@@ -1377,6 +1391,9 @@
public final void setRawResult(T v) { result = v; }
public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); }
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + runnable + "]";
+ }
private static final long serialVersionUID = 5232453952276885070L;
}
@@ -1394,6 +1411,9 @@
public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); }
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + runnable + "]";
+ }
private static final long serialVersionUID = 5232453952276885070L;
}
@@ -1439,6 +1459,9 @@
}
}
public final void run() { invoke(); }
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + callable + "]";
+ }
private static final long serialVersionUID = 2838392045355241008L;
}
@@ -1515,19 +1538,14 @@
setExceptionalCompletion((Throwable)ex);
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATUS;
-
+ // VarHandle mechanics
+ private static final VarHandle STATUS;
static {
- exceptionTableLock = new ReentrantLock();
- exceptionTableRefQueue = new ReferenceQueue<Object>();
- exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
try {
- STATUS = U.objectFieldOffset
- (ForkJoinTask.class.getDeclaredField("status"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index e98ba99..fa47c22 100644
--- a/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -36,6 +36,8 @@
package java.util.concurrent;
import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
/**
@@ -47,7 +49,9 @@
* and termination methods surrounding the main task processing loop.
* If you do create such a subclass, you will also need to supply a
* custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
- * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
+ * {@linkplain ForkJoinPool#ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+ * UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit)
+ * use it} in a {@code ForkJoinPool}.
*
* @since 1.7
* @author Doug Lea
@@ -66,8 +70,9 @@
* owning thread.
*
* Support for (non-public) subclass InnocuousForkJoinWorkerThread
- * requires that we break quite a lot of encapsulation (via Unsafe)
- * both here and in the subclass to access and set Thread fields.
+ * requires that we break quite a lot of encapsulation (via helper
+ * methods in ThreadLocalRandom) both here and in the subclass to
+ * access and set Thread fields.
*/
final ForkJoinPool pool; // the pool this thread works in
@@ -87,13 +92,28 @@
}
/**
+ * Version for use by the default pool. Supports setting the
+ * context class loader. This is a separate constructor to avoid
+ * affecting the protected constructor.
+ */
+ ForkJoinWorkerThread(ForkJoinPool pool, ClassLoader ccl) {
+ super("aForkJoinWorkerThread");
+ super.setContextClassLoader(ccl);
+ this.pool = pool;
+ this.workQueue = pool.registerWorker(this);
+ }
+
+ /**
* Version for InnocuousForkJoinWorkerThread.
*/
- ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
+ ForkJoinWorkerThread(ForkJoinPool pool,
+ ClassLoader ccl,
+ ThreadGroup threadGroup,
AccessControlContext acc) {
super(threadGroup, null, "aForkJoinWorkerThread");
- U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
- eraseThreadLocals(); // clear before registering
+ super.setContextClassLoader(ccl);
+ ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
+ ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
this.pool = pool;
this.workQueue = pool.registerWorker(this);
}
@@ -171,66 +191,44 @@
}
/**
- * Erases ThreadLocals by nulling out Thread maps.
- */
- final void eraseThreadLocals() {
- U.putObject(this, THREADLOCALS, null);
- U.putObject(this, INHERITABLETHREADLOCALS, null);
- }
-
- /**
* Non-public hook method for InnocuousForkJoinWorkerThread.
*/
void afterTopLevelExec() {
}
- // Set up to allow setting thread fields in constructor
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long THREADLOCALS;
- private static final long INHERITABLETHREADLOCALS;
- private static final long INHERITEDACCESSCONTROLCONTEXT;
- static {
- try {
- THREADLOCALS = U.objectFieldOffset
- (Thread.class.getDeclaredField("threadLocals"));
- INHERITABLETHREADLOCALS = U.objectFieldOffset
- (Thread.class.getDeclaredField("inheritableThreadLocals"));
- INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
- (Thread.class.getDeclaredField("inheritedAccessControlContext"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
/**
* A worker thread that has no permissions, is not a member of any
- * user-defined ThreadGroup, and erases all ThreadLocals after
+ * user-defined ThreadGroup, uses the system class loader as
+ * thread context class loader, and erases all ThreadLocals after
* running each top-level task.
*/
static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
/** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
private static final ThreadGroup innocuousThreadGroup =
- createThreadGroup();
+ AccessController.doPrivileged(new PrivilegedAction<>() {
+ public ThreadGroup run() {
+ ThreadGroup group = Thread.currentThread().getThreadGroup();
+ for (ThreadGroup p; (p = group.getParent()) != null; )
+ group = p;
+ return new ThreadGroup(
+ group, "InnocuousForkJoinWorkerThreadGroup");
+ }});
/** An AccessControlContext supporting no privileges */
private static final AccessControlContext INNOCUOUS_ACC =
new AccessControlContext(
- new ProtectionDomain[] {
- new ProtectionDomain(null, null)
- });
+ new ProtectionDomain[] { new ProtectionDomain(null, null) });
InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
- super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
+ super(pool,
+ ClassLoader.getSystemClassLoader(),
+ innocuousThreadGroup,
+ INNOCUOUS_ACC);
}
@Override // to erase ThreadLocals
void afterTopLevelExec() {
- eraseThreadLocals();
- }
-
- @Override // to always report system loader
- public ClassLoader getContextClassLoader() {
- return ClassLoader.getSystemClassLoader();
+ ThreadLocalRandom.eraseThreadLocals(this);
}
@Override // to silently fail
@@ -240,34 +238,5 @@
public void setContextClassLoader(ClassLoader cl) {
throw new SecurityException("setContextClassLoader");
}
-
- /**
- * Returns a new group with the system ThreadGroup (the
- * topmost, parent-less group) as parent. Uses Unsafe to
- * traverse Thread.group and ThreadGroup.parent fields.
- */
- private static ThreadGroup createThreadGroup() {
- try {
- sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
- long tg = u.objectFieldOffset
- (Thread.class.getDeclaredField("group"));
- long gp = u.objectFieldOffset
- (ThreadGroup.class.getDeclaredField("parent"));
- ThreadGroup group = (ThreadGroup)
- u.getObject(Thread.currentThread(), tg);
- while (group != null) {
- ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
- if (parent == null)
- return new ThreadGroup(group,
- "InnocuousForkJoinWorkerThreadGroup");
- group = parent;
- }
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- // fall through if null as cannot-happen safeguard
- throw new Error("Cannot create ThreadGroup");
- }
}
-
}
diff --git a/ojluni/src/main/java/java/util/concurrent/Future.java b/ojluni/src/main/java/java/util/concurrent/Future.java
index 9bd05d6..6099c7c 100644
--- a/ojluni/src/main/java/java/util/concurrent/Future.java
+++ b/ojluni/src/main/java/java/util/concurrent/Future.java
@@ -50,8 +50,7 @@
* declare types of the form {@code Future<?>} and
* return {@code null} as a result of the underlying task.
*
- * <p>
- * <b>Sample Usage</b> (Note that the following classes are all
+ * <p><b>Sample Usage</b> (Note that the following classes are all
* made-up.)
*
* <pre> {@code
@@ -59,13 +58,9 @@
* class App {
* ExecutorService executor = ...
* ArchiveSearcher searcher = ...
- * void showSearch(final String target)
- * throws InterruptedException {
- * Future<String> future
- * = executor.submit(new Callable<String>() {
- * public String call() {
- * return searcher.search(target);
- * }});
+ * void showSearch(String target) throws InterruptedException {
+ * Callable<String> task = () -> searcher.search(target);
+ * Future<String> future = executor.submit(task);
* displayOtherThings(); // do other things while searching
* try {
* displayText(future.get()); // use future
@@ -77,11 +72,7 @@
* implements {@code Runnable}, and so may be executed by an {@code Executor}.
* For example, the above construction with {@code submit} could be replaced by:
* <pre> {@code
- * FutureTask<String> future =
- * new FutureTask<>(new Callable<String>() {
- * public String call() {
- * return searcher.search(target);
- * }});
+ * FutureTask<String> future = new FutureTask<>(task);
* executor.execute(future);}</pre>
*
* <p>Memory consistency effects: Actions taken by the asynchronous computation
diff --git a/ojluni/src/main/java/java/util/concurrent/FutureTask.java b/ojluni/src/main/java/java/util/concurrent/FutureTask.java
index 62c2bfc..e913ef3 100644
--- a/ojluni/src/main/java/java/util/concurrent/FutureTask.java
+++ b/ojluni/src/main/java/java/util/concurrent/FutureTask.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
/**
@@ -69,9 +71,6 @@
* cancellation races. Sync control in the current design relies
* on a "state" field updated via CAS to track completion, along
* with a simple Treiber stack to hold waiting threads.
- *
- * Style note: As usual, we bypass overhead of using
- * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
*/
/**
@@ -163,9 +162,8 @@
}
public boolean cancel(boolean mayInterruptIfRunning) {
- if (!(state == NEW &&
- U.compareAndSwapInt(this, STATE, NEW,
- mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+ if (!(state == NEW && STATE.compareAndSet
+ (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
@@ -174,7 +172,7 @@
if (t != null)
t.interrupt();
} finally { // final state
- U.putOrderedInt(this, STATE, INTERRUPTED);
+ STATE.setRelease(this, INTERRUPTED);
}
}
} finally {
@@ -228,9 +226,9 @@
* @param v the value
*/
protected void set(V v) {
- if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+ if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = v;
- U.putOrderedInt(this, STATE, NORMAL); // final state
+ STATE.setRelease(this, NORMAL); // final state
finishCompletion();
}
}
@@ -246,16 +244,16 @@
* @param t the cause of failure
*/
protected void setException(Throwable t) {
- if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+ if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = t;
- U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
+ STATE.setRelease(this, EXCEPTIONAL); // final state
finishCompletion();
}
}
public void run() {
if (state != NEW ||
- !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+ !RUNNER.compareAndSet(this, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
@@ -296,7 +294,7 @@
*/
protected boolean runAndReset() {
if (state != NEW ||
- !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+ !RUNNER.compareAndSet(this, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
@@ -363,7 +361,7 @@
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
- if (U.compareAndSwapObject(this, WAITERS, q, null)) {
+ if (WAITERS.weakCompareAndSet(this, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
@@ -425,8 +423,7 @@
q = new WaitNode();
}
else if (!queued)
- queued = U.compareAndSwapObject(this, WAITERS,
- q.next = waiters, q);
+ queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
else if (timed) {
final long parkNanos;
if (startTime == 0L) { // first time
@@ -475,7 +472,7 @@
if (pred.thread == null) // check for race
continue retry;
}
- else if (!U.compareAndSwapObject(this, WAITERS, q, s))
+ else if (!WAITERS.compareAndSet(this, q, s))
continue retry;
}
break;
@@ -483,21 +480,53 @@
}
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long RUNNER;
- private static final long WAITERS;
+ /**
+ * Returns a string representation of this FutureTask.
+ *
+ * @implSpec
+ * The default implementation returns a string identifying this
+ * FutureTask, as well as its completion state. The state, in
+ * brackets, contains one of the strings {@code "Completed Normally"},
+ * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
+ * "Not completed"}.
+ *
+ * @return a string representation of this FutureTask
+ */
+ public String toString() {
+ final String status;
+ switch (state) {
+ case NORMAL:
+ status = "[Completed normally]";
+ break;
+ case EXCEPTIONAL:
+ status = "[Completed exceptionally: " + outcome + "]";
+ break;
+ case CANCELLED:
+ case INTERRUPTING:
+ case INTERRUPTED:
+ status = "[Cancelled]";
+ break;
+ default:
+ final Callable<?> callable = this.callable;
+ status = (callable == null)
+ ? "[Not completed]"
+ : "[Not completed, task = " + callable + "]";
+ }
+ return super.toString() + status;
+ }
+
+ // VarHandle mechanics
+ private static final VarHandle STATE;
+ private static final VarHandle RUNNER;
+ private static final VarHandle WAITERS;
static {
try {
- STATE = U.objectFieldOffset
- (FutureTask.class.getDeclaredField("state"));
- RUNNER = U.objectFieldOffset
- (FutureTask.class.getDeclaredField("runner"));
- WAITERS = U.objectFieldOffset
- (FutureTask.class.getDeclaredField("waiters"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATE = l.findVarHandle(FutureTask.class, "state", int.class);
+ RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
+ WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
index 9829c9c..f55998e 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
@@ -39,15 +39,13 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
/**
* An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
@@ -66,9 +64,12 @@
* contains}, {@link #iterator iterator.remove()}, and the bulk
* operations, all of which run in linear time.
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
*
* @since 1.6
* @author Doug Lea
@@ -194,18 +195,7 @@
*/
public LinkedBlockingDeque(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
- final ReentrantLock lock = this.lock;
- lock.lock(); // Never contended, but necessary for visibility
- try {
- for (E e : c) {
- if (e == null)
- throw new NullPointerException();
- if (!linkLast(new Node<E>(e)))
- throw new IllegalStateException("Deque full");
- }
- } finally {
- lock.unlock();
- }
+ addAll(c);
}
@@ -298,6 +288,7 @@
*/
void unlink(Node<E> x) {
// assert lock.isHeldByCurrentThread();
+ // assert x.item != null;
Node<E> p = x.prev;
Node<E> n = x.next;
if (p == null) {
@@ -660,7 +651,7 @@
/**
* Retrieves and removes the head of the queue represented by this deque.
- * This method differs from {@link #poll poll} only in that it throws an
+ * This method differs from {@link #poll() poll()} only in that it throws an
* exception if this deque is empty.
*
* <p>This method is equivalent to {@link #removeFirst() removeFirst}.
@@ -686,7 +677,7 @@
/**
* Retrieves, but does not remove, the head of the queue represented by
- * this deque. This method differs from {@link #peek peek} only in that
+ * this deque. This method differs from {@link #peek() peek()} only in that
* it throws an exception if this deque is empty.
*
* <p>This method is equivalent to {@link #getFirst() getFirst}.
@@ -740,8 +731,7 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -834,46 +824,65 @@
}
}
- /*
- * TODO: Add support for more efficient bulk operations.
+ /**
+ * Appends all of the elements in the specified collection to the end of
+ * this deque, in the order that they are returned by the specified
+ * collection's iterator. Attempts to {@code addAll} of a deque to
+ * itself result in {@code IllegalArgumentException}.
*
- * We don't want to acquire the lock for every iteration, but we
- * also want other threads a chance to interact with the
- * collection, especially when count is close to capacity.
+ * @param c the elements to be inserted into this deque
+ * @return {@code true} if this deque changed as a result of the call
+ * @throws NullPointerException if the specified collection or any
+ * of its elements are null
+ * @throws IllegalArgumentException if the collection is this deque
+ * @throws IllegalStateException if this deque is full
+ * @see #add(Object)
*/
+ public boolean addAll(Collection<? extends E> c) {
+ if (c == this)
+ // As historically specified in AbstractQueue#addAll
+ throw new IllegalArgumentException();
-// /**
-// * Adds all of the elements in the specified collection to this
-// * queue. Attempts to addAll of a queue to itself result in
-// * {@code IllegalArgumentException}. Further, the behavior of
-// * this operation is undefined if the specified collection is
-// * modified while the operation is in progress.
-// *
-// * @param c collection containing elements to be added to this queue
-// * @return {@code true} if this queue changed as a result of the call
-// * @throws ClassCastException {@inheritDoc}
-// * @throws NullPointerException {@inheritDoc}
-// * @throws IllegalArgumentException {@inheritDoc}
-// * @throws IllegalStateException if this deque is full
-// * @see #add(Object)
-// */
-// public boolean addAll(Collection<? extends E> c) {
-// if (c == null)
-// throw new NullPointerException();
-// if (c == this)
-// throw new IllegalArgumentException();
-// final ReentrantLock lock = this.lock;
-// lock.lock();
-// try {
-// boolean modified = false;
-// for (E e : c)
-// if (linkLast(e))
-// modified = true;
-// return modified;
-// } finally {
-// lock.unlock();
-// }
-// }
+ // Copy c into a private chain of Nodes
+ Node<E> beg = null, end = null;
+ int n = 0;
+ for (E e : c) {
+ Objects.requireNonNull(e);
+ n++;
+ Node<E> newNode = new Node<E>(e);
+ if (beg == null)
+ beg = end = newNode;
+ else {
+ end.next = newNode;
+ newNode.prev = end;
+ end = newNode;
+ }
+ }
+ if (beg == null)
+ return false;
+
+ // Atomically append the chain at the end
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ if (count + n <= capacity) {
+ beg.prev = last;
+ if (first == null)
+ first = beg;
+ else
+ last.next = beg;
+ last = end;
+ count += n;
+ notEmpty.signalAll();
+ return true;
+ }
+ } finally {
+ lock.unlock();
+ }
+ // Fall back to historic non-atomic implementation, failing
+ // with IllegalStateException when the capacity is exceeded.
+ return super.addAll(c);
+ }
/**
* Returns an array containing all of the elements in this deque, in
@@ -986,6 +995,18 @@
}
/**
+ * Used for any element traversal that is not entirely under lock.
+ * Such traversals must handle both:
+ * - dequeued nodes (p.next == p)
+ * - (possibly multiple) interior removed nodes (p.item == null)
+ */
+ Node<E> succ(Node<E> p) {
+ if (p == (p = p.next))
+ p = first;
+ return p;
+ }
+
+ /**
* Returns an iterator over the elements in this deque in proper sequence.
* The elements will be returned in order from first (head) to last (tail).
*
@@ -1024,8 +1045,8 @@
/**
* nextItem holds on to item fields because once we claim that
* an element exists in hasNext(), we must return item read
- * under lock (in advance()) even if it was in the process of
- * being removed when hasNext() was called.
+ * under lock even if it was in the process of being removed
+ * when hasNext() was called.
*/
E nextItem;
@@ -1038,48 +1059,19 @@
abstract Node<E> firstNode();
abstract Node<E> nextNode(Node<E> n);
+ private Node<E> succ(Node<E> p) {
+ if (p == (p = nextNode(p)))
+ p = firstNode();
+ return p;
+ }
+
AbstractItr() {
// set to initial position
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
- next = firstNode();
- nextItem = (next == null) ? null : next.item;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Returns the successor node of the given non-null, but
- * possibly previously deleted, node.
- */
- private Node<E> succ(Node<E> n) {
- // Chains of deleted nodes ending in null or self-links
- // are possible if multiple interior nodes are removed.
- for (;;) {
- Node<E> s = nextNode(n);
- if (s == null)
- return null;
- else if (s.item != null)
- return s;
- else if (s == n)
- return firstNode();
- else
- n = s;
- }
- }
-
- /**
- * Advances next.
- */
- void advance() {
- final ReentrantLock lock = LinkedBlockingDeque.this.lock;
- lock.lock();
- try {
- // assert next != null;
- next = succ(next);
- nextItem = (next == null) ? null : next.item;
+ if ((next = firstNode()) != null)
+ nextItem = next.item;
} finally {
lock.unlock();
}
@@ -1090,14 +1082,65 @@
}
public E next() {
- if (next == null)
+ Node<E> p;
+ if ((p = next) == null)
throw new NoSuchElementException();
- lastRet = next;
+ lastRet = p;
E x = nextItem;
- advance();
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+ lock.lock();
+ try {
+ E e = null;
+ for (p = nextNode(p); p != null && (e = p.item) == null; )
+ p = succ(p);
+ next = p;
+ nextItem = e;
+ } finally {
+ lock.unlock();
+ }
return x;
}
+ public void forEachRemaining(Consumer<? super E> action) {
+ // A variant of forEachFrom
+ Objects.requireNonNull(action);
+ Node<E> p;
+ if ((p = next) == null) return;
+ lastRet = p;
+ next = null;
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+ final int batchSize = 64;
+ Object[] es = null;
+ int n, len = 1;
+ do {
+ lock.lock();
+ try {
+ if (es == null) {
+ p = nextNode(p);
+ for (Node<E> q = p; q != null; q = succ(q))
+ if (q.item != null && ++len == batchSize)
+ break;
+ es = new Object[len];
+ es[0] = nextItem;
+ nextItem = null;
+ n = 1;
+ } else
+ n = 0;
+ for (; p != null && n < len; p = succ(p))
+ if ((es[n] = p.item) != null) {
+ lastRet = p;
+ n++;
+ }
+ } finally {
+ lock.unlock();
+ }
+ for (int i = 0; i < n; i++) {
+ @SuppressWarnings("unchecked") E e = (E) es[i];
+ action.accept(e);
+ }
+ } while (n > 0 && p != null);
+ }
+
public void remove() {
Node<E> n = lastRet;
if (n == null)
@@ -1116,51 +1159,49 @@
/** Forward iterator */
private class Itr extends AbstractItr {
+ Itr() {} // prevent access constructor creation
Node<E> firstNode() { return first; }
Node<E> nextNode(Node<E> n) { return n.next; }
}
/** Descending iterator */
private class DescendingItr extends AbstractItr {
+ DescendingItr() {} // prevent access constructor creation
Node<E> firstNode() { return last; }
Node<E> nextNode(Node<E> n) { return n.prev; }
}
- /** A customized variant of Spliterators.IteratorSpliterator */
- static final class LBDSpliterator<E> implements Spliterator<E> {
+ /**
+ * A customized variant of Spliterators.IteratorSpliterator.
+ * Keep this class in sync with (very similar) LBQSpliterator.
+ */
+ private final class LBDSpliterator implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25; // max batch array size;
- final LinkedBlockingDeque<E> queue;
Node<E> current; // current node; null until initialized
int batch; // batch size for splits
boolean exhausted; // true when no more nodes
- long est; // size estimate
- LBDSpliterator(LinkedBlockingDeque<E> queue) {
- this.queue = queue;
- this.est = queue.size();
- }
+ long est = size(); // size estimate
+
+ LBDSpliterator() {}
public long estimateSize() { return est; }
public Spliterator<E> trySplit() {
Node<E> h;
- final LinkedBlockingDeque<E> q = this.queue;
- int b = batch;
- int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
- ((h = current) != null || (h = q.first) != null) &&
- h.next != null) {
+ ((h = current) != null || (h = first) != null)
+ && h.next != null) {
+ int n = batch = Math.min(batch + 1, MAX_BATCH);
Object[] a = new Object[n];
- final ReentrantLock lock = q.lock;
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
int i = 0;
Node<E> p = current;
lock.lock();
try {
- if (p != null || (p = q.first) != null) {
- do {
+ if (p != null || (p = first) != null)
+ for (; p != null && i < n; p = succ(p))
if ((a[i] = p.item) != null)
- ++i;
- } while ((p = p.next) != null && i < n);
- }
+ i++;
} finally {
lock.unlock();
}
@@ -1170,66 +1211,33 @@
}
else if ((est -= i) < 0L)
est = 0L;
- if (i > 0) {
- batch = i;
+ if (i > 0)
return Spliterators.spliterator
(a, 0, i, (Spliterator.ORDERED |
Spliterator.NONNULL |
Spliterator.CONCURRENT));
- }
}
return null;
}
- public void forEachRemaining(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
- final LinkedBlockingDeque<E> q = this.queue;
- final ReentrantLock lock = q.lock;
- if (!exhausted) {
- exhausted = true;
- Node<E> p = current;
- do {
- E e = null;
- lock.lock();
- try {
- if (p == null)
- p = q.first;
- while (p != null) {
- e = p.item;
- p = p.next;
- if (e != null)
- break;
- }
- } finally {
- lock.unlock();
- }
- if (e != null)
- action.accept(e);
- } while (p != null);
- }
- }
-
public boolean tryAdvance(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
- final LinkedBlockingDeque<E> q = this.queue;
- final ReentrantLock lock = q.lock;
+ Objects.requireNonNull(action);
if (!exhausted) {
E e = null;
+ final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
- if (current == null)
- current = q.first;
- while (current != null) {
- e = current.item;
- current = current.next;
- if (e != null)
- break;
- }
+ Node<E> p;
+ if ((p = current) != null || (p = first) != null)
+ do {
+ e = p.item;
+ p = succ(p);
+ } while (e == null && p != null);
+ if ((current = p) == null)
+ exhausted = true;
} finally {
lock.unlock();
}
- if (current == null)
- exhausted = true;
if (e != null) {
action.accept(e);
return true;
@@ -1238,9 +1246,20 @@
return false;
}
+ public void forEachRemaining(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ if (!exhausted) {
+ exhausted = true;
+ Node<E> p = current;
+ current = null;
+ forEachFrom(action, p);
+ }
+ }
+
public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
+ return (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT);
}
}
@@ -1261,7 +1280,127 @@
* @since 1.8
*/
public Spliterator<E> spliterator() {
- return new LBDSpliterator<E>(this);
+ return new LBDSpliterator();
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ forEachFrom(action, null);
+ }
+
+ /**
+ * Runs action on each element found during a traversal starting at p.
+ * If p is null, traversal starts at head.
+ */
+ void forEachFrom(Consumer<? super E> action, Node<E> p) {
+ // Extract batches of elements while holding the lock; then
+ // run the action on the elements while not
+ final ReentrantLock lock = this.lock;
+ final int batchSize = 64; // max number of elements per batch
+ Object[] es = null; // container for batch of elements
+ int n, len = 0;
+ do {
+ lock.lock();
+ try {
+ if (es == null) {
+ if (p == null) p = first;
+ for (Node<E> q = p; q != null; q = succ(q))
+ if (q.item != null && ++len == batchSize)
+ break;
+ es = new Object[len];
+ }
+ for (n = 0; p != null && n < len; p = succ(p))
+ if ((es[n] = p.item) != null)
+ n++;
+ } finally {
+ lock.unlock();
+ }
+ for (int i = 0; i < n; i++) {
+ @SuppressWarnings("unchecked") E e = (E) es[i];
+ action.accept(e);
+ }
+ } while (n > 0 && p != null);
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> 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));
+ }
+
+ /** Implementation of bulk remove methods. */
+ @SuppressWarnings("unchecked")
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ boolean removed = false;
+ final ReentrantLock lock = this.lock;
+ Node<E> p = null;
+ Node<E>[] nodes = null;
+ int n, len = 0;
+ do {
+ // 1. Extract batch of up to 64 elements while holding the lock.
+ lock.lock();
+ try {
+ if (nodes == null) { // first batch; initialize
+ p = first;
+ for (Node<E> q = p; q != null; q = succ(q))
+ if (q.item != null && ++len == 64)
+ break;
+ nodes = (Node<E>[]) new Node<?>[len];
+ }
+ for (n = 0; p != null && n < len; p = succ(p))
+ nodes[n++] = p;
+ } finally {
+ lock.unlock();
+ }
+
+ // 2. Run the filter on the elements while lock is free.
+ long deathRow = 0L; // "bitset" of size 64
+ for (int i = 0; i < n; i++) {
+ final E e;
+ if ((e = nodes[i].item) != null && filter.test(e))
+ deathRow |= 1L << i;
+ }
+
+ // 3. Remove any filtered elements while holding the lock.
+ if (deathRow != 0) {
+ lock.lock();
+ try {
+ for (int i = 0; i < n; i++) {
+ final Node<E> q;
+ if ((deathRow & (1L << i)) != 0L
+ && (q = nodes[i]).item != null) {
+ unlink(q);
+ removed = true;
+ }
+ nodes[i] = null; // help GC
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ } while (n > 0 && p != null);
+ return removed;
}
/**
@@ -1304,12 +1443,21 @@
last = null;
// Read in all elements and place in queue
for (;;) {
- @SuppressWarnings("unchecked")
- E item = (E)s.readObject();
+ @SuppressWarnings("unchecked") E item = (E)s.readObject();
if (item == null)
break;
add(item);
}
}
+ void checkInvariants() {
+ // assert lock.isHeldByCurrentThread();
+ // Nodes may get self-linked or lose their item, but only
+ // after being unlinked and becoming unreachable from first.
+ for (Node<E> p = first; p != null; p = p.next) {
+ // assert p.next != p;
+ // assert p.item != null;
+ }
+ }
+
}
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
index cf2d447..4ba6c1e 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
@@ -39,16 +39,14 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
/**
* An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
@@ -69,9 +67,12 @@
* dynamically created upon each insertion unless this would bring the
* queue above capacity.
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
*
* @since 1.5
* @author Doug Lea
@@ -234,14 +235,6 @@
putLock.unlock();
}
-// /**
-// * Tells whether both locks are held by current thread.
-// */
-// boolean isFullyLocked() {
-// return (putLock.isHeldByCurrentThread() &&
-// takeLock.isHeldByCurrentThread());
-// }
-
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
@@ -330,10 +323,8 @@
*/
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
- // Note: convention in all put/take/etc is to preset local var
- // holding count negative to indicate failure unless set.
- int c = -1;
- Node<E> node = new Node<E>(e);
+ final int c;
+ final Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
@@ -374,7 +365,7 @@
if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
- int c = -1;
+ final int c;
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
@@ -412,28 +403,28 @@
final AtomicInteger count = this.count;
if (count.get() == capacity)
return false;
- int c = -1;
- Node<E> node = new Node<E>(e);
+ final int c;
+ final Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
- if (count.get() < capacity) {
- enqueue(node);
- c = count.getAndIncrement();
- if (c + 1 < capacity)
- notFull.signal();
- }
+ if (count.get() == capacity)
+ return false;
+ enqueue(node);
+ c = count.getAndIncrement();
+ if (c + 1 < capacity)
+ notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
- return c >= 0;
+ return true;
}
public E take() throws InterruptedException {
- E x;
- int c = -1;
+ final E x;
+ final int c;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
@@ -454,8 +445,8 @@
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- E x = null;
- int c = -1;
+ final E x;
+ final int c;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
@@ -482,17 +473,17 @@
final AtomicInteger count = this.count;
if (count.get() == 0)
return null;
- E x = null;
- int c = -1;
+ final E x;
+ final int c;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
- if (count.get() > 0) {
- x = dequeue();
- c = count.getAndDecrement();
- if (c > 1)
- notEmpty.signal();
- }
+ if (count.get() == 0)
+ return null;
+ x = dequeue();
+ c = count.getAndDecrement();
+ if (c > 1)
+ notEmpty.signal();
} finally {
takeLock.unlock();
}
@@ -502,6 +493,7 @@
}
public E peek() {
+ final AtomicInteger count = this.count;
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
@@ -514,16 +506,17 @@
}
/**
- * Unlinks interior Node p with predecessor trail.
+ * Unlinks interior Node p with predecessor pred.
*/
- void unlink(Node<E> p, Node<E> trail) {
- // assert isFullyLocked();
+ void unlink(Node<E> p, Node<E> pred) {
+ // assert putLock.isHeldByCurrentThread();
+ // assert takeLock.isHeldByCurrentThread();
// p.next is not changed, to allow iterators that are
// traversing p to maintain their weak-consistency guarantee.
p.item = null;
- trail.next = p.next;
+ pred.next = p.next;
if (last == p)
- last = trail;
+ last = pred;
if (count.getAndDecrement() == capacity)
notFull.signal();
}
@@ -543,11 +536,11 @@
if (o == null) return false;
fullyLock();
try {
- for (Node<E> trail = head, p = trail.next;
+ for (Node<E> pred = head, p = pred.next;
p != null;
- trail = p, p = p.next) {
+ pred = p, p = p.next) {
if (o.equals(p.item)) {
- unlink(p, trail);
+ unlink(p, pred);
return true;
}
}
@@ -701,8 +694,7 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -741,6 +733,18 @@
}
/**
+ * Used for any element traversal that is not entirely under lock.
+ * Such traversals must handle both:
+ * - dequeued nodes (p.next == p)
+ * - (possibly multiple) interior removed nodes (p.item == null)
+ */
+ Node<E> succ(Node<E> p) {
+ if (p == (p = p.next))
+ p = head.next;
+ return p;
+ }
+
+ /**
* Returns an iterator over the elements in this queue in proper sequence.
* The elements will be returned in order from first (head) to last (tail).
*
@@ -753,71 +757,103 @@
return new Itr();
}
+ /**
+ * Weakly-consistent iterator.
+ *
+ * Lazily updated ancestor field provides expected O(1) remove(),
+ * but still O(n) in the worst case, whenever the saved ancestor
+ * is concurrently deleted.
+ */
private class Itr implements Iterator<E> {
- /*
- * Basic weakly-consistent iterator. At all times hold the next
- * item to hand out so that if hasNext() reports true, we will
- * still have it to return even if lost race with a take etc.
- */
-
- private Node<E> current;
+ private Node<E> next; // Node holding nextItem
+ private E nextItem; // next item to hand out
private Node<E> lastRet;
- private E currentElement;
+ private Node<E> ancestor; // Helps unlink lastRet on remove()
Itr() {
fullyLock();
try {
- current = head.next;
- if (current != null)
- currentElement = current.item;
+ if ((next = head.next) != null)
+ nextItem = next.item;
} finally {
fullyUnlock();
}
}
public boolean hasNext() {
- return current != null;
+ return next != null;
}
public E next() {
+ Node<E> p;
+ if ((p = next) == null)
+ throw new NoSuchElementException();
+ lastRet = p;
+ E x = nextItem;
fullyLock();
try {
- if (current == null)
- throw new NoSuchElementException();
- lastRet = current;
- E item = null;
- // Unlike other traversal methods, iterators must handle both:
- // - dequeued nodes (p.next == p)
- // - (possibly multiple) interior removed nodes (p.item == null)
- for (Node<E> p = current, q;; p = q) {
- if ((q = p.next) == p)
- q = head.next;
- if (q == null || (item = q.item) != null) {
- current = q;
- E x = currentElement;
- currentElement = item;
- return x;
- }
- }
+ E e = null;
+ for (p = p.next; p != null && (e = p.item) == null; )
+ p = succ(p);
+ next = p;
+ nextItem = e;
} finally {
fullyUnlock();
}
+ return x;
+ }
+
+ public void forEachRemaining(Consumer<? super E> action) {
+ // A variant of forEachFrom
+ Objects.requireNonNull(action);
+ Node<E> p;
+ if ((p = next) == null) return;
+ lastRet = p;
+ next = null;
+ final int batchSize = 64;
+ Object[] es = null;
+ int n, len = 1;
+ do {
+ fullyLock();
+ try {
+ if (es == null) {
+ p = p.next;
+ for (Node<E> q = p; q != null; q = succ(q))
+ if (q.item != null && ++len == batchSize)
+ break;
+ es = new Object[len];
+ es[0] = nextItem;
+ nextItem = null;
+ n = 1;
+ } else
+ n = 0;
+ for (; p != null && n < len; p = succ(p))
+ if ((es[n] = p.item) != null) {
+ lastRet = p;
+ n++;
+ }
+ } finally {
+ fullyUnlock();
+ }
+ for (int i = 0; i < n; i++) {
+ @SuppressWarnings("unchecked") E e = (E) es[i];
+ action.accept(e);
+ }
+ } while (n > 0 && p != null);
}
public void remove() {
- if (lastRet == null)
+ Node<E> p = lastRet;
+ if (p == null)
throw new IllegalStateException();
+ lastRet = null;
fullyLock();
try {
- Node<E> node = lastRet;
- lastRet = null;
- for (Node<E> trail = head, p = trail.next;
- p != null;
- trail = p, p = p.next) {
- if (p == node) {
- unlink(p, trail);
- break;
- }
+ if (p.item != null) {
+ if (ancestor == null)
+ ancestor = head;
+ ancestor = findPred(p, ancestor);
+ unlink(p, ancestor);
}
} finally {
fullyUnlock();
@@ -825,42 +861,38 @@
}
}
- /** A customized variant of Spliterators.IteratorSpliterator */
- static final class LBQSpliterator<E> implements Spliterator<E> {
+ /**
+ * A customized variant of Spliterators.IteratorSpliterator.
+ * Keep this class in sync with (very similar) LBDSpliterator.
+ */
+ private final class LBQSpliterator implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25; // max batch array size;
- final LinkedBlockingQueue<E> queue;
Node<E> current; // current node; null until initialized
int batch; // batch size for splits
boolean exhausted; // true when no more nodes
- long est; // size estimate
- LBQSpliterator(LinkedBlockingQueue<E> queue) {
- this.queue = queue;
- this.est = queue.size();
- }
+ long est = size(); // size estimate
+
+ LBQSpliterator() {}
public long estimateSize() { return est; }
public Spliterator<E> trySplit() {
Node<E> h;
- final LinkedBlockingQueue<E> q = this.queue;
- int b = batch;
- int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
- ((h = current) != null || (h = q.head.next) != null) &&
- h.next != null) {
+ ((h = current) != null || (h = head.next) != null)
+ && h.next != null) {
+ int n = batch = Math.min(batch + 1, MAX_BATCH);
Object[] a = new Object[n];
int i = 0;
Node<E> p = current;
- q.fullyLock();
+ fullyLock();
try {
- if (p != null || (p = q.head.next) != null) {
- do {
+ if (p != null || (p = head.next) != null)
+ for (; p != null && i < n; p = succ(p))
if ((a[i] = p.item) != null)
- ++i;
- } while ((p = p.next) != null && i < n);
- }
+ i++;
} finally {
- q.fullyUnlock();
+ fullyUnlock();
}
if ((current = p) == null) {
est = 0L;
@@ -868,64 +900,32 @@
}
else if ((est -= i) < 0L)
est = 0L;
- if (i > 0) {
- batch = i;
+ if (i > 0)
return Spliterators.spliterator
(a, 0, i, (Spliterator.ORDERED |
Spliterator.NONNULL |
Spliterator.CONCURRENT));
- }
}
return null;
}
- public void forEachRemaining(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
- final LinkedBlockingQueue<E> q = this.queue;
- if (!exhausted) {
- exhausted = true;
- Node<E> p = current;
- do {
- E e = null;
- q.fullyLock();
- try {
- if (p == null)
- p = q.head.next;
- while (p != null) {
- e = p.item;
- p = p.next;
- if (e != null)
- break;
- }
- } finally {
- q.fullyUnlock();
- }
- if (e != null)
- action.accept(e);
- } while (p != null);
- }
- }
-
public boolean tryAdvance(Consumer<? super E> action) {
- if (action == null) throw new NullPointerException();
- final LinkedBlockingQueue<E> q = this.queue;
+ Objects.requireNonNull(action);
if (!exhausted) {
E e = null;
- q.fullyLock();
+ fullyLock();
try {
- if (current == null)
- current = q.head.next;
- while (current != null) {
- e = current.item;
- current = current.next;
- if (e != null)
- break;
- }
+ Node<E> p;
+ if ((p = current) != null || (p = head.next) != null)
+ do {
+ e = p.item;
+ p = succ(p);
+ } while (e == null && p != null);
+ if ((current = p) == null)
+ exhausted = true;
} finally {
- q.fullyUnlock();
+ fullyUnlock();
}
- if (current == null)
- exhausted = true;
if (e != null) {
action.accept(e);
return true;
@@ -934,9 +934,20 @@
return false;
}
+ public void forEachRemaining(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ if (!exhausted) {
+ exhausted = true;
+ Node<E> p = current;
+ current = null;
+ forEachFrom(action, p);
+ }
+ }
+
public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
+ return (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT);
}
}
@@ -957,7 +968,140 @@
* @since 1.8
*/
public Spliterator<E> spliterator() {
- return new LBQSpliterator<E>(this);
+ return new LBQSpliterator();
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ forEachFrom(action, null);
+ }
+
+ /**
+ * Runs action on each element found during a traversal starting at p.
+ * If p is null, traversal starts at head.
+ */
+ void forEachFrom(Consumer<? super E> action, Node<E> p) {
+ // Extract batches of elements while holding the lock; then
+ // run the action on the elements while not
+ final int batchSize = 64; // max number of elements per batch
+ Object[] es = null; // container for batch of elements
+ int n, len = 0;
+ do {
+ fullyLock();
+ try {
+ if (es == null) {
+ if (p == null) p = head.next;
+ for (Node<E> q = p; q != null; q = succ(q))
+ if (q.item != null && ++len == batchSize)
+ break;
+ es = new Object[len];
+ }
+ for (n = 0; p != null && n < len; p = succ(p))
+ if ((es[n] = p.item) != null)
+ n++;
+ } finally {
+ fullyUnlock();
+ }
+ for (int i = 0; i < n; i++) {
+ @SuppressWarnings("unchecked") E e = (E) es[i];
+ action.accept(e);
+ }
+ } while (n > 0 && p != null);
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> 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));
+ }
+
+ /**
+ * Returns the predecessor of live node p, given a node that was
+ * once a live ancestor of p (or head); allows unlinking of p.
+ */
+ Node<E> findPred(Node<E> p, Node<E> ancestor) {
+ // assert p.item != null;
+ if (ancestor.item == null)
+ ancestor = head;
+ // Fails with NPE if precondition not satisfied
+ for (Node<E> q; (q = ancestor.next) != p; )
+ ancestor = q;
+ return ancestor;
+ }
+
+ /** Implementation of bulk remove methods. */
+ @SuppressWarnings("unchecked")
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ boolean removed = false;
+ Node<E> p = null, ancestor = head;
+ Node<E>[] nodes = null;
+ int n, len = 0;
+ do {
+ // 1. Extract batch of up to 64 elements while holding the lock.
+ fullyLock();
+ try {
+ if (nodes == null) { // first batch; initialize
+ p = head.next;
+ for (Node<E> q = p; q != null; q = succ(q))
+ if (q.item != null && ++len == 64)
+ break;
+ nodes = (Node<E>[]) new Node<?>[len];
+ }
+ for (n = 0; p != null && n < len; p = succ(p))
+ nodes[n++] = p;
+ } finally {
+ fullyUnlock();
+ }
+
+ // 2. Run the filter on the elements while lock is free.
+ long deathRow = 0L; // "bitset" of size 64
+ for (int i = 0; i < n; i++) {
+ final E e;
+ if ((e = nodes[i].item) != null && filter.test(e))
+ deathRow |= 1L << i;
+ }
+
+ // 3. Remove any filtered elements while holding the lock.
+ if (deathRow != 0) {
+ fullyLock();
+ try {
+ for (int i = 0; i < n; i++) {
+ final Node<E> q;
+ if ((deathRow & (1L << i)) != 0L
+ && (q = nodes[i]).item != null) {
+ ancestor = findPred(q, ancestor);
+ unlink(q, ancestor);
+ removed = true;
+ }
+ nodes[i] = null; // help GC
+ }
+ } finally {
+ fullyUnlock();
+ }
+ }
+ } while (n > 0 && p != null);
+ return removed;
}
/**
diff --git a/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index e282b42..06d04e22 100644
--- a/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -35,20 +35,20 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Queue;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
/**
* An unbounded {@link TransferQueue} based on linked nodes.
@@ -63,16 +63,15 @@
* asynchronous nature of these queues, determining the current number
* of elements requires a traversal of the elements, and so may report
* inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code addAll},
- * {@code removeAll}, {@code retainAll}, {@code containsAll},
- * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
- * to be performed atomically. For example, an iterator operating
- * concurrently with an {@code addAll} operation might view only some
- * of the added elements.
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe only some of the added elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
*
* <p>Memory consistency effects: As with other concurrent
* collections, actions in a thread prior to placing an object into a
@@ -81,6 +80,10 @@
* actions subsequent to the access or removal of that element from
* the {@code LinkedTransferQueue} in another thread.
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.7
* @author Doug Lea
* @param <E> the type of elements held in this queue
@@ -93,8 +96,8 @@
* *** Overview of Dual Queues with Slack ***
*
* Dual Queues, introduced by Scherer and Scott
- * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
- * (linked) queues in which nodes may represent either data or
+ * (http://www.cs.rochester.edu/~scott/papers/2004_DISC_dual_DS.pdf)
+ * are (linked) queues in which nodes may represent either data or
* requests. When a thread tries to enqueue a data node, but
* encounters a request node, it instead "matches" and removes it;
* and vice versa for enqueuing requests. Blocking Dual Queues
@@ -156,9 +159,8 @@
* correctly perform enqueue and dequeue operations by traversing
* from a pointer to the initial node; CASing the item of the
* first unmatched node on match and CASing the next field of the
- * trailing node on appends. (Plus some special-casing when
- * initially empty). While this would be a terrible idea in
- * itself, it does have the benefit of not requiring ANY atomic
+ * trailing node on appends. While this would be a terrible idea
+ * in itself, it does have the benefit of not requiring ANY atomic
* updates on head/tail fields.
*
* We introduce here an approach that lies between the extremes of
@@ -194,15 +196,15 @@
* with a given probability per traversal step.
*
* In any strategy along these lines, because CASes updating
- * fields may fail, the actual slack may exceed targeted
- * slack. However, they may be retried at any time to maintain
- * targets. Even when using very small slack values, this
- * approach works well for dual queues because it allows all
- * operations up to the point of matching or appending an item
- * (hence potentially allowing progress by another thread) to be
- * read-only, thus not introducing any further contention. As
- * described below, we implement this by performing slack
- * maintenance retries only after these points.
+ * fields may fail, the actual slack may exceed targeted slack.
+ * However, they may be retried at any time to maintain targets.
+ * Even when using very small slack values, this approach works
+ * well for dual queues because it allows all operations up to the
+ * point of matching or appending an item (hence potentially
+ * allowing progress by another thread) to be read-only, thus not
+ * introducing any further contention. As described below, we
+ * implement this by performing slack maintenance retries only
+ * after these points.
*
* As an accompaniment to such techniques, traversal overhead can
* be further reduced without increasing contention of head
@@ -221,7 +223,7 @@
* (Similar issues arise in non-GC environments.) To cope with
* this in our implementation, upon CASing to advance the head
* pointer, we set the "next" link of the previous head to point
- * only to itself; thus limiting the length of connected dead lists.
+ * only to itself; thus limiting the length of chains of dead nodes.
* (We also take similar care to wipe out possibly garbage
* retaining values held in other Node fields.) However, doing so
* adds some further complexity to traversal: If any "next"
@@ -264,15 +266,6 @@
* interior nodes) except in the case of cancellation/removal (see
* below).
*
- * We allow both the head and tail fields to be null before any
- * nodes are enqueued; initializing upon first append. This
- * simplifies some other logic, as well as providing more
- * efficient explicit control paths instead of letting JVMs insert
- * implicit NullPointerExceptions when they are null. While not
- * currently fully implemented, we also leave open the possibility
- * of re-nulling these fields when empty (which is complicated to
- * arrange, for little benefit.)
- *
* All enqueue/dequeue operations are handled by the single method
* "xfer" with parameters indicating whether to act as some form
* of offer, put, poll, take, or transfer (each possibly with
@@ -280,44 +273,40 @@
* method outweighs the code bulk and maintenance problems of
* using separate methods for each case.
*
- * Operation consists of up to three phases. The first is
- * implemented within method xfer, the second in tryAppend, and
- * the third in method awaitMatch.
+ * Operation consists of up to two phases. The first is implemented
+ * in method xfer, the second in method awaitMatch.
*
- * 1. Try to match an existing node
+ * 1. Traverse until matching or appending (method xfer)
*
- * Starting at head, skip already-matched nodes until finding
- * an unmatched node of opposite mode, if one exists, in which
- * case matching it and returning, also if necessary updating
- * head to one past the matched node (or the node itself if the
- * list has no other unmatched nodes). If the CAS misses, then
- * a loop retries advancing head by two steps until either
- * success or the slack is at most two. By requiring that each
- * attempt advances head by two (if applicable), we ensure that
- * the slack does not grow without bound. Traversals also check
- * if the initial head is now off-list, in which case they
- * start at the new head.
+ * Conceptually, we simply traverse all nodes starting from head.
+ * If we encounter an unmatched node of opposite mode, we match
+ * it and return, also updating head (by at least 2 hops) to
+ * one past the matched node (or the node itself if it's the
+ * pinned trailing node). Traversals also check for the
+ * possibility of falling off-list, in which case they restart.
*
- * If no candidates are found and the call was untimed
- * poll/offer, (argument "how" is NOW) return.
+ * If the trailing node of the list is reached, a match is not
+ * possible. If this call was untimed poll or tryTransfer
+ * (argument "how" is NOW), return empty-handed immediately.
+ * Else a new node is CAS-appended. On successful append, if
+ * this call was ASYNC (e.g. offer), an element was
+ * successfully added to the end of the queue and we return.
*
- * 2. Try to append a new node (method tryAppend)
+ * Of course, this naive traversal is O(n) when no match is
+ * possible. We optimize the traversal by maintaining a tail
+ * pointer, which is expected to be "near" the end of the list.
+ * It is only safe to fast-forward to tail (in the presence of
+ * arbitrary concurrent changes) if it is pointing to a node of
+ * the same mode, even if it is dead (in this case no preceding
+ * node could still be matchable by this traversal). If we
+ * need to restart due to falling off-list, we can again
+ * fast-forward to tail, but only if it has changed since the
+ * last traversal (else we might loop forever). If tail cannot
+ * be used, traversal starts at head (but in this case we
+ * expect to be able to match near head). As with head, we
+ * CAS-advance the tail pointer by at least two hops.
*
- * Starting at current tail pointer, find the actual last node
- * and try to append a new node (or if head was null, establish
- * the first node). Nodes can be appended only if their
- * predecessors are either already matched or are of the same
- * mode. If we detect otherwise, then a new node with opposite
- * mode must have been appended during traversal, so we must
- * restart at phase 1. The traversal and update steps are
- * otherwise similar to phase 1: Retrying upon CAS misses and
- * checking for staleness. In particular, if a self-link is
- * encountered, then we can safely jump to a node on the list
- * by continuing the traversal at current head.
- *
- * On successful append, if the call was ASYNC, return.
- *
- * 3. Await match or cancellation (method awaitMatch)
+ * 2. Await match or cancellation (method awaitMatch)
*
* Wait for another thread to match node; instead cancelling if
* the current thread was interrupted or the wait timed out. On
@@ -371,12 +360,12 @@
* from, the head of list.
*
* Without taking these into account, it would be possible for an
- * unbounded number of supposedly removed nodes to remain
- * reachable. Situations leading to such buildup are uncommon but
- * can occur in practice; for example when a series of short timed
- * calls to poll repeatedly time out but never otherwise fall off
- * the list because of an untimed call to take at the front of the
- * queue.
+ * unbounded number of supposedly removed nodes to remain reachable.
+ * Situations leading to such buildup are uncommon but can occur
+ * in practice; for example when a series of short timed calls to
+ * poll repeatedly time out at the trailing node but otherwise
+ * never fall off the list because of an untimed call to take() at
+ * the front of the queue.
*
* When these cases arise, rather than always retraversing the
* entire list to find an actual predecessor to unlink (which
@@ -389,10 +378,9 @@
* We perform sweeps by the thread hitting threshold (rather than
* background threads or by spreading work to other threads)
* because in the main contexts in which removal occurs, the
- * caller is already timed-out, cancelled, or performing a
- * potentially O(n) operation (e.g. remove(x)), none of which are
- * time-critical enough to warrant the overhead that alternatives
- * would impose on other threads.
+ * caller is timed-out or cancelled, which are not time-critical
+ * enough to warrant the overhead that alternatives would impose
+ * on other threads.
*
* Because the sweepVotes estimate is conservative, and because
* nodes become unlinked "naturally" as they fall off the head of
@@ -404,6 +392,13 @@
* quiescent queues. The value defined below was chosen
* empirically to balance these under various timeout scenarios.
*
+ * Because traversal operations on the linked list of nodes are a
+ * natural opportunity to sweep dead nodes, we generally do so,
+ * including all the operations that might remove elements as they
+ * traverse, such as removeIf and Iterator.remove. This largely
+ * eliminates long chains of dead interior nodes, except from
+ * cancelled or timed out blocking operations.
+ *
* Note that we cannot self-link unlinked interior nodes during
* sweeps. However, the associated garbage chains terminate when
* some successor ultimately falls off the head of the list and is
@@ -444,55 +439,72 @@
/**
* Queue nodes. Uses Object, not E, for items to allow forgetting
- * them after use. Relies heavily on Unsafe mechanics to minimize
- * unnecessary ordering constraints: Writes that are intrinsically
- * ordered wrt other accesses or CASes use simple relaxed forms.
+ * them after use. Writes that are intrinsically ordered wrt
+ * other accesses or CASes use simple relaxed forms.
*/
static final class Node {
final boolean isData; // false if this is a request node
volatile Object item; // initially non-null if isData; CASed to match
volatile Node next;
- volatile Thread waiter; // null until waiting
+ volatile Thread waiter; // null when not waiting for a match
- // CAS methods for fields
+ /**
+ * Constructs a data node holding item if item is non-null,
+ * else a request node. Uses relaxed write because item can
+ * only be seen after piggy-backing publication via CAS.
+ */
+ Node(Object item) {
+ ITEM.set(this, item);
+ isData = (item != null);
+ }
+
+ /** Constructs a (matched data) dummy node. */
+ Node() {
+ isData = true;
+ }
+
final boolean casNext(Node cmp, Node val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ // assert val != null;
+ return NEXT.compareAndSet(this, cmp, val);
}
final boolean casItem(Object cmp, Object val) {
- // assert cmp == null || cmp.getClass() != Node.class;
- return U.compareAndSwapObject(this, ITEM, cmp, val);
- }
-
- /**
- * Constructs a new node. Uses relaxed write because item can
- * only be seen after publication via casNext.
- */
- Node(Object item, boolean isData) {
- U.putObject(this, ITEM, item); // relaxed write
- this.isData = isData;
+ // assert isData == (cmp != null);
+ // assert isData == (val == null);
+ // assert !(cmp instanceof Node);
+ return ITEM.compareAndSet(this, cmp, val);
}
/**
* Links node to itself to avoid garbage retention. Called
* only after CASing head field, so uses relaxed write.
*/
- final void forgetNext() {
- U.putObject(this, NEXT, this);
+ final void selfLink() {
+ // assert isMatched();
+ NEXT.setRelease(this, this);
+ }
+
+ final void appendRelaxed(Node next) {
+ // assert next != null;
+ // assert this.next == null;
+ NEXT.set(this, next);
}
/**
- * Sets item to self and waiter to null, to avoid garbage
- * retention after matching or cancelling. Uses relaxed writes
- * because order is already constrained in the only calling
- * contexts: item is forgotten only after volatile/atomic
- * mechanics that extract items. Similarly, clearing waiter
- * follows either CAS or return from park (if ever parked;
- * else we don't care).
+ * Sets item (of a request node) to self and waiter to null,
+ * to avoid garbage retention after matching or cancelling.
+ * Uses relaxed writes because order is already constrained in
+ * the only calling contexts: item is forgotten only after
+ * volatile/atomic mechanics that extract items, and visitors
+ * of request nodes only ever check whether item is null.
+ * Similarly, clearing waiter follows either CAS or return
+ * from park (if ever parked; else we don't care).
*/
final void forgetContents() {
- U.putObject(this, ITEM, this);
- U.putObject(this, WAITER, null);
+ // assert isMatched();
+ if (!isData)
+ ITEM.set(this, this);
+ WAITER.set(this, null);
}
/**
@@ -500,15 +512,16 @@
* case of artificial matches due to cancellation.
*/
final boolean isMatched() {
- Object x = item;
- return (x == this) || ((x == null) == isData);
+ return isData == (item == null);
}
- /**
- * Returns true if this is an unmatched request node.
- */
- final boolean isUnmatchedRequest() {
- return !isData && item == null;
+ /** Tries to CAS-match this node; if successful, wakes waiter. */
+ final boolean tryMatch(Object cmp, Object val) {
+ if (casItem(cmp, val)) {
+ LockSupport.unpark(waiter);
+ return true;
+ }
+ return false;
}
/**
@@ -518,69 +531,118 @@
*/
final boolean cannotPrecede(boolean haveData) {
boolean d = isData;
- Object x;
- return d != haveData && (x = item) != this && (x != null) == d;
- }
-
- /**
- * Tries to artificially match a data node -- used by remove.
- */
- final boolean tryMatchData() {
- // assert isData;
- Object x = item;
- if (x != null && x != this && casItem(x, null)) {
- LockSupport.unpark(waiter);
- return true;
- }
- return false;
+ return d != haveData && d != (item == null);
}
private static final long serialVersionUID = -3375979862319811754L;
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long ITEM;
- private static final long NEXT;
- private static final long WAITER;
- static {
- try {
- ITEM = U.objectFieldOffset
- (Node.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- WAITER = U.objectFieldOffset
- (Node.class.getDeclaredField("waiter"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
}
- /** head of the queue; null until first enqueue */
+ /**
+ * A node from which the first live (non-matched) node (if any)
+ * can be reached in O(1) time.
+ * Invariants:
+ * - all live nodes are reachable from head via .next
+ * - head != null
+ * - (tmp = head).next != tmp || tmp != head
+ * Non-invariants:
+ * - head may or may not be live
+ * - it is permitted for tail to lag behind head, that is, for tail
+ * to not be reachable from head!
+ */
transient volatile Node head;
- /** tail of the queue; null until first append */
+ /**
+ * A node from which the last node on list (that is, the unique
+ * node with node.next == null) can be reached in O(1) time.
+ * Invariants:
+ * - the last node is always reachable from tail via .next
+ * - tail != null
+ * Non-invariants:
+ * - tail may or may not be live
+ * - it is permitted for tail to lag behind head, that is, for tail
+ * to not be reachable from head!
+ * - tail.next may or may not be self-linked.
+ */
private transient volatile Node tail;
- /** The number of apparent failures to unsplice removed nodes */
+ /** The number of apparent failures to unsplice cancelled nodes */
private transient volatile int sweepVotes;
- // CAS methods for fields
private boolean casTail(Node cmp, Node val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ // assert cmp != null;
+ // assert val != null;
+ return TAIL.compareAndSet(this, cmp, val);
}
private boolean casHead(Node cmp, Node val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return HEAD.compareAndSet(this, cmp, val);
}
- private boolean casSweepVotes(int cmp, int val) {
- return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+ /** Atomic version of ++sweepVotes. */
+ private int incSweepVotes() {
+ return (int) SWEEPVOTES.getAndAdd(this, 1) + 1;
}
- /*
- * Possible values for "how" argument in xfer method.
+ /**
+ * Tries to CAS pred.next (or head, if pred is null) from c to p.
+ * Caller must ensure that we're not unlinking the trailing node.
*/
+ private boolean tryCasSuccessor(Node pred, Node c, Node p) {
+ // assert p != null;
+ // assert c.isData != (c.item != null);
+ // assert c != p;
+ if (pred != null)
+ return pred.casNext(c, p);
+ if (casHead(c, p)) {
+ c.selfLink();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Collapses dead (matched) nodes between pred and q.
+ * @param pred the last known live node, or null if none
+ * @param c the first dead node
+ * @param p the last dead node
+ * @param q p.next: the next live node, or null if at end
+ * @return pred if pred still alive and CAS succeeded; else p
+ */
+ private Node skipDeadNodes(Node pred, Node c, Node p, Node q) {
+ // assert pred != c;
+ // assert p != q;
+ // assert c.isMatched();
+ // assert p.isMatched();
+ if (q == null) {
+ // Never unlink trailing node.
+ if (c == p) return pred;
+ q = p;
+ }
+ return (tryCasSuccessor(pred, c, q)
+ && (pred == null || !pred.isMatched()))
+ ? pred : p;
+ }
+
+ /**
+ * Collapses dead (matched) nodes from h (which was once head) to p.
+ * Caller ensures all nodes from h up to and including p are dead.
+ */
+ private void skipDeadNodesNearHead(Node h, Node p) {
+ // assert h != null;
+ // assert h != p;
+ // assert p.isMatched();
+ for (;;) {
+ final Node q;
+ if ((q = p.next) == null) break;
+ else if (!q.isMatched()) { p = q; break; }
+ else if (p == (p = q)) return;
+ }
+ if (casHead(h, p))
+ h.selfLink();
+ }
+
+ /* Possible values for "how" argument in xfer method. */
+
private static final int NOW = 0; // for untimed poll, tryTransfer
private static final int ASYNC = 1; // for offer, put, add
private static final int SYNC = 2; // for transfer, take
@@ -596,84 +658,32 @@
* @return an item if matched, else e
* @throws NullPointerException if haveData mode but e is null
*/
+ @SuppressWarnings("unchecked")
private E xfer(E e, boolean haveData, int how, long nanos) {
if (haveData && (e == null))
throw new NullPointerException();
- Node s = null; // the node to append, if needed
- retry:
- for (;;) { // restart on append race
-
- for (Node h = head, p = h; p != null;) { // find & match first node
- boolean isData = p.isData;
- Object item = p.item;
- if (item != p && (item != null) == isData) { // unmatched
- if (isData == haveData) // can't match
- break;
- if (p.casItem(item, e)) { // match
- for (Node q = p; q != h;) {
- Node n = q.next; // update by 2 unless singleton
- if (head == h && casHead(h, n == null ? q : n)) {
- h.forgetNext();
- break;
- } // advance and retry
- if ((h = head) == null ||
- (q = h.next) == null || !q.isMatched())
- break; // unless slack < 2
- }
- LockSupport.unpark(p.waiter);
- @SuppressWarnings("unchecked") E itemE = (E) item;
- return itemE;
+ restart: for (Node s = null, t = null, h = null;;) {
+ for (Node p = (t != (t = tail) && t.isData == haveData) ? t
+ : (h = head);; ) {
+ final Node q; final Object item;
+ if (p.isData != haveData
+ && haveData == ((item = p.item) == null)) {
+ if (h == null) h = head;
+ if (p.tryMatch(item, e)) {
+ if (h != p) skipDeadNodesNearHead(h, p);
+ return (E) item;
}
}
- Node n = p.next;
- p = (p != n) ? n : (h = head); // Use head if p offlist
- }
-
- if (how != NOW) { // No matches available
- if (s == null)
- s = new Node(e, haveData);
- Node pred = tryAppend(s, haveData);
- if (pred == null)
- continue retry; // lost race vs opposite mode
- if (how != ASYNC)
- return awaitMatch(s, pred, e, (how == TIMED), nanos);
- }
- return e; // not waiting
- }
- }
-
- /**
- * Tries to append node s as tail.
- *
- * @param s the node to append
- * @param haveData true if appending in data mode
- * @return null on failure due to losing race with append in
- * different mode, else s's predecessor, or s itself if no
- * predecessor
- */
- private Node tryAppend(Node s, boolean haveData) {
- for (Node t = tail, p = t;;) { // move p to last node and append
- Node n, u; // temps for reads of next & tail
- if (p == null && (p = head) == null) {
- if (casHead(null, s))
- return s; // initialize
- }
- else if (p.cannotPrecede(haveData))
- return null; // lost race vs opposite mode
- else if ((n = p.next) != null) // not last; keep traversing
- p = p != t && t != (u = tail) ? (t = u) : // stale tail
- (p != n) ? n : null; // restart if off list
- else if (!p.casNext(null, s))
- p = p.next; // re-read on CAS failure
- else {
- if (p != t) { // update if slack now >= 2
- while ((tail != t || !casTail(t, s)) &&
- (t = tail) != null &&
- (s = t.next) != null && // advance and retry
- (s = s.next) != null && s != t);
+ if ((q = p.next) == null) {
+ if (how == NOW) return e;
+ if (s == null) s = new Node(e);
+ if (!p.casNext(null, s)) continue;
+ if (p != t) casTail(t, s);
+ if (how == ASYNC) return e;
+ return awaitMatch(s, p, e, (how == TIMED), nanos);
}
- return p;
+ if (p == (p = q)) continue restart;
}
}
}
@@ -682,9 +692,9 @@
* Spins/yields/blocks until node s is matched or caller gives up.
*
* @param s the waiting node
- * @param pred the predecessor of s, or s itself if it has no
- * predecessor, or null if unknown (the null case does not occur
- * in any current calls but may in possible future extensions)
+ * @param pred the predecessor of s, or null if unknown (the null
+ * case does not occur in any current calls but may in possible
+ * future extensions)
* @param e the comparison value for checking match
* @param timed if true, wait only until timeout elapses
* @param nanos timeout in nanosecs, used only if timed is true
@@ -697,17 +707,20 @@
ThreadLocalRandom randomYields = null; // bound if needed
for (;;) {
- Object item = s.item;
- if (item != e) { // matched
+ final Object item;
+ if ((item = s.item) != e) { // matched
// assert item != s;
s.forgetContents(); // avoid garbage
@SuppressWarnings("unchecked") E itemE = (E) item;
return itemE;
}
else if (w.isInterrupted() || (timed && nanos <= 0L)) {
- unsplice(pred, s); // try to unlink and cancel
- if (s.casItem(e, s)) // return normally if lost CAS
+ // try to cancel and unlink
+ if (s.casItem(e, s.isData ? null : s)) {
+ unsplice(pred, s);
return e;
+ }
+ // return normally if lost CAS
}
else if (spins < 0) { // establish spins at/near front
if ((spins = spinsFor(pred, s.isData)) > 0)
@@ -751,34 +764,32 @@
/* -------------- Traversal methods -------------- */
/**
- * Returns the successor of p, or the head node if p.next has been
- * linked to self, which will only be true if traversing with a
- * stale pointer that is now off the list.
- */
- final Node succ(Node p) {
- Node next = p.next;
- return (p == next) ? head : next;
- }
-
- /**
* Returns the first unmatched data node, or null if none.
- * Callers must recheck if the returned node's item field is null
- * or self-linked before using.
+ * Callers must recheck if the returned node is unmatched
+ * before using.
*/
final Node firstDataNode() {
+ Node first = null;
restartFromHead: for (;;) {
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p)
- return p;
+ Node h = head, p = h;
+ while (p != null) {
+ if (p.item != null) {
+ if (p.isData) {
+ first = p;
+ break;
+ }
}
- else if (item == null)
+ else if (!p.isData)
break;
- if (p == (p = p.next))
+ final Node q;
+ if ((q = p.next) == null)
+ break;
+ if (p == (p = q))
continue restartFromHead;
}
- return null;
+ if (p != h && casHead(h, p))
+ h.selfLink();
+ return first;
}
}
@@ -811,7 +822,7 @@
for (Node p = head; p != null;) {
Object item = p.item;
if (p.isData) {
- if (item != null && item != p) {
+ if (item != null) {
if (a == null)
a = new String[4];
else if (size == a.length)
@@ -840,7 +851,7 @@
for (Node p = head; p != null;) {
Object item = p.item;
if (p.isData) {
- if (item != null && item != p) {
+ if (item != null) {
if (x == null)
x = new Object[4];
else if (size == x.length)
@@ -919,76 +930,50 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- if (a == null) throw new NullPointerException();
+ Objects.requireNonNull(a);
return (T[]) toArrayInternal(a);
}
+ /**
+ * Weakly-consistent iterator.
+ *
+ * Lazily updated ancestor is expected to be amortized O(1) remove(),
+ * but O(n) in the worst case, when lastRet is concurrently deleted.
+ */
final class Itr implements Iterator<E> {
private Node nextNode; // next node to return item for
private E nextItem; // the corresponding item
private Node lastRet; // last returned node, to support remove
- private Node lastPred; // predecessor to unlink lastRet
+ private Node ancestor; // Helps unlink lastRet on remove()
/**
- * Moves to next node after prev, or first node if prev null.
+ * Moves to next node after pred, or first node if pred null.
*/
- private void advance(Node prev) {
- /*
- * To track and avoid buildup of deleted nodes in the face
- * of calls to both Queue.remove and Itr.remove, we must
- * include variants of unsplice and sweep upon each
- * advance: Upon Itr.remove, we may need to catch up links
- * from lastPred, and upon other removes, we might need to
- * skip ahead from stale nodes and unsplice deleted ones
- * found while advancing.
- */
-
- Node r, b; // reset lastPred upon possible deletion of lastRet
- if ((r = lastRet) != null && !r.isMatched())
- lastPred = r; // next lastPred is old lastRet
- else if ((b = lastPred) == null || b.isMatched())
- lastPred = null; // at start of list
- else {
- Node s, n; // help with removal of lastPred.next
- while ((s = b.next) != null &&
- s != b && s.isMatched() &&
- (n = s.next) != null && n != s)
- b.casNext(s, n);
- }
-
- this.lastRet = prev;
-
- for (Node p = prev, s, n;;) {
- s = (p == null) ? head : p.next;
- if (s == null)
- break;
- else if (s == p) {
- p = null;
- continue;
+ @SuppressWarnings("unchecked")
+ private void advance(Node pred) {
+ for (Node p = (pred == null) ? head : pred.next, c = p;
+ p != null; ) {
+ final Object item;
+ if ((item = p.item) != null && p.isData) {
+ nextNode = p;
+ nextItem = (E) item;
+ if (c != p)
+ tryCasSuccessor(pred, c, p);
+ return;
}
- Object item = s.item;
- if (s.isData) {
- if (item != null && item != s) {
- @SuppressWarnings("unchecked") E itemE = (E) item;
- nextItem = itemE;
- nextNode = s;
- return;
- }
+ else if (!p.isData && item == null)
+ break;
+ if (c != p && !tryCasSuccessor(pred, c, c = p)) {
+ pred = p;
+ c = p = p.next;
}
- else if (item == null)
- break;
- // assert s.isMatched();
- if (p == null)
- p = s;
- else if ((n = s.next) == null)
- break;
- else if (s == n)
- p = null;
- else
- p.casNext(s, n);
+ else if (p == (p = p.next)) {
+ pred = null;
+ c = p = head;
+ }
}
- nextNode = null;
nextItem = null;
+ nextNode = null;
}
Itr() {
@@ -1000,25 +985,67 @@
}
public final E next() {
- Node p = nextNode;
- if (p == null) throw new NoSuchElementException();
+ final Node p;
+ if ((p = nextNode) == null) throw new NoSuchElementException();
E e = nextItem;
- advance(p);
+ advance(lastRet = p);
return e;
}
+ public void forEachRemaining(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ Node q = null;
+ for (Node p; (p = nextNode) != null; advance(q = p))
+ action.accept(nextItem);
+ if (q != null)
+ lastRet = q;
+ }
+
public final void remove() {
final Node lastRet = this.lastRet;
if (lastRet == null)
throw new IllegalStateException();
this.lastRet = null;
- if (lastRet.tryMatchData())
- unsplice(lastPred, lastRet);
+ if (lastRet.item == null) // already deleted?
+ return;
+ // Advance ancestor, collapsing intervening dead nodes
+ Node pred = ancestor;
+ for (Node p = (pred == null) ? head : pred.next, c = p, q;
+ p != null; ) {
+ if (p == lastRet) {
+ final Object item;
+ if ((item = p.item) != null)
+ p.tryMatch(item, null);
+ if ((q = p.next) == null) q = p;
+ if (c != q) tryCasSuccessor(pred, c, q);
+ ancestor = pred;
+ return;
+ }
+ final Object item; final boolean pAlive;
+ if (pAlive = ((item = p.item) != null && p.isData)) {
+ // exceptionally, nothing to do
+ }
+ else if (!p.isData && item == null)
+ break;
+ if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) {
+ pred = p;
+ c = p = p.next;
+ }
+ else if (p == (p = p.next)) {
+ pred = null;
+ c = p = head;
+ }
+ }
+ // traversal failed to find lastRet; must have been deleted;
+ // leave ancestor at original location to avoid overshoot;
+ // better luck next time!
+
+ // assert lastRet.isMatched();
}
}
/** A customized variant of Spliterators.IteratorSpliterator */
- final class LTQSpliterator<E> implements Spliterator<E> {
+ final class LTQSpliterator implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25; // max batch array size;
Node current; // current node; null until initialized
int batch; // batch size for splits
@@ -1026,79 +1053,90 @@
LTQSpliterator() {}
public Spliterator<E> trySplit() {
- Node p;
- int b = batch;
- int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
- if (!exhausted &&
- ((p = current) != null || (p = firstDataNode()) != null) &&
- p.next != null) {
- Object[] a = new Object[n];
- int i = 0;
- do {
- Object e = p.item;
- if (e != p && (a[i] = e) != null)
- ++i;
- if (p == (p = p.next))
- p = firstDataNode();
- } while (p != null && i < n && p.isData);
- if ((current = p) == null)
- exhausted = true;
- if (i > 0) {
- batch = i;
- return Spliterators.spliterator
- (a, 0, i, (Spliterator.ORDERED |
- Spliterator.NONNULL |
- Spliterator.CONCURRENT));
+ Node p, q;
+ if ((p = current()) == null || (q = p.next) == null)
+ return null;
+ int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+ Object[] a = null;
+ do {
+ final Object item = p.item;
+ if (p.isData) {
+ if (item != null) {
+ if (a == null)
+ a = new Object[n];
+ a[i++] = item;
+ }
+ } else if (item == null) {
+ p = null;
+ break;
}
- }
- return null;
+ if (p == (p = q))
+ p = firstDataNode();
+ } while (p != null && (q = p.next) != null && i < n);
+ setCurrent(p);
+ return (i == 0) ? null :
+ Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
- Node p;
- if (action == null) throw new NullPointerException();
- if (!exhausted &&
- ((p = current) != null || (p = firstDataNode()) != null)) {
+ Objects.requireNonNull(action);
+ final Node p;
+ if ((p = current()) != null) {
+ current = null;
exhausted = true;
- do {
- Object e = p.item;
- if (e != null && e != p)
- action.accept((E)e);
- if (p == (p = p.next))
- p = firstDataNode();
- } while (p != null && p.isData);
+ forEachFrom(action, p);
}
}
@SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
Node p;
- if (action == null) throw new NullPointerException();
- if (!exhausted &&
- ((p = current) != null || (p = firstDataNode()) != null)) {
- Object e;
+ if ((p = current()) != null) {
+ E e = null;
do {
- if ((e = p.item) == p)
- e = null;
+ final Object item = p.item;
+ final boolean isData = p.isData;
if (p == (p = p.next))
- p = firstDataNode();
- } while (e == null && p != null && p.isData);
- if ((current = p) == null)
- exhausted = true;
+ p = head;
+ if (isData) {
+ if (item != null) {
+ e = (E) item;
+ break;
+ }
+ }
+ else if (item == null)
+ p = null;
+ } while (p != null);
+ setCurrent(p);
if (e != null) {
- action.accept((E)e);
+ action.accept(e);
return true;
}
}
return false;
}
+ private void setCurrent(Node p) {
+ if ((current = p) == null)
+ exhausted = true;
+ }
+
+ private Node current() {
+ Node p;
+ if ((p = current) == null && !exhausted)
+ setCurrent(p = firstDataNode());
+ return p;
+ }
+
public long estimateSize() { return Long.MAX_VALUE; }
public int characteristics() {
- return Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT;
+ return (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT);
}
}
@@ -1119,7 +1157,7 @@
* @since 1.8
*/
public Spliterator<E> spliterator() {
- return new LTQSpliterator<E>();
+ return new LTQSpliterator();
}
/* -------------- Removal methods -------------- */
@@ -1129,10 +1167,15 @@
* the given predecessor.
*
* @param pred a node that was at one time known to be the
- * predecessor of s, or null or s itself if s is/was at head
+ * predecessor of s
* @param s the node to be unspliced
*/
final void unsplice(Node pred, Node s) {
+ // assert pred != null;
+ // assert pred != s;
+ // assert s != null;
+ // assert s.isMatched();
+ // assert (SWEEP_THRESHOLD & (SWEEP_THRESHOLD - 1)) == 0;
s.waiter = null; // disable signals
/*
* See above for rationale. Briefly: if pred still points to
@@ -1141,13 +1184,13 @@
* nor s are head or offlist, add to sweepVotes, and if enough
* votes have accumulated, sweep.
*/
- if (pred != null && pred != s && pred.next == s) {
+ if (pred != null && pred.next == s) {
Node n = s.next;
if (n == null ||
(n != s && pred.casNext(s, n) && pred.isMatched())) {
for (;;) { // check if at, or could be, head
Node h = head;
- if (h == pred || h == s || h == null)
+ if (h == pred || h == s)
return; // at head or list empty
if (!h.isMatched())
break;
@@ -1155,21 +1198,12 @@
if (hn == null)
return; // now empty
if (hn != h && casHead(h, hn))
- h.forgetNext(); // advance head
+ h.selfLink(); // advance head
}
- if (pred.next != pred && s.next != s) { // recheck if offlist
- for (;;) { // sweep now if enough votes
- int v = sweepVotes;
- if (v < SWEEP_THRESHOLD) {
- if (casSweepVotes(v, v + 1))
- break;
- }
- else if (casSweepVotes(v, 0)) {
- sweep();
- break;
- }
- }
- }
+ // sweep every SWEEP_THRESHOLD votes
+ if (pred.next != pred && s.next != s // recheck if offlist
+ && (incSweepVotes() & (SWEEP_THRESHOLD - 1)) == 0)
+ sweep();
}
}
}
@@ -1194,35 +1228,10 @@
}
/**
- * Main implementation of remove(Object)
- */
- private boolean findAndRemove(Object e) {
- if (e != null) {
- for (Node pred = null, p = head; p != null; ) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p && e.equals(item) &&
- p.tryMatchData()) {
- unsplice(pred, p);
- return true;
- }
- }
- else if (item == null)
- break;
- pred = p;
- if ((p = p.next) == pred) { // stale
- pred = null;
- p = head;
- }
- }
- }
- return false;
- }
-
- /**
* Creates an initially empty {@code LinkedTransferQueue}.
*/
public LinkedTransferQueue() {
+ head = tail = new Node();
}
/**
@@ -1235,8 +1244,18 @@
* of its elements are null
*/
public LinkedTransferQueue(Collection<? extends E> c) {
- this();
- addAll(c);
+ Node h = null, t = null;
+ for (E e : c) {
+ Node newNode = new Node(Objects.requireNonNull(e));
+ if (h == null)
+ h = t = newNode;
+ else
+ t.appendRelaxed(t = newNode);
+ }
+ if (h == null)
+ h = t = new Node();
+ head = h;
+ tail = t;
}
/**
@@ -1255,8 +1274,7 @@
* return {@code false}.
*
* @return {@code true} (as specified by
- * {@link java.util.concurrent.BlockingQueue#offer(Object,long,TimeUnit)
- * BlockingQueue.offer})
+ * {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e, long timeout, TimeUnit unit) {
@@ -1368,15 +1386,12 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
int n = 0;
- for (E e; (e = poll()) != null;) {
+ for (E e; (e = poll()) != null; n++)
c.add(e);
- ++n;
- }
return n;
}
@@ -1385,15 +1400,12 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
int n = 0;
- for (E e; n < maxElements && (e = poll()) != null;) {
+ for (E e; n < maxElements && (e = poll()) != null; n++)
c.add(e);
- ++n;
- }
return n;
}
@@ -1415,7 +1427,7 @@
for (Node p = head; p != null;) {
Object item = p.item;
if (p.isData) {
- if (item != null && item != p) {
+ if (item != null) {
@SuppressWarnings("unchecked") E e = (E) item;
return e;
}
@@ -1443,7 +1455,7 @@
for (Node p = head; p != null;) {
Object item = p.item;
if (p.isData) {
- if (item != null && item != p)
+ if (item != null)
break;
}
else if (item == null)
@@ -1487,7 +1499,31 @@
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
- return findAndRemove(o);
+ if (o == null) return false;
+ restartFromHead: for (;;) {
+ for (Node p = head, pred = null; p != null; ) {
+ Node q = p.next;
+ final Object item;
+ if ((item = p.item) != null) {
+ if (p.isData) {
+ if (o.equals(item) && p.tryMatch(item, null)) {
+ skipDeadNodes(pred, p, p, q);
+ return true;
+ }
+ pred = p; p = q; continue;
+ }
+ }
+ else if (!p.isData)
+ break;
+ for (Node c = p;; q = p.next) {
+ if (q == null || !q.isMatched()) {
+ pred = skipDeadNodes(pred, c, p, q); p = q; break;
+ }
+ if (p == (p = q)) continue restartFromHead;
+ }
+ }
+ return false;
+ }
}
/**
@@ -1499,18 +1535,29 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- if (o != null) {
- for (Node p = head; p != null; p = succ(p)) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p && o.equals(item))
- return true;
+ if (o == null) return false;
+ restartFromHead: for (;;) {
+ for (Node p = head, pred = null; p != null; ) {
+ Node q = p.next;
+ final Object item;
+ if ((item = p.item) != null) {
+ if (p.isData) {
+ if (o.equals(item))
+ return true;
+ pred = p; p = q; continue;
+ }
}
- else if (item == null)
+ else if (!p.isData)
break;
+ for (Node c = p;; q = p.next) {
+ if (q == null || !q.isMatched()) {
+ pred = skipDeadNodes(pred, c, p, q); p = q; break;
+ }
+ if (p == (p = q)) continue restartFromHead;
+ }
}
+ return false;
}
- return false;
}
/**
@@ -1518,8 +1565,7 @@
* {@code LinkedTransferQueue} is not capacity constrained.
*
* @return {@code Integer.MAX_VALUE} (as specified by
- * {@link java.util.concurrent.BlockingQueue#remainingCapacity()
- * BlockingQueue.remainingCapacity})
+ * {@link BlockingQueue#remainingCapacity()})
*/
public int remainingCapacity() {
return Integer.MAX_VALUE;
@@ -1551,33 +1597,149 @@
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- for (;;) {
- @SuppressWarnings("unchecked")
- E item = (E) s.readObject();
- if (item == null)
- break;
+
+ // Read in elements until trailing null sentinel found
+ Node h = null, t = null;
+ for (Object item; (item = s.readObject()) != null; ) {
+ Node newNode = new Node(item);
+ if (h == null)
+ h = t = newNode;
else
- offer(item);
+ t.appendRelaxed(t = newNode);
+ }
+ if (h == null)
+ h = t = new Node();
+ head = h;
+ tail = t;
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> 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));
+ }
+
+ public void clear() {
+ bulkRemove(e -> true);
+ }
+
+ /**
+ * Tolerate this many consecutive dead nodes before CAS-collapsing.
+ * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
+ */
+ private static final int MAX_HOPS = 8;
+
+ /** Implementation of bulk remove methods. */
+ @SuppressWarnings("unchecked")
+ private boolean bulkRemove(Predicate<? super E> filter) {
+ boolean removed = false;
+ restartFromHead: for (;;) {
+ int hops = MAX_HOPS;
+ // c will be CASed to collapse intervening dead nodes between
+ // pred (or head if null) and p.
+ for (Node p = head, c = p, pred = null, q; p != null; p = q) {
+ q = p.next;
+ final Object item; boolean pAlive;
+ if (pAlive = ((item = p.item) != null && p.isData)) {
+ if (filter.test((E) item)) {
+ if (p.tryMatch(item, null))
+ removed = true;
+ pAlive = false;
+ }
+ }
+ else if (!p.isData && item == null)
+ break;
+ if (pAlive || q == null || --hops == 0) {
+ // p might already be self-linked here, but if so:
+ // - CASing head will surely fail
+ // - CASing pred's next will be useless but harmless.
+ if ((c != p && !tryCasSuccessor(pred, c, c = p))
+ || pAlive) {
+ // if CAS failed or alive, abandon old pred
+ hops = MAX_HOPS;
+ pred = p;
+ c = q;
+ }
+ } else if (p == q)
+ continue restartFromHead;
+ }
+ return removed;
}
}
- // Unsafe mechanics
+ /**
+ * Runs action on each element found during a traversal starting at p.
+ * If p is null, the action is not run.
+ */
+ @SuppressWarnings("unchecked")
+ void forEachFrom(Consumer<? super E> action, Node p) {
+ for (Node pred = null; p != null; ) {
+ Node q = p.next;
+ final Object item;
+ if ((item = p.item) != null) {
+ if (p.isData) {
+ action.accept((E) item);
+ pred = p; p = q; continue;
+ }
+ }
+ else if (!p.isData)
+ break;
+ for (Node c = p;; q = p.next) {
+ if (q == null || !q.isMatched()) {
+ pred = skipDeadNodes(pred, c, p, q); p = q; break;
+ }
+ if (p == (p = q)) { pred = null; p = head; break; }
+ }
+ }
+ }
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
- private static final long SWEEPVOTES;
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ forEachFrom(action, head);
+ }
+
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
+ private static final VarHandle SWEEPVOTES;
+ static final VarHandle ITEM;
+ static final VarHandle NEXT;
+ static final VarHandle WAITER;
static {
try {
- HEAD = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("tail"));
- SWEEPVOTES = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
+ Node.class);
+ TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
+ Node.class);
+ SWEEPVOTES = l.findVarHandle(LinkedTransferQueue.class, "sweepVotes",
+ int.class);
+ ITEM = l.findVarHandle(Node.class, "item", Object.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/Phaser.java b/ojluni/src/main/java/java/util/concurrent/Phaser.java
index 9ef9936..76cd707 100644
--- a/ojluni/src/main/java/java/util/concurrent/Phaser.java
+++ b/ojluni/src/main/java/java/util/concurrent/Phaser.java
@@ -35,14 +35,15 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
/**
* A reusable synchronization barrier, similar in functionality to
- * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and
- * {@link java.util.concurrent.CountDownLatch CountDownLatch}
- * but supporting more flexible usage.
+ * {@link CyclicBarrier} and {@link CountDownLatch} but supporting
+ * more flexible usage.
*
* <p><b>Registration.</b> Unlike the case for other barriers, the
* number of parties <em>registered</em> to synchronize on a phaser
@@ -152,49 +153,46 @@
* <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
* to control a one-shot action serving a variable number of parties.
* The typical idiom is for the method setting this up to first
- * register, then start the actions, then deregister, as in:
+ * register, then start all the actions, then deregister, as in:
*
* <pre> {@code
* void runTasks(List<Runnable> tasks) {
- * final Phaser phaser = new Phaser(1); // "1" to register self
+ * Phaser startingGate = new Phaser(1); // "1" to register self
* // create and start threads
- * for (final Runnable task : tasks) {
- * phaser.register();
- * new Thread() {
- * public void run() {
- * phaser.arriveAndAwaitAdvance(); // await all creation
- * task.run();
- * }
- * }.start();
+ * for (Runnable task : tasks) {
+ * startingGate.register();
+ * new Thread(() -> {
+ * startingGate.arriveAndAwaitAdvance();
+ * task.run();
+ * }).start();
* }
*
- * // allow threads to start and deregister self
- * phaser.arriveAndDeregister();
+ * // deregister self to allow threads to proceed
+ * startingGate.arriveAndDeregister();
* }}</pre>
*
* <p>One way to cause a set of threads to repeatedly perform actions
* for a given number of iterations is to override {@code onAdvance}:
*
* <pre> {@code
- * void startTasks(List<Runnable> tasks, final int iterations) {
- * final Phaser phaser = new Phaser() {
+ * void startTasks(List<Runnable> tasks, int iterations) {
+ * Phaser phaser = new Phaser() {
* protected boolean onAdvance(int phase, int registeredParties) {
- * return phase >= iterations || registeredParties == 0;
+ * return phase >= iterations - 1 || registeredParties == 0;
* }
* };
* phaser.register();
- * for (final Runnable task : tasks) {
+ * for (Runnable task : tasks) {
* phaser.register();
- * new Thread() {
- * public void run() {
- * do {
- * task.run();
- * phaser.arriveAndAwaitAdvance();
- * } while (!phaser.isTerminated());
- * }
- * }.start();
+ * new Thread(() -> {
+ * do {
+ * task.run();
+ * phaser.arriveAndAwaitAdvance();
+ * } while (!phaser.isTerminated());
+ * }).start();
* }
- * phaser.arriveAndDeregister(); // deregister self, don't wait
+ * // allow threads to proceed; don't wait for them
+ * phaser.arriveAndDeregister();
* }}</pre>
*
* If the main task must later await termination, it
@@ -221,7 +219,6 @@
* phaser.arriveAndDeregister();
* }}</pre>
*
- *
* <p>To create a set of {@code n} tasks using a tree of phasers, you
* could use code of the following form, assuming a Task class with a
* constructor accepting a {@code Phaser} that it registers with upon
@@ -348,10 +345,6 @@
private final AtomicReference<QNode> evenQ;
private final AtomicReference<QNode> oddQ;
- private AtomicReference<QNode> queueFor(int phase) {
- return ((phase & 1) == 0) ? evenQ : oddQ;
- }
-
/**
* Returns message string for bounds exceptions on arrival.
*/
@@ -388,7 +381,7 @@
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+ if (STATE.compareAndSet(this, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -401,12 +394,12 @@
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- U.compareAndSwapLong(this, STATE, s, n);
+ STATE.compareAndSet(this, s, n);
releaseWaiters(phase);
}
else if (nextUnarrived == 0) { // propagate deregistration
phase = parent.doArrive(ONE_DEREGISTER);
- U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+ STATE.compareAndSet(this, s, s | EMPTY);
}
else
phase = parent.doArrive(ONE_ARRIVAL);
@@ -441,13 +434,13 @@
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
- else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+ else if (STATE.compareAndSet(this, s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
- if (U.compareAndSwapLong(this, STATE, s, next))
+ if (STATE.compareAndSet(this, s, next))
break;
}
else {
@@ -459,8 +452,8 @@
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
- while (!U.compareAndSwapLong
- (this, STATE, s,
+ while (!STATE.weakCompareAndSet
+ (this, s,
((long)phase << PHASE_SHIFT) | adjust)) {
s = state;
phase = (int)(root.state >>> PHASE_SHIFT);
@@ -491,8 +484,8 @@
// CAS to root phase with current parties, tripping unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
- !U.compareAndSwapLong
- (this, STATE, s,
+ !STATE.weakCompareAndSet
+ (this, s,
s = (((long)phase << PHASE_SHIFT) |
((phase < 0) ? (s & COUNTS_MASK) :
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -681,7 +674,7 @@
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+ if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
@@ -696,7 +689,7 @@
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- if (!U.compareAndSwapLong(this, STATE, s, n))
+ if (!STATE.compareAndSet(this, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
@@ -812,7 +805,7 @@
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
- if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+ if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
// signal all threads
releaseWaiters(0); // Waiters on evenQ
releaseWaiters(1); // Waiters on oddQ
@@ -1047,6 +1040,9 @@
node = new QNode(this, phase, false, false, 0L);
node.wasInterrupted = interrupted;
}
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // else
+ // Thread.onSpinWait();
}
else if (node.isReleasable()) // done or aborted
break;
@@ -1135,16 +1131,14 @@
}
}
- // Unsafe mechanics
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long STATE;
+ // VarHandle mechanics
+ private static final VarHandle STATE;
static {
try {
- STATE = U.objectFieldOffset
- (Phaser.class.getDeclaredField("state"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATE = l.findVarHandle(Phaser.class, "state", long.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
diff --git a/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index 644de86..03a17e5 100644
--- a/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -35,12 +35,15 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.SortedSet;
@@ -48,10 +51,8 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
-
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
+import java.util.function.Predicate;
+import jdk.internal.misc.SharedSecrets;
/**
* An unbounded {@linkplain BlockingQueue blocking queue} that uses
@@ -64,15 +65,15 @@
* non-comparable objects (doing so results in
* {@code ClassCastException}).
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces. The Iterator provided in method {@link
- * #iterator()} is <em>not</em> guaranteed to traverse the elements of
- * the PriorityBlockingQueue in any particular order. If you need
- * ordered traversal, consider using
- * {@code Arrays.sort(pq.toArray())}. Also, method {@code drainTo}
- * can be used to <em>remove</em> some or all elements in priority
- * order and place them in another collection.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * The Iterator provided in method {@link #iterator()} and the
+ * Spliterator provided in method {@link #spliterator()} are <em>not</em>
+ * guaranteed to traverse the elements of the PriorityBlockingQueue in
+ * any particular order. If you need ordered traversal, consider using
+ * {@code Arrays.sort(pq.toArray())}. Also, method {@code drainTo} can
+ * be used to <em>remove</em> some or all elements in priority order and
+ * place them in another collection.
*
* <p>Operations on this class make no guarantees about the ordering
* of elements with equal priority. If you need to enforce an
@@ -101,6 +102,10 @@
* }
* }}</pre>
*
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.5
* @author Doug Lea
* @param <E> the type of elements held in this queue
@@ -163,12 +168,12 @@
/**
* Lock used for all public operations.
*/
- private final ReentrantLock lock;
+ private final ReentrantLock lock = new ReentrantLock();
/**
* Condition for blocking when empty.
*/
- private final Condition notEmpty;
+ private final Condition notEmpty = lock.newCondition();
/**
* Spinlock for allocation, acquired via CAS.
@@ -220,10 +225,8 @@
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
- this.lock = new ReentrantLock();
- this.notEmpty = lock.newCondition();
this.comparator = comparator;
- this.queue = new Object[initialCapacity];
+ this.queue = new Object[Math.max(1, initialCapacity)];
}
/**
@@ -243,8 +246,6 @@
* of its elements are null
*/
public PriorityBlockingQueue(Collection<? extends E> c) {
- this.lock = new ReentrantLock();
- this.notEmpty = lock.newCondition();
boolean heapify = true; // true if not known to be in heap order
boolean screen = true; // true if must screen for nulls
if (c instanceof SortedSet<?>) {
@@ -260,22 +261,27 @@
if (pq.getClass() == PriorityBlockingQueue.class) // exact match
heapify = false;
}
- Object[] a = c.toArray();
- int n = a.length;
+ Object[] es = c.toArray();
+ int n = es.length;
// If c.toArray incorrectly doesn't return Object[], copy it.
- if (a.getClass() != Object[].class)
- a = Arrays.copyOf(a, n, Object[].class);
+ if (es.getClass() != Object[].class)
+ es = Arrays.copyOf(es, n, Object[].class);
if (screen && (n == 1 || this.comparator != null)) {
- for (int i = 0; i < n; ++i)
- if (a[i] == null)
+ for (Object e : es)
+ if (e == null)
throw new NullPointerException();
}
- this.queue = a;
+ this.queue = ensureNonEmpty(es);
this.size = n;
if (heapify)
heapify();
}
+ /** Ensures that queue[0] exists, helping peek() and poll(). */
+ private static Object[] ensureNonEmpty(Object[] es) {
+ return (es.length > 0) ? es : new Object[1];
+ }
+
/**
* Tries to grow array to accommodate at least one more element
* (but normally expand by about 50%), giving up (allowing retry)
@@ -289,7 +295,7 @@
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
- U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+ ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
@@ -319,22 +325,23 @@
* Mechanics for poll(). Call only while holding lock.
*/
private E dequeue() {
- int n = size - 1;
- if (n < 0)
- return null;
- else {
- Object[] array = queue;
- E result = (E) array[0];
- E x = (E) array[n];
- array[n] = null;
- Comparator<? super E> cmp = comparator;
- if (cmp == null)
- siftDownComparable(0, x, array, n);
- else
- siftDownUsingComparator(0, x, array, n, cmp);
- size = n;
- return result;
+ // assert lock.isHeldByCurrentThread();
+ final Object[] es;
+ final E result;
+
+ if ((result = (E) ((es = queue)[0])) != null) {
+ final int n;
+ final E x = (E) es[(n = --size)];
+ es[n] = null;
+ if (n > 0) {
+ final Comparator<? super E> cmp;
+ if ((cmp = comparator) == null)
+ siftDownComparable(0, x, es, n);
+ else
+ siftDownUsingComparator(0, x, es, n, cmp);
+ }
}
+ return result;
}
/**
@@ -342,40 +349,38 @@
* 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.)
- * These methods are static, with heap state as arguments, to
- * simplify use in light of possible comparator exceptions.
*
* @param k the position to fill
* @param x the item to insert
- * @param array the heap array
+ * @param es the heap array
*/
- private static <T> void siftUpComparable(int k, T x, Object[] array) {
+ private static <T> void siftUpComparable(int k, T x, Object[] es) {
Comparable<? super T> key = (Comparable<? super T>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
- Object e = array[parent];
+ Object e = es[parent];
if (key.compareTo((T) e) >= 0)
break;
- array[k] = e;
+ es[k] = e;
k = parent;
}
- array[k] = key;
+ es[k] = key;
}
- private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
- Comparator<? super T> cmp) {
+ private static <T> void siftUpUsingComparator(
+ int k, T x, Object[] es, Comparator<? super T> cmp) {
while (k > 0) {
int parent = (k - 1) >>> 1;
- Object e = array[parent];
+ Object e = es[parent];
if (cmp.compare(x, (T) e) >= 0)
break;
- array[k] = e;
+ es[k] = e;
k = parent;
}
- array[k] = x;
+ es[k] = x;
}
/**
@@ -385,67 +390,61 @@
*
* @param k the position to fill
* @param x the item to insert
- * @param array the heap array
+ * @param es the heap array
* @param n heap size
*/
- private static <T> void siftDownComparable(int k, T x, Object[] array,
- int n) {
- if (n > 0) {
- Comparable<? super T> key = (Comparable<? super T>)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 = array[child];
- int right = child + 1;
- if (right < n &&
- ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
- c = array[child = right];
- if (key.compareTo((T) c) <= 0)
- break;
- array[k] = c;
- k = child;
- }
- array[k] = key;
+ private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
+ // assert n > 0;
+ Comparable<? super T> key = (Comparable<? super T>)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 = es[child];
+ int right = child + 1;
+ if (right < n &&
+ ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
+ c = es[child = right];
+ if (key.compareTo((T) c) <= 0)
+ break;
+ es[k] = c;
+ k = child;
}
+ es[k] = key;
}
- private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
- int n,
- Comparator<? super T> cmp) {
- if (n > 0) {
- int half = n >>> 1;
- while (k < half) {
- int child = (k << 1) + 1;
- Object c = array[child];
- int right = child + 1;
- if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
- c = array[child = right];
- if (cmp.compare(x, (T) c) <= 0)
- break;
- array[k] = c;
- k = child;
- }
- array[k] = x;
+ private static <T> void siftDownUsingComparator(
+ int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
+ // assert n > 0;
+ int half = n >>> 1;
+ while (k < half) {
+ int child = (k << 1) + 1;
+ Object c = es[child];
+ int right = child + 1;
+ if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
+ c = es[child = right];
+ if (cmp.compare(x, (T) c) <= 0)
+ break;
+ es[k] = c;
+ k = child;
}
+ 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).
*/
private void heapify() {
- Object[] array = queue;
- int n = size;
- int half = (n >>> 1) - 1;
- Comparator<? super E> cmp = comparator;
- if (cmp == null) {
- for (int i = half; i >= 0; i--)
- siftDownComparable(i, (E) array[i], array, n);
- }
- else {
- for (int i = half; i >= 0; i--)
- siftDownUsingComparator(i, (E) array[i], array, n, cmp);
- }
+ final Object[] es = queue;
+ int n = size, i = (n >>> 1) - 1;
+ final Comparator<? super E> 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);
}
/**
@@ -479,15 +478,15 @@
final ReentrantLock lock = this.lock;
lock.lock();
int n, cap;
- Object[] array;
- while ((n = size) >= (cap = (array = queue).length))
- tryGrow(array, cap);
+ Object[] es;
+ while ((n = size) >= (cap = (es = queue).length))
+ tryGrow(es, cap);
try {
- Comparator<? super E> cmp = comparator;
- if (cmp == null)
- siftUpComparable(n, e, array);
+ final Comparator<? super E> cmp;
+ if ((cmp = comparator) == null)
+ siftUpComparable(n, e, es);
else
- siftUpUsingComparator(n, e, array, cmp);
+ siftUpUsingComparator(n, e, es, cmp);
size = n + 1;
notEmpty.signal();
} finally {
@@ -570,7 +569,7 @@
final ReentrantLock lock = this.lock;
lock.lock();
try {
- return (size == 0) ? null : (E) queue[0];
+ return (E) queue[0];
} finally {
lock.unlock();
}
@@ -610,10 +609,9 @@
private int indexOf(Object o) {
if (o != null) {
- Object[] array = queue;
- int n = size;
- for (int i = 0; i < n; i++)
- if (o.equals(array[i]))
+ final Object[] es = queue;
+ for (int i = 0, n = size; i < n; i++)
+ if (o.equals(es[i]))
return i;
}
return -1;
@@ -623,23 +621,23 @@
* Removes the ith element from queue.
*/
private void removeAt(int i) {
- Object[] array = queue;
- int n = size - 1;
+ final Object[] es = queue;
+ final int n = size - 1;
if (n == i) // removed last element
- array[i] = null;
+ es[i] = null;
else {
- E moved = (E) array[n];
- array[n] = null;
- Comparator<? super E> cmp = comparator;
- if (cmp == null)
- siftDownComparable(i, moved, array, n);
+ E moved = (E) es[n];
+ es[n] = null;
+ final Comparator<? super E> cmp;
+ if ((cmp = comparator) == null)
+ siftDownComparable(i, moved, es, n);
else
- siftDownUsingComparator(i, moved, array, n, cmp);
- if (array[i] == moved) {
+ siftDownUsingComparator(i, moved, es, n, cmp);
+ if (es[i] == moved) {
if (cmp == null)
- siftUpComparable(i, moved, array);
+ siftUpComparable(i, moved, es);
else
- siftUpUsingComparator(i, moved, array, cmp);
+ siftUpUsingComparator(i, moved, es, cmp);
}
}
size = n;
@@ -672,14 +670,16 @@
/**
* Identity-based version for use in Itr.remove.
+ *
+ * @param o element to be removed from this queue, if present
*/
- void removeEQ(Object o) {
+ void removeEq(Object o) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
- Object[] array = queue;
+ final Object[] es = queue;
for (int i = 0, n = size; i < n; i++) {
- if (o == array[i]) {
+ if (o == es[i]) {
removeAt(i);
break;
}
@@ -728,8 +728,7 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -756,11 +755,10 @@
final ReentrantLock lock = this.lock;
lock.lock();
try {
- Object[] array = queue;
- int n = size;
+ final Object[] es = queue;
+ for (int i = 0, n = size; i < n; i++)
+ es[i] = null;
size = 0;
- for (int i = 0; i < n; i++)
- array[i] = null;
} finally {
lock.unlock();
}
@@ -861,10 +859,9 @@
final class Itr implements Iterator<E> {
final Object[] array; // Array of all elements
int cursor; // index of next element to return
- int lastRet; // index of last element, or -1 if no such
+ int lastRet = -1; // index of last element, or -1 if no such
Itr(Object[] array) {
- lastRet = -1;
this.array = array;
}
@@ -875,16 +872,28 @@
public E next() {
if (cursor >= array.length)
throw new NoSuchElementException();
- lastRet = cursor;
- return (E)array[cursor++];
+ return (E)array[lastRet = cursor++];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
- removeEQ(array[lastRet]);
+ removeEq(array[lastRet]);
lastRet = -1;
}
+
+ public void forEachRemaining(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ final Object[] es = array;
+ int i;
+ if ((i = cursor) < es.length) {
+ lastRet = -1;
+ cursor = es.length;
+ for (; i < es.length; i++)
+ action.accept((E) es[i]);
+ lastRet = es.length - 1;
+ }
+ }
}
/**
@@ -922,7 +931,9 @@
throws java.io.IOException, ClassNotFoundException {
try {
s.defaultReadObject();
- this.queue = new Object[q.size()];
+ int sz = q.size();
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, sz);
+ this.queue = new Object[Math.max(1, sz)];
comparator = q.comparator();
addAll(q);
} finally {
@@ -930,68 +941,65 @@
}
}
- // Similar to Collections.ArraySnapshotSpliterator but avoids
- // commitment to toArray until needed
- static final class PBQSpliterator<E> implements Spliterator<E> {
- final PriorityBlockingQueue<E> queue;
- Object[] array;
+ /**
+ * Immutable snapshot spliterator that binds to elements "late".
+ */
+ final class PBQSpliterator implements Spliterator<E> {
+ Object[] array; // null until late-bound-initialized
int index;
int fence;
- PBQSpliterator(PriorityBlockingQueue<E> queue, Object[] array,
- int index, int fence) {
- this.queue = queue;
+ PBQSpliterator() {}
+
+ PBQSpliterator(Object[] array, int index, int fence) {
this.array = array;
this.index = index;
this.fence = fence;
}
- final int getFence() {
- int hi;
- if ((hi = fence) < 0)
- hi = fence = (array = queue.toArray()).length;
- return hi;
+ private int getFence() {
+ if (array == null)
+ fence = (array = toArray()).length;
+ return fence;
}
- public PBQSpliterator<E> trySplit() {
+ public PBQSpliterator trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid) ? null :
- new PBQSpliterator<E>(queue, array, lo, index = mid);
+ new PBQSpliterator(array, lo, index = mid);
}
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
- Object[] a; int i, hi; // hoist accesses and checks from loop
- if (action == null)
- throw new NullPointerException();
- if ((a = array) == null)
- fence = (a = queue.toArray()).length;
- if ((hi = fence) <= a.length &&
- (i = index) >= 0 && i < (index = hi)) {
- do { action.accept((E)a[i]); } while (++i < hi);
- }
+ Objects.requireNonNull(action);
+ final int hi = getFence(), lo = index;
+ final Object[] es = array;
+ index = hi; // ensure exhaustion
+ for (int i = lo; i < hi; i++)
+ action.accept((E) es[i]);
}
public boolean tryAdvance(Consumer<? super E> action) {
- if (action == null)
- throw new NullPointerException();
+ Objects.requireNonNull(action);
if (getFence() > index && index >= 0) {
- @SuppressWarnings("unchecked") E e = (E) array[index++];
- action.accept(e);
+ action.accept((E) array[index++]);
return true;
}
return false;
}
- public long estimateSize() { return (long)(getFence() - index); }
+ public long estimateSize() { return getFence() - index; }
public int characteristics() {
- return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
+ return (Spliterator.NONNULL |
+ Spliterator.SIZED |
+ Spliterator.SUBSIZED);
}
}
/**
* Returns a {@link Spliterator} over the elements in this queue.
+ * The spliterator does not traverse elements in any particular order
+ * (the {@link Spliterator#ORDERED ORDERED} characteristic is not reported).
*
* <p>The returned spliterator is
* <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
@@ -1006,18 +1014,106 @@
* @since 1.8
*/
public Spliterator<E> spliterator() {
- return new PBQSpliterator<E>(this, null, 0, -1);
+ return new PBQSpliterator();
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long ALLOCATIONSPINLOCK;
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean removeIf(Predicate<? super E> 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<? super E> filter) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ 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)
+ return false;
+ // Tolerate predicates that reentrantly access the
+ // collection for read, 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);
+ 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;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void forEach(Consumer<? super E> action) {
+ Objects.requireNonNull(action);
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ final Object[] es = queue;
+ for (int i = 0, n = size; i < n; i++)
+ action.accept((E) es[i]);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ // VarHandle mechanics
+ private static final VarHandle ALLOCATIONSPINLOCK;
static {
try {
- ALLOCATIONSPINLOCK = U.objectFieldOffset
- (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
+ "allocationSpinLock",
+ int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
index 6b9fcc3..be75ff4 100644
--- a/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
+++ b/ojluni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
@@ -77,14 +77,11 @@
* Executors.newScheduledThreadPool(1);
*
* public void beepForAnHour() {
- * final Runnable beeper = new Runnable() {
- * public void run() { System.out.println("beep"); }
- * };
- * final ScheduledFuture<?< beeperHandle =
+ * Runnable beeper = () -> System.out.println("beep");
+ * ScheduledFuture<?> beeperHandle =
* scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
- * scheduler.schedule(new Runnable() {
- * public void run() { beeperHandle.cancel(true); }
- * }, 60 * 60, SECONDS);
+ * Runnable canceller = () -> beeperHandle.cancel(false);
+ * scheduler.schedule(canceller, 1, HOURS);
* }
* }}</pre>
*
@@ -94,8 +91,7 @@
public interface ScheduledExecutorService extends ExecutorService {
/**
- * Creates and executes a one-shot action that becomes enabled
- * after the given delay.
+ * Submits a one-shot task that becomes enabled after the given delay.
*
* @param command the task to execute
* @param delay the time from now to delay execution
@@ -105,14 +101,14 @@
* {@code null} upon completion
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
- * @throws NullPointerException if command is null
+ * @throws NullPointerException if command or unit is null
*/
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
/**
- * Creates and executes a ScheduledFuture that becomes enabled after the
- * given delay.
+ * Submits a value-returning one-shot task that becomes enabled
+ * after the given delay.
*
* @param callable the function to execute
* @param delay the time from now to delay execution
@@ -121,15 +117,15 @@
* @return a ScheduledFuture that can be used to extract result or cancel
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
- * @throws NullPointerException if callable is null
+ * @throws NullPointerException if callable or unit is null
*/
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
/**
- * Creates and executes a periodic action that becomes enabled first
- * after the given initial delay, and subsequently with the given
- * period; that is, executions will commence after
+ * Submits a periodic action that becomes enabled first after the
+ * given initial delay, and subsequently with the given period;
+ * that is, executions will commence after
* {@code initialDelay}, then {@code initialDelay + period}, then
* {@code initialDelay + 2 * period}, and so on.
*
@@ -140,8 +136,8 @@
* via the returned future.
* <li>The executor terminates, also resulting in task cancellation.
* <li>An execution of the task throws an exception. In this case
- * calling {@link Future#get() get} on the returned future will
- * throw {@link ExecutionException}.
+ * calling {@link Future#get() get} on the returned future will throw
+ * {@link ExecutionException}, holding the exception as its cause.
* </ul>
* Subsequent executions are suppressed. Subsequent calls to
* {@link Future#isDone isDone()} on the returned future will
@@ -162,7 +158,7 @@
* abnormal termination of a task execution.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
- * @throws NullPointerException if command is null
+ * @throws NullPointerException if command or unit is null
* @throws IllegalArgumentException if period less than or equal to zero
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
@@ -171,10 +167,10 @@
TimeUnit unit);
/**
- * Creates and executes a periodic action that becomes enabled first
- * after the given initial delay, and subsequently with the
- * given delay between the termination of one execution and the
- * commencement of the next.
+ * Submits a periodic action that becomes enabled first after the
+ * given initial delay, and subsequently with the given delay
+ * between the termination of one execution and the commencement of
+ * the next.
*
* <p>The sequence of task executions continues indefinitely until
* one of the following exceptional completions occur:
@@ -183,8 +179,8 @@
* via the returned future.
* <li>The executor terminates, also resulting in task cancellation.
* <li>An execution of the task throws an exception. In this case
- * calling {@link Future#get() get} on the returned future will
- * throw {@link ExecutionException}.
+ * calling {@link Future#get() get} on the returned future will throw
+ * {@link ExecutionException}, holding the exception as its cause.
* </ul>
* Subsequent executions are suppressed. Subsequent calls to
* {@link Future#isDone isDone()} on the returned future will
@@ -202,7 +198,7 @@
* abnormal termination of a task execution.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
- * @throws NullPointerException if command is null
+ * @throws NullPointerException if command or unit is null
* @throws IllegalArgumentException if delay less than or equal to zero
*/
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
diff --git a/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index 4249872..192df25 100644
--- a/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -44,6 +44,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -89,6 +90,11 @@
* use {@code allowCoreThreadTimeOut} because this may leave the pool
* without threads to handle tasks once they become eligible to run.
*
+ * <p>As with {@code ThreadPoolExecutor}, if not otherwise specified,
+ * this class uses {@link Executors#defaultThreadFactory} as the
+ * default thread factory, and {@link ThreadPoolExecutor.AbortPolicy}
+ * as the default rejected execution handler.
+ *
* <p><b>Extension notes:</b> This class overrides the
* {@link ThreadPoolExecutor#execute(Runnable) execute} and
* {@link AbstractExecutorService#submit(Runnable) submit}
@@ -162,6 +168,7 @@
*/
private volatile boolean continueExistingPeriodicTasksAfterShutdown;
+ // Android-changed: Preserving behaviour on expired tasks (b/202927404)
/**
* False if should cancel non-periodic tasks on shutdown.
*/
@@ -294,10 +301,9 @@
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
- boolean periodic = isPeriodic();
- if (!canRunInCurrentRunState(periodic))
+ if (!canRunInCurrentRunState(this))
cancel(false);
- else if (!periodic)
+ else if (!isPeriodic())
super.run();
else if (super.runAndReset()) {
setNextRunTime();
@@ -307,15 +313,20 @@
}
/**
- * Returns true if can run a task given current run state
- * and run-after-shutdown parameters.
- *
- * @param periodic true if this task periodic, false if delayed
+ * Returns true if can run a task given current run state and
+ * run-after-shutdown parameters.
*/
- boolean canRunInCurrentRunState(boolean periodic) {
- return isRunningOrShutdown(periodic ?
- continueExistingPeriodicTasksAfterShutdown :
- executeExistingDelayedTasksAfterShutdown);
+ boolean canRunInCurrentRunState(RunnableScheduledFuture<?> task) {
+ if (!isShutdown())
+ return true;
+ if (isStopped())
+ return false;
+ return task.isPeriodic()
+ ? continueExistingPeriodicTasksAfterShutdown
+ : (executeExistingDelayedTasksAfterShutdown
+ // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+ // || task.getDelay(NANOSECONDS) <= 0);
+ );
}
/**
@@ -334,9 +345,7 @@
reject(task);
else {
super.getQueue().add(task);
- if (isShutdown() &&
- !canRunInCurrentRunState(task.isPeriodic()) &&
- remove(task))
+ if (!canRunInCurrentRunState(task) && remove(task))
task.cancel(false);
else
ensurePrestart();
@@ -350,13 +359,14 @@
* @param task the task
*/
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
- if (canRunInCurrentRunState(true)) {
+ if (canRunInCurrentRunState(task)) {
super.getQueue().add(task);
- if (!canRunInCurrentRunState(true) && remove(task))
- task.cancel(false);
- else
+ if (canRunInCurrentRunState(task) || !remove(task)) {
ensurePrestart();
+ return;
+ }
}
+ task.cancel(false);
}
/**
@@ -369,23 +379,20 @@
getExecuteExistingDelayedTasksAfterShutdownPolicy();
boolean keepPeriodic =
getContinueExistingPeriodicTasksAfterShutdownPolicy();
- if (!keepDelayed && !keepPeriodic) {
- for (Object e : q.toArray())
- if (e instanceof RunnableScheduledFuture<?>)
- ((RunnableScheduledFuture<?>) e).cancel(false);
- q.clear();
- }
- else {
- // Traverse snapshot to avoid iterator exceptions
- for (Object e : q.toArray()) {
- if (e instanceof RunnableScheduledFuture) {
- RunnableScheduledFuture<?> t =
- (RunnableScheduledFuture<?>)e;
- if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
- t.isCancelled()) { // also remove if already cancelled
- if (q.remove(t))
- t.cancel(false);
- }
+ // Traverse snapshot to avoid iterator exceptions
+ // TODO: implement and use efficient removeIf
+ // super.getQueue().removeIf(...);
+ for (Object e : q.toArray()) {
+ if (e instanceof RunnableScheduledFuture) {
+ RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>)e;
+ if ((t.isPeriodic()
+ ? !keepPeriodic
+ // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+ // : (!keepDelayed && t.getDelay(NANOSECONDS) > 0))
+ : !keepDelayed)
+ || t.isCancelled()) { // also remove if already cancelled
+ if (q.remove(t))
+ t.cancel(false);
}
}
}
@@ -581,6 +588,34 @@
}
/**
+ * Submits a periodic action that becomes enabled first after the
+ * given initial delay, and subsequently with the given period;
+ * that is, executions will commence after
+ * {@code initialDelay}, then {@code initialDelay + period}, then
+ * {@code initialDelay + 2 * period}, and so on.
+ *
+ * <p>The sequence of task executions continues indefinitely until
+ * one of the following exceptional completions occur:
+ * <ul>
+ * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+ * via the returned future.
+ * <li>Method {@link #shutdown} is called and the {@linkplain
+ * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
+ * whether to continue after shutdown} is not set true, or method
+ * {@link #shutdownNow} is called; also resulting in task
+ * cancellation.
+ * <li>An execution of the task throws an exception. In this case
+ * calling {@link Future#get() get} on the returned future will throw
+ * {@link ExecutionException}, holding the exception as its cause.
+ * </ul>
+ * Subsequent executions are suppressed. Subsequent calls to
+ * {@link Future#isDone isDone()} on the returned future will
+ * return {@code true}.
+ *
+ * <p>If any execution of this task takes longer than its period, then
+ * subsequent executions may start late, but will not concurrently
+ * execute.
+ *
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
@@ -606,6 +641,29 @@
}
/**
+ * Submits a periodic action that becomes enabled first after the
+ * given initial delay, and subsequently with the given delay
+ * between the termination of one execution and the commencement of
+ * the next.
+ *
+ * <p>The sequence of task executions continues indefinitely until
+ * one of the following exceptional completions occur:
+ * <ul>
+ * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+ * via the returned future.
+ * <li>Method {@link #shutdown} is called and the {@linkplain
+ * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
+ * whether to continue after shutdown} is not set true, or method
+ * {@link #shutdownNow} is called; also resulting in task
+ * cancellation.
+ * <li>An execution of the task throws an exception. In this case
+ * calling {@link Future#get() get} on the returned future will throw
+ * {@link ExecutionException}, holding the exception as its cause.
+ * </ul>
+ * Subsequent executions are suppressed. Subsequent calls to
+ * {@link Future#isDone isDone()} on the returned future will
+ * return {@code true}.
+ *
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
@@ -683,9 +741,8 @@
/**
* Sets the policy on whether to continue executing existing
* periodic tasks even when this executor has been {@code shutdown}.
- * In this case, these tasks will only terminate upon
- * {@code shutdownNow} or after setting the policy to
- * {@code false} when already shutdown.
+ * In this case, executions will continue until {@code shutdownNow}
+ * or the policy is set to {@code false} when already shutdown.
* This value is by default {@code false}.
*
* @param value if {@code true}, continue after shutdown, else don't
@@ -700,9 +757,8 @@
/**
* Gets the policy on whether to continue executing existing
* periodic tasks even when this executor has been {@code shutdown}.
- * In this case, these tasks will only terminate upon
- * {@code shutdownNow} or after setting the policy to
- * {@code false} when already shutdown.
+ * In this case, executions will continue until {@code shutdownNow}
+ * or the policy is set to {@code false} when already shutdown.
* This value is by default {@code false}.
*
* @return {@code true} if will continue after shutdown
@@ -905,7 +961,7 @@
/**
* Sets f's heapIndex if it is a ScheduledFutureTask.
*/
- private void setIndex(RunnableScheduledFuture<?> f, int idx) {
+ private static void setIndex(RunnableScheduledFuture<?> f, int idx) {
if (f instanceof ScheduledFutureTask)
((ScheduledFutureTask)f).heapIndex = idx;
}
@@ -1203,41 +1259,12 @@
}
}
- /**
- * Returns first element only if it is expired.
- * Used only by drainTo. Call only when holding lock.
- */
- private RunnableScheduledFuture<?> peekExpired() {
- // assert lock.isHeldByCurrentThread();
- RunnableScheduledFuture<?> first = queue[0];
- return (first == null || first.getDelay(NANOSECONDS) > 0) ?
- null : first;
- }
-
public int drainTo(Collection<? super Runnable> c) {
- if (c == null)
- throw new NullPointerException();
- if (c == this)
- throw new IllegalArgumentException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- RunnableScheduledFuture<?> first;
- int n = 0;
- while ((first = peekExpired()) != null) {
- c.add(first); // In this order, in case add() throws.
- finishPoll(first);
- ++n;
- }
- return n;
- } finally {
- lock.unlock();
- }
+ return drainTo(c, Integer.MAX_VALUE);
}
public int drainTo(Collection<? super Runnable> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -1245,9 +1272,11 @@
final ReentrantLock lock = this.lock;
lock.lock();
try {
- RunnableScheduledFuture<?> first;
int n = 0;
- while (n < maxElements && (first = peekExpired()) != null) {
+ for (RunnableScheduledFuture<?> first;
+ n < maxElements
+ && (first = queue[0]) != null
+ && first.getDelay(NANOSECONDS) <= 0;) {
c.add(first); // In this order, in case add() throws.
finishPoll(first);
++n;
@@ -1285,7 +1314,13 @@
}
public Iterator<Runnable> iterator() {
- return new Itr(Arrays.copyOf(queue, size));
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return new Itr(Arrays.copyOf(queue, size));
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -1307,8 +1342,7 @@
public Runnable next() {
if (cursor >= array.length)
throw new NoSuchElementException();
- lastRet = cursor;
- return array[cursor++];
+ return array[lastRet = cursor++];
}
public void remove() {
diff --git a/ojluni/src/main/java/java/util/concurrent/Semaphore.java b/ojluni/src/main/java/java/util/concurrent/Semaphore.java
index 1298a6e..86ee638 100644
--- a/ojluni/src/main/java/java/util/concurrent/Semaphore.java
+++ b/ojluni/src/main/java/java/util/concurrent/Semaphore.java
@@ -72,8 +72,8 @@
* protected synchronized Object getNextAvailableItem() {
* for (int i = 0; i < MAX_AVAILABLE; ++i) {
* if (!used[i]) {
- * used[i] = true;
- * return items[i];
+ * used[i] = true;
+ * return items[i];
* }
* }
* return null; // not reached
@@ -82,11 +82,11 @@
* protected synchronized boolean markAsUnused(Object item) {
* for (int i = 0; i < MAX_AVAILABLE; ++i) {
* if (item == items[i]) {
- * if (used[i]) {
- * used[i] = false;
- * return true;
- * } else
- * return false;
+ * if (used[i]) {
+ * used[i] = false;
+ * return true;
+ * } else
+ * return false;
* }
* }
* return false;
@@ -359,7 +359,7 @@
* This "barging" behavior can be useful in certain
* circumstances, even though it breaks fairness. If you want to honor
* the fairness setting, then use
- * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) }
+ * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS)}
* which is almost equivalent (it also detects interruption).
*
* @return {@code true} if a permit was acquired and {@code false}
@@ -523,7 +523,7 @@
* "barging" behavior can be useful in certain
* circumstances, even though it breaks fairness. If you want to
* honor the fairness setting, then use {@link #tryAcquire(int,
- * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) }
+ * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS)}
* which is almost equivalent (it also detects interruption).
*
* @param permits the number of permits to acquire
@@ -631,9 +631,12 @@
}
/**
- * Acquires and returns all permits that are immediately available.
+ * Acquires and returns all permits that are immediately
+ * available, or if negative permits are available, releases them.
+ * Upon return, zero permits are available.
*
- * @return the number of permits acquired
+ * @return the number of permits acquired or, if negative, the
+ * number released
*/
public int drainPermits() {
return sync.drainPermits();
diff --git a/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java b/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java
new file mode 100644
index 0000000..9efb01d
--- /dev/null
+++ b/ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java
@@ -0,0 +1,1477 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import static java.util.concurrent.Flow.Publisher;
+import static java.util.concurrent.Flow.Subscriber;
+import static java.util.concurrent.Flow.Subscription;
+
+/**
+ * A {@link Flow.Publisher} that asynchronously issues submitted
+ * (non-null) items to current subscribers until it is closed. Each
+ * current subscriber receives newly submitted items in the same order
+ * unless drops or exceptions are encountered. Using a
+ * SubmissionPublisher allows item generators to act as compliant <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * Publishers relying on drop handling and/or blocking for flow
+ * control.
+ *
+ * <p>A SubmissionPublisher uses the {@link Executor} supplied in its
+ * constructor for delivery to subscribers. The best choice of
+ * Executor depends on expected usage. If the generator(s) of
+ * submitted items run in separate threads, and the number of
+ * subscribers can be estimated, consider using a {@link
+ * Executors#newFixedThreadPool}. Otherwise consider using the
+ * default, normally the {@link ForkJoinPool#commonPool}.
+ *
+ * <p>Buffering allows producers and consumers to transiently operate
+ * at different rates. Each subscriber uses an independent buffer.
+ * Buffers are created upon first use and expanded as needed up to the
+ * given maximum. (The enforced capacity may be rounded up to the
+ * nearest power of two and/or bounded by the largest value supported
+ * by this implementation.) Invocations of {@link
+ * Flow.Subscription#request(long) request} do not directly result in
+ * buffer expansion, but risk saturation if unfilled requests exceed
+ * the maximum capacity. The default value of {@link
+ * Flow#defaultBufferSize()} may provide a useful starting point for
+ * choosing a capacity based on expected rates, resources, and usages.
+ *
+ * <p>A single SubmissionPublisher may be shared among multiple
+ * sources. Actions in a source thread prior to publishing an item or
+ * issuing a signal <a href="package-summary.html#MemoryVisibility">
+ * <i>happen-before</i></a> actions subsequent to the corresponding
+ * access by each subscriber. But reported estimates of lag and demand
+ * are designed for use in monitoring, not for synchronization
+ * control, and may reflect stale or inaccurate views of progress.
+ *
+ * <p>Publication methods support different policies about what to do
+ * when buffers are saturated. Method {@link #submit(Object) submit}
+ * blocks until resources are available. This is simplest, but least
+ * responsive. The {@code offer} methods may drop items (either
+ * immediately or with bounded timeout), but provide an opportunity to
+ * interpose a handler and then retry.
+ *
+ * <p>If any Subscriber method throws an exception, its subscription
+ * is cancelled. If a handler is supplied as a constructor argument,
+ * it is invoked before cancellation upon an exception in method
+ * {@link Flow.Subscriber#onNext onNext}, but exceptions in methods
+ * {@link Flow.Subscriber#onSubscribe onSubscribe},
+ * {@link Flow.Subscriber#onError(Throwable) onError} and
+ * {@link Flow.Subscriber#onComplete() onComplete} are not recorded or
+ * handled before cancellation. If the supplied Executor throws
+ * {@link RejectedExecutionException} (or any other RuntimeException
+ * or Error) when attempting to execute a task, or a drop handler
+ * throws an exception when processing a dropped item, then the
+ * exception is rethrown. In these cases, not all subscribers will
+ * have been issued the published item. It is usually good practice to
+ * {@link #closeExceptionally closeExceptionally} in these cases.
+ *
+ * <p>Method {@link #consume(Consumer)} simplifies support for a
+ * common case in which the only action of a subscriber is to request
+ * and process all items using a supplied function.
+ *
+ * <p>This class may also serve as a convenient base for subclasses
+ * that generate items, and use the methods in this class to publish
+ * them. For example here is a class that periodically publishes the
+ * items generated from a supplier. (In practice you might add methods
+ * to independently start and stop generation, to share Executors
+ * among publishers, and so on, or use a SubmissionPublisher as a
+ * component rather than a superclass.)
+ *
+ * <pre> {@code
+ * class PeriodicPublisher<T> extends SubmissionPublisher<T> {
+ * final ScheduledFuture<?> periodicTask;
+ * final ScheduledExecutorService scheduler;
+ * PeriodicPublisher(Executor executor, int maxBufferCapacity,
+ * Supplier<? extends T> supplier,
+ * long period, TimeUnit unit) {
+ * super(executor, maxBufferCapacity);
+ * scheduler = new ScheduledThreadPoolExecutor(1);
+ * periodicTask = scheduler.scheduleAtFixedRate(
+ * () -> submit(supplier.get()), 0, period, unit);
+ * }
+ * public void close() {
+ * periodicTask.cancel(false);
+ * scheduler.shutdown();
+ * super.close();
+ * }
+ * }}</pre>
+ *
+ * <p>Here is an example of a {@link Flow.Processor} implementation.
+ * It uses single-step requests to its publisher for simplicity of
+ * illustration. A more adaptive version could monitor flow using the
+ * lag estimate returned from {@code submit}, along with other utility
+ * methods.
+ *
+ * <pre> {@code
+ * class TransformProcessor<S,T> extends SubmissionPublisher<T>
+ * implements Flow.Processor<S,T> {
+ * final Function<? super S, ? extends T> function;
+ * Flow.Subscription subscription;
+ * TransformProcessor(Executor executor, int maxBufferCapacity,
+ * Function<? super S, ? extends T> function) {
+ * super(executor, maxBufferCapacity);
+ * this.function = function;
+ * }
+ * public void onSubscribe(Flow.Subscription subscription) {
+ * (this.subscription = subscription).request(1);
+ * }
+ * public void onNext(S item) {
+ * subscription.request(1);
+ * submit(function.apply(item));
+ * }
+ * public void onError(Throwable ex) { closeExceptionally(ex); }
+ * public void onComplete() { close(); }
+ * }}</pre>
+ *
+ * @param <T> the published item type
+ * @author Doug Lea
+ * @since 9
+ */
+public class SubmissionPublisher<T> implements Publisher<T>,
+ AutoCloseable {
+ /*
+ * Most mechanics are handled by BufferedSubscription. This class
+ * mainly tracks subscribers and ensures sequentiality, by using
+ * built-in synchronization locks across public methods. Using
+ * built-in locks works well in the most typical case in which
+ * only one thread submits items. We extend this idea in
+ * submission methods by detecting single-ownership to reduce
+ * producer-consumer synchronization strength.
+ */
+
+ /** The largest possible power of two array size. */
+ static final int BUFFER_CAPACITY_LIMIT = 1 << 30;
+
+ /**
+ * Initial buffer capacity used when maxBufferCapacity is
+ * greater. Must be a power of two.
+ */
+ static final int INITIAL_CAPACITY = 32;
+
+ /** Round capacity to power of 2, at most limit. */
+ static final int roundCapacity(int cap) {
+ int n = cap - 1;
+ n |= n >>> 1;
+ n |= n >>> 2;
+ n |= n >>> 4;
+ n |= n >>> 8;
+ n |= n >>> 16;
+ return (n <= 0) ? 1 : // at least 1
+ (n >= BUFFER_CAPACITY_LIMIT) ? BUFFER_CAPACITY_LIMIT : n + 1;
+ }
+
+ // default Executor setup; nearly the same as CompletableFuture
+
+ /**
+ * Default executor -- ForkJoinPool.commonPool() unless it cannot
+ * support parallelism.
+ */
+ private static final Executor ASYNC_POOL =
+ (ForkJoinPool.getCommonPoolParallelism() > 1) ?
+ ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+ /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+ private static final class ThreadPerTaskExecutor implements Executor {
+ ThreadPerTaskExecutor() {} // prevent access constructor creation
+ public void execute(Runnable r) { new Thread(r).start(); }
+ }
+
+ /**
+ * Clients (BufferedSubscriptions) are maintained in a linked list
+ * (via their "next" fields). This works well for publish loops.
+ * It requires O(n) traversal to check for duplicate subscribers,
+ * but we expect that subscribing is much less common than
+ * publishing. Unsubscribing occurs only during traversal loops,
+ * when BufferedSubscription methods return negative values
+ * signifying that they have been closed. To reduce
+ * head-of-line blocking, submit and offer methods first call
+ * BufferedSubscription.offer on each subscriber, and place
+ * saturated ones in retries list (using nextRetry field), and
+ * retry, possibly blocking or dropping.
+ */
+ BufferedSubscription<T> clients;
+
+ /** Run status, updated only within locks */
+ volatile boolean closed;
+ /** Set true on first call to subscribe, to initialize possible owner */
+ boolean subscribed;
+ /** The first caller thread to subscribe, or null if thread ever changed */
+ Thread owner;
+ /** If non-null, the exception in closeExceptionally */
+ volatile Throwable closedException;
+
+ // Parameters for constructing BufferedSubscriptions
+ final Executor executor;
+ final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+ final int maxBufferCapacity;
+
+ /**
+ * Creates a new SubmissionPublisher using the given Executor for
+ * async delivery to subscribers, with the given maximum buffer size
+ * for each subscriber, and, if non-null, the given handler invoked
+ * when any Subscriber throws an exception in method {@link
+ * Flow.Subscriber#onNext(Object) onNext}.
+ *
+ * @param executor the executor to use for async delivery,
+ * supporting creation of at least one independent thread
+ * @param maxBufferCapacity the maximum capacity for each
+ * subscriber's buffer (the enforced capacity may be rounded up to
+ * the nearest power of two and/or bounded by the largest value
+ * supported by this implementation; method {@link #getMaxBufferCapacity}
+ * returns the actual value)
+ * @param handler if non-null, procedure to invoke upon exception
+ * thrown in method {@code onNext}
+ * @throws NullPointerException if executor is null
+ * @throws IllegalArgumentException if maxBufferCapacity not
+ * positive
+ */
+ public SubmissionPublisher(Executor executor, int maxBufferCapacity,
+ BiConsumer<? super Subscriber<? super T>, ? super Throwable> handler) {
+ if (executor == null)
+ throw new NullPointerException();
+ if (maxBufferCapacity <= 0)
+ throw new IllegalArgumentException("capacity must be positive");
+ this.executor = executor;
+ this.onNextHandler = handler;
+ this.maxBufferCapacity = roundCapacity(maxBufferCapacity);
+ }
+
+ /**
+ * Creates a new SubmissionPublisher using the given Executor for
+ * async delivery to subscribers, with the given maximum buffer size
+ * for each subscriber, and no handler for Subscriber exceptions in
+ * method {@link Flow.Subscriber#onNext(Object) onNext}.
+ *
+ * @param executor the executor to use for async delivery,
+ * supporting creation of at least one independent thread
+ * @param maxBufferCapacity the maximum capacity for each
+ * subscriber's buffer (the enforced capacity may be rounded up to
+ * the nearest power of two and/or bounded by the largest value
+ * supported by this implementation; method {@link #getMaxBufferCapacity}
+ * returns the actual value)
+ * @throws NullPointerException if executor is null
+ * @throws IllegalArgumentException if maxBufferCapacity not
+ * positive
+ */
+ public SubmissionPublisher(Executor executor, int maxBufferCapacity) {
+ this(executor, maxBufferCapacity, null);
+ }
+
+ /**
+ * Creates a new SubmissionPublisher using the {@link
+ * ForkJoinPool#commonPool()} for async delivery to subscribers
+ * (unless it does not support a parallelism level of at least two,
+ * in which case, a new Thread is created to run each task), with
+ * maximum buffer capacity of {@link Flow#defaultBufferSize}, and no
+ * handler for Subscriber exceptions in method {@link
+ * Flow.Subscriber#onNext(Object) onNext}.
+ */
+ public SubmissionPublisher() {
+ this(ASYNC_POOL, Flow.defaultBufferSize(), null);
+ }
+
+ /**
+ * Adds the given Subscriber unless already subscribed. If already
+ * subscribed, the Subscriber's {@link
+ * Flow.Subscriber#onError(Throwable) onError} method is invoked on
+ * the existing subscription with an {@link IllegalStateException}.
+ * Otherwise, upon success, the Subscriber's {@link
+ * Flow.Subscriber#onSubscribe onSubscribe} method is invoked
+ * asynchronously with a new {@link Flow.Subscription}. If {@link
+ * Flow.Subscriber#onSubscribe onSubscribe} throws an exception, the
+ * subscription is cancelled. Otherwise, if this SubmissionPublisher
+ * was closed exceptionally, then the subscriber's {@link
+ * Flow.Subscriber#onError onError} method is invoked with the
+ * corresponding exception, or if closed without exception, the
+ * subscriber's {@link Flow.Subscriber#onComplete() onComplete}
+ * method is invoked. Subscribers may enable receiving items by
+ * invoking the {@link Flow.Subscription#request(long) request}
+ * method of the new Subscription, and may unsubscribe by invoking
+ * its {@link Flow.Subscription#cancel() cancel} method.
+ *
+ * @param subscriber the subscriber
+ * @throws NullPointerException if subscriber is null
+ */
+ public void subscribe(Subscriber<? super T> subscriber) {
+ if (subscriber == null) throw new NullPointerException();
+ int max = maxBufferCapacity; // allocate initial array
+ Object[] array = new Object[max < INITIAL_CAPACITY ?
+ max : INITIAL_CAPACITY];
+ BufferedSubscription<T> subscription =
+ new BufferedSubscription<T>(subscriber, executor, onNextHandler,
+ array, max);
+ synchronized (this) {
+ if (!subscribed) {
+ subscribed = true;
+ owner = Thread.currentThread();
+ }
+ for (BufferedSubscription<T> b = clients, pred = null;;) {
+ if (b == null) {
+ Throwable ex;
+ subscription.onSubscribe();
+ if ((ex = closedException) != null)
+ subscription.onError(ex);
+ else if (closed)
+ subscription.onComplete();
+ else if (pred == null)
+ clients = subscription;
+ else
+ pred.next = subscription;
+ break;
+ }
+ BufferedSubscription<T> next = b.next;
+ if (b.isClosed()) { // remove
+ b.next = null; // detach
+ if (pred == null)
+ clients = next;
+ else
+ pred.next = next;
+ }
+ else if (subscriber.equals(b.subscriber)) {
+ b.onError(new IllegalStateException("Duplicate subscribe"));
+ break;
+ }
+ else
+ pred = b;
+ b = next;
+ }
+ }
+ }
+
+ /**
+ * Common implementation for all three forms of submit and offer.
+ * Acts as submit if nanos == Long.MAX_VALUE, else offer.
+ */
+ private int doOffer(T item, long nanos,
+ BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+ if (item == null) throw new NullPointerException();
+ int lag = 0;
+ boolean complete, unowned;
+ synchronized (this) {
+ Thread t = Thread.currentThread(), o;
+ BufferedSubscription<T> b = clients;
+ if ((unowned = ((o = owner) != t)) && o != null)
+ owner = null; // disable bias
+ if (b == null)
+ complete = closed;
+ else {
+ complete = false;
+ boolean cleanMe = false;
+ BufferedSubscription<T> retries = null, rtail = null, next;
+ do {
+ next = b.next;
+ int stat = b.offer(item, unowned);
+ if (stat == 0) { // saturated; add to retry list
+ b.nextRetry = null; // avoid garbage on exceptions
+ if (rtail == null)
+ retries = b;
+ else
+ rtail.nextRetry = b;
+ rtail = b;
+ }
+ else if (stat < 0) // closed
+ cleanMe = true; // remove later
+ else if (stat > lag)
+ lag = stat;
+ } while ((b = next) != null);
+
+ if (retries != null || cleanMe)
+ lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
+ }
+ }
+ if (complete)
+ throw new IllegalStateException("Closed");
+ else
+ return lag;
+ }
+
+ /**
+ * Helps, (timed) waits for, and/or drops buffers on list; returns
+ * lag or negative drops (for use in offer).
+ */
+ private int retryOffer(T item, long nanos,
+ BiPredicate<Subscriber<? super T>, ? super T> onDrop,
+ BufferedSubscription<T> retries, int lag,
+ boolean cleanMe) {
+ for (BufferedSubscription<T> r = retries; r != null;) {
+ BufferedSubscription<T> nextRetry = r.nextRetry;
+ r.nextRetry = null;
+ if (nanos > 0L)
+ r.awaitSpace(nanos);
+ int stat = r.retryOffer(item);
+ if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item))
+ stat = r.retryOffer(item);
+ if (stat == 0)
+ lag = (lag >= 0) ? -1 : lag - 1;
+ else if (stat < 0)
+ cleanMe = true;
+ else if (lag >= 0 && stat > lag)
+ lag = stat;
+ r = nextRetry;
+ }
+ if (cleanMe)
+ cleanAndCount();
+ return lag;
+ }
+
+ /**
+ * Returns current list count after removing closed subscribers.
+ * Call only while holding lock. Used mainly by retryOffer for
+ * cleanup.
+ */
+ private int cleanAndCount() {
+ int count = 0;
+ BufferedSubscription<T> pred = null, next;
+ for (BufferedSubscription<T> b = clients; b != null; b = next) {
+ next = b.next;
+ if (b.isClosed()) {
+ b.next = null;
+ if (pred == null)
+ clients = next;
+ else
+ pred.next = next;
+ }
+ else {
+ pred = b;
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Publishes the given item to each current subscriber by
+ * asynchronously invoking its {@link Flow.Subscriber#onNext(Object)
+ * onNext} method, blocking uninterruptibly while resources for any
+ * subscriber are unavailable. This method returns an estimate of
+ * the maximum lag (number of items submitted but not yet consumed)
+ * among all current subscribers. This value is at least one
+ * (accounting for this submitted item) if there are any
+ * subscribers, else zero.
+ *
+ * <p>If the Executor for this publisher throws a
+ * RejectedExecutionException (or any other RuntimeException or
+ * Error) when attempting to asynchronously notify subscribers,
+ * then this exception is rethrown, in which case not all
+ * subscribers will have been issued this item.
+ *
+ * @param item the (non-null) item to publish
+ * @return the estimated maximum lag among subscribers
+ * @throws IllegalStateException if closed
+ * @throws NullPointerException if item is null
+ * @throws RejectedExecutionException if thrown by Executor
+ */
+ public int submit(T item) {
+ return doOffer(item, Long.MAX_VALUE, null);
+ }
+
+ /**
+ * Publishes the given item, if possible, to each current subscriber
+ * by asynchronously invoking its {@link
+ * Flow.Subscriber#onNext(Object) onNext} method. The item may be
+ * dropped by one or more subscribers if resource limits are
+ * exceeded, in which case the given handler (if non-null) is
+ * invoked, and if it returns true, retried once. Other calls to
+ * methods in this class by other threads are blocked while the
+ * handler is invoked. Unless recovery is assured, options are
+ * usually limited to logging the error and/or issuing an {@link
+ * Flow.Subscriber#onError(Throwable) onError} signal to the
+ * subscriber.
+ *
+ * <p>This method returns a status indicator: If negative, it
+ * represents the (negative) number of drops (failed attempts to
+ * issue the item to a subscriber). Otherwise it is an estimate of
+ * the maximum lag (number of items submitted but not yet
+ * consumed) among all current subscribers. This value is at least
+ * one (accounting for this submitted item) if there are any
+ * subscribers, else zero.
+ *
+ * <p>If the Executor for this publisher throws a
+ * RejectedExecutionException (or any other RuntimeException or
+ * Error) when attempting to asynchronously notify subscribers, or
+ * the drop handler throws an exception when processing a dropped
+ * item, then this exception is rethrown.
+ *
+ * @param item the (non-null) item to publish
+ * @param onDrop if non-null, the handler invoked upon a drop to a
+ * subscriber, with arguments of the subscriber and item; if it
+ * returns true, an offer is re-attempted (once)
+ * @return if negative, the (negative) number of drops; otherwise
+ * an estimate of maximum lag
+ * @throws IllegalStateException if closed
+ * @throws NullPointerException if item is null
+ * @throws RejectedExecutionException if thrown by Executor
+ */
+ public int offer(T item,
+ BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+ return doOffer(item, 0L, onDrop);
+ }
+
+ /**
+ * Publishes the given item, if possible, to each current subscriber
+ * by asynchronously invoking its {@link
+ * Flow.Subscriber#onNext(Object) onNext} method, blocking while
+ * resources for any subscription are unavailable, up to the
+ * specified timeout or until the caller thread is interrupted, at
+ * which point the given handler (if non-null) is invoked, and if it
+ * returns true, retried once. (The drop handler may distinguish
+ * timeouts from interrupts by checking whether the current thread
+ * is interrupted.) Other calls to methods in this class by other
+ * threads are blocked while the handler is invoked. Unless
+ * recovery is assured, options are usually limited to logging the
+ * error and/or issuing an {@link Flow.Subscriber#onError(Throwable)
+ * onError} signal to the subscriber.
+ *
+ * <p>This method returns a status indicator: If negative, it
+ * represents the (negative) number of drops (failed attempts to
+ * issue the item to a subscriber). Otherwise it is an estimate of
+ * the maximum lag (number of items submitted but not yet
+ * consumed) among all current subscribers. This value is at least
+ * one (accounting for this submitted item) if there are any
+ * subscribers, else zero.
+ *
+ * <p>If the Executor for this publisher throws a
+ * RejectedExecutionException (or any other RuntimeException or
+ * Error) when attempting to asynchronously notify subscribers, or
+ * the drop handler throws an exception when processing a dropped
+ * item, then this exception is rethrown.
+ *
+ * @param item the (non-null) item to publish
+ * @param timeout how long to wait for resources for any subscriber
+ * before giving up, in units of {@code unit}
+ * @param unit a {@code TimeUnit} determining how to interpret the
+ * {@code timeout} parameter
+ * @param onDrop if non-null, the handler invoked upon a drop to a
+ * subscriber, with arguments of the subscriber and item; if it
+ * returns true, an offer is re-attempted (once)
+ * @return if negative, the (negative) number of drops; otherwise
+ * an estimate of maximum lag
+ * @throws IllegalStateException if closed
+ * @throws NullPointerException if item is null
+ * @throws RejectedExecutionException if thrown by Executor
+ */
+ public int offer(T item, long timeout, TimeUnit unit,
+ BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+ long nanos = unit.toNanos(timeout);
+ // distinguishes from untimed (only wrt interrupt policy)
+ if (nanos == Long.MAX_VALUE) --nanos;
+ return doOffer(item, nanos, onDrop);
+ }
+
+ /**
+ * Unless already closed, issues {@link
+ * Flow.Subscriber#onComplete() onComplete} signals to current
+ * subscribers, and disallows subsequent attempts to publish.
+ * Upon return, this method does <em>NOT</em> guarantee that all
+ * subscribers have yet completed.
+ */
+ public void close() {
+ if (!closed) {
+ BufferedSubscription<T> b;
+ synchronized (this) {
+ // no need to re-check closed here
+ b = clients;
+ clients = null;
+ owner = null;
+ closed = true;
+ }
+ while (b != null) {
+ BufferedSubscription<T> next = b.next;
+ b.next = null;
+ b.onComplete();
+ b = next;
+ }
+ }
+ }
+
+ /**
+ * Unless already closed, issues {@link
+ * Flow.Subscriber#onError(Throwable) onError} signals to current
+ * subscribers with the given error, and disallows subsequent
+ * attempts to publish. Future subscribers also receive the given
+ * error. Upon return, this method does <em>NOT</em> guarantee
+ * that all subscribers have yet completed.
+ *
+ * @param error the {@code onError} argument sent to subscribers
+ * @throws NullPointerException if error is null
+ */
+ public void closeExceptionally(Throwable error) {
+ if (error == null)
+ throw new NullPointerException();
+ if (!closed) {
+ BufferedSubscription<T> b;
+ synchronized (this) {
+ b = clients;
+ if (!closed) { // don't clobber racing close
+ closedException = error;
+ clients = null;
+ owner = null;
+ closed = true;
+ }
+ }
+ while (b != null) {
+ BufferedSubscription<T> next = b.next;
+ b.next = null;
+ b.onError(error);
+ b = next;
+ }
+ }
+ }
+
+ /**
+ * Returns true if this publisher is not accepting submissions.
+ *
+ * @return true if closed
+ */
+ public boolean isClosed() {
+ return closed;
+ }
+
+ /**
+ * Returns the exception associated with {@link
+ * #closeExceptionally(Throwable) closeExceptionally}, or null if
+ * not closed or if closed normally.
+ *
+ * @return the exception, or null if none
+ */
+ public Throwable getClosedException() {
+ return closedException;
+ }
+
+ /**
+ * Returns true if this publisher has any subscribers.
+ *
+ * @return true if this publisher has any subscribers
+ */
+ public boolean hasSubscribers() {
+ boolean nonEmpty = false;
+ synchronized (this) {
+ for (BufferedSubscription<T> b = clients; b != null;) {
+ BufferedSubscription<T> next = b.next;
+ if (b.isClosed()) {
+ b.next = null;
+ b = clients = next;
+ }
+ else {
+ nonEmpty = true;
+ break;
+ }
+ }
+ }
+ return nonEmpty;
+ }
+
+ /**
+ * Returns the number of current subscribers.
+ *
+ * @return the number of current subscribers
+ */
+ public int getNumberOfSubscribers() {
+ synchronized (this) {
+ return cleanAndCount();
+ }
+ }
+
+ /**
+ * Returns the Executor used for asynchronous delivery.
+ *
+ * @return the Executor used for asynchronous delivery
+ */
+ public Executor getExecutor() {
+ return executor;
+ }
+
+ /**
+ * Returns the maximum per-subscriber buffer capacity.
+ *
+ * @return the maximum per-subscriber buffer capacity
+ */
+ public int getMaxBufferCapacity() {
+ return maxBufferCapacity;
+ }
+
+ /**
+ * Returns a list of current subscribers for monitoring and
+ * tracking purposes, not for invoking {@link Flow.Subscriber}
+ * methods on the subscribers.
+ *
+ * @return list of current subscribers
+ */
+ public List<Subscriber<? super T>> getSubscribers() {
+ ArrayList<Subscriber<? super T>> subs = new ArrayList<>();
+ synchronized (this) {
+ BufferedSubscription<T> pred = null, next;
+ for (BufferedSubscription<T> b = clients; b != null; b = next) {
+ next = b.next;
+ if (b.isClosed()) {
+ b.next = null;
+ if (pred == null)
+ clients = next;
+ else
+ pred.next = next;
+ }
+ else {
+ subs.add(b.subscriber);
+ pred = b;
+ }
+ }
+ }
+ return subs;
+ }
+
+ /**
+ * Returns true if the given Subscriber is currently subscribed.
+ *
+ * @param subscriber the subscriber
+ * @return true if currently subscribed
+ * @throws NullPointerException if subscriber is null
+ */
+ public boolean isSubscribed(Subscriber<? super T> subscriber) {
+ if (subscriber == null) throw new NullPointerException();
+ if (!closed) {
+ synchronized (this) {
+ BufferedSubscription<T> pred = null, next;
+ for (BufferedSubscription<T> b = clients; b != null; b = next) {
+ next = b.next;
+ if (b.isClosed()) {
+ b.next = null;
+ if (pred == null)
+ clients = next;
+ else
+ pred.next = next;
+ }
+ else if (subscriber.equals(b.subscriber))
+ return true;
+ else
+ pred = b;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an estimate of the minimum number of items requested
+ * (via {@link Flow.Subscription#request(long) request}) but not
+ * yet produced, among all current subscribers.
+ *
+ * @return the estimate, or zero if no subscribers
+ */
+ public long estimateMinimumDemand() {
+ long min = Long.MAX_VALUE;
+ boolean nonEmpty = false;
+ synchronized (this) {
+ BufferedSubscription<T> pred = null, next;
+ for (BufferedSubscription<T> b = clients; b != null; b = next) {
+ int n; long d;
+ next = b.next;
+ if ((n = b.estimateLag()) < 0) {
+ b.next = null;
+ if (pred == null)
+ clients = next;
+ else
+ pred.next = next;
+ }
+ else {
+ if ((d = b.demand - n) < min)
+ min = d;
+ nonEmpty = true;
+ pred = b;
+ }
+ }
+ }
+ return nonEmpty ? min : 0;
+ }
+
+ /**
+ * Returns an estimate of the maximum number of items produced but
+ * not yet consumed among all current subscribers.
+ *
+ * @return the estimate
+ */
+ public int estimateMaximumLag() {
+ int max = 0;
+ synchronized (this) {
+ BufferedSubscription<T> pred = null, next;
+ for (BufferedSubscription<T> b = clients; b != null; b = next) {
+ int n;
+ next = b.next;
+ if ((n = b.estimateLag()) < 0) {
+ b.next = null;
+ if (pred == null)
+ clients = next;
+ else
+ pred.next = next;
+ }
+ else {
+ if (n > max)
+ max = n;
+ pred = b;
+ }
+ }
+ }
+ return max;
+ }
+
+ /**
+ * Processes all published items using the given Consumer function.
+ * Returns a CompletableFuture that is completed normally when this
+ * publisher signals {@link Flow.Subscriber#onComplete()
+ * onComplete}, or completed exceptionally upon any error, or an
+ * exception is thrown by the Consumer, or the returned
+ * CompletableFuture is cancelled, in which case no further items
+ * are processed.
+ *
+ * @param consumer the function applied to each onNext item
+ * @return a CompletableFuture that is completed normally
+ * when the publisher signals onComplete, and exceptionally
+ * upon any error or cancellation
+ * @throws NullPointerException if consumer is null
+ */
+ public CompletableFuture<Void> consume(Consumer<? super T> consumer) {
+ if (consumer == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> status = new CompletableFuture<>();
+ subscribe(new ConsumerSubscriber<T>(status, consumer));
+ return status;
+ }
+
+ /** Subscriber for method consume */
+ static final class ConsumerSubscriber<T> implements Subscriber<T> {
+ final CompletableFuture<Void> status;
+ final Consumer<? super T> consumer;
+ Subscription subscription;
+ ConsumerSubscriber(CompletableFuture<Void> status,
+ Consumer<? super T> consumer) {
+ this.status = status; this.consumer = consumer;
+ }
+ public final void onSubscribe(Subscription subscription) {
+ this.subscription = subscription;
+ status.whenComplete((v, e) -> subscription.cancel());
+ if (!status.isDone())
+ subscription.request(Long.MAX_VALUE);
+ }
+ public final void onError(Throwable ex) {
+ status.completeExceptionally(ex);
+ }
+ public final void onComplete() {
+ status.complete(null);
+ }
+ public final void onNext(T item) {
+ try {
+ consumer.accept(item);
+ } catch (Throwable ex) {
+ subscription.cancel();
+ status.completeExceptionally(ex);
+ }
+ }
+ }
+
+ /**
+ * A task for consuming buffer items and signals, created and
+ * executed whenever they become available. A task consumes as
+ * many items/signals as possible before terminating, at which
+ * point another task is created when needed. The dual Runnable
+ * and ForkJoinTask declaration saves overhead when executed by
+ * ForkJoinPools, without impacting other kinds of Executors.
+ */
+ @SuppressWarnings("serial")
+ static final class ConsumerTask<T> extends ForkJoinTask<Void>
+ implements Runnable, CompletableFuture.AsynchronousCompletionTask {
+ final BufferedSubscription<T> consumer;
+ ConsumerTask(BufferedSubscription<T> consumer) {
+ this.consumer = consumer;
+ }
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ public final boolean exec() { consumer.consume(); return false; }
+ public final void run() { consumer.consume(); }
+ }
+
+ /**
+ * A resizable array-based ring buffer with integrated control to
+ * start a consumer task whenever items are available. The buffer
+ * algorithm is specialized for the case of at most one concurrent
+ * producer and consumer, and power of two buffer sizes. It relies
+ * primarily on atomic operations (CAS or getAndSet) at the next
+ * array slot to put or take an element, at the "tail" and "head"
+ * indices written only by the producer and consumer respectively.
+ *
+ * We ensure internally that there is at most one active consumer
+ * task at any given time. The publisher guarantees a single
+ * producer via its lock. Sync among producers and consumers
+ * relies on volatile fields "ctl", "demand", and "waiting" (along
+ * with element access). Other variables are accessed in plain
+ * mode, relying on outer ordering and exclusion, and/or enclosing
+ * them within other volatile accesses. Some atomic operations are
+ * avoided by tracking single threaded ownership by producers (in
+ * the style of biased locking).
+ *
+ * Execution control and protocol state are managed using field
+ * "ctl". Methods to subscribe, close, request, and cancel set
+ * ctl bits (mostly using atomic boolean method getAndBitwiseOr),
+ * and ensure that a task is running. (The corresponding consumer
+ * side actions are in method consume.) To avoid starting a new
+ * task on each action, ctl also includes a keep-alive bit
+ * (ACTIVE) that is refreshed if needed on producer actions.
+ * (Maintaining agreement about keep-alives requires most atomic
+ * updates to be full SC/Volatile strength, which is still much
+ * cheaper than using one task per item.) Error signals
+ * additionally null out items and/or fields to reduce termination
+ * latency. The cancel() method is supported by treating as ERROR
+ * but suppressing onError signal.
+ *
+ * Support for blocking also exploits the fact that there is only
+ * one possible waiter. ManagedBlocker-compatible control fields
+ * are placed in this class itself rather than in wait-nodes.
+ * Blocking control relies on the "waiting" and "waiter"
+ * fields. Producers set them before trying to block. Signalling
+ * unparks and clears fields. If the producer and/or consumer are
+ * using a ForkJoinPool, the producer attempts to help run
+ * consumer tasks via ForkJoinPool.helpAsyncBlocker before
+ * blocking.
+ *
+ * Usages of this class may encounter any of several forms of
+ * memory contention. We try to ameliorate across them without
+ * unduly impacting footprints in low-contention usages where it
+ * isn't needed. Buffer arrays start out small and grow only as
+ * needed. The class uses @Contended and heuristic field
+ * declaration ordering to reduce false-sharing memory contention
+ * across instances of BufferedSubscription (as in, multiple
+ * subscribers per publisher). We additionally segregate some
+ * fields that would otherwise nearly always encounter cache line
+ * contention among producers and consumers. To reduce contention
+ * across time (vs space), consumers only periodically update
+ * other fields (see method takeItems), at the expense of possibly
+ * staler reporting of lags and demand (bounded at 12.5% == 1/8
+ * capacity) and possibly more atomic operations.
+ *
+ * Other forms of imbalance and slowdowns can occur during startup
+ * when producer and consumer methods are compiled and/or memory
+ * is allocated at different rates. This is ameliorated by
+ * artificially subdividing some consumer methods, including
+ * isolation of all subscriber callbacks. This code also includes
+ * typical power-of-two array screening idioms to avoid compilers
+ * generating traps, along with the usual SSA-based inline
+ * assignment coding style. Also, all methods and fields have
+ * default visibility to simplify usage by callers.
+ */
+ @SuppressWarnings("serial")
+ @jdk.internal.vm.annotation.Contended
+ static final class BufferedSubscription<T>
+ implements Subscription, ForkJoinPool.ManagedBlocker {
+ long timeout; // Long.MAX_VALUE if untimed wait
+ int head; // next position to take
+ int tail; // next position to put
+ final int maxCapacity; // max buffer size
+ volatile int ctl; // atomic run state flags
+ Object[] array; // buffer
+ final Subscriber<? super T> subscriber;
+ final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+ Executor executor; // null on error
+ Thread waiter; // blocked producer thread
+ Throwable pendingError; // holds until onError issued
+ BufferedSubscription<T> next; // used only by publisher
+ BufferedSubscription<T> nextRetry; // used only by publisher
+
+ @jdk.internal.vm.annotation.Contended("c") // segregate
+ volatile long demand; // # unfilled requests
+ @jdk.internal.vm.annotation.Contended("c")
+ volatile int waiting; // nonzero if producer blocked
+
+ // ctl bit values
+ static final int CLOSED = 0x01; // if set, other bits ignored
+ static final int ACTIVE = 0x02; // keep-alive for consumer task
+ static final int REQS = 0x04; // (possibly) nonzero demand
+ static final int ERROR = 0x08; // issues onError when noticed
+ static final int COMPLETE = 0x10; // issues onComplete when done
+ static final int RUN = 0x20; // task is or will be running
+ static final int OPEN = 0x40; // true after subscribe
+
+ static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel
+
+ BufferedSubscription(Subscriber<? super T> subscriber,
+ Executor executor,
+ BiConsumer<? super Subscriber<? super T>,
+ ? super Throwable> onNextHandler,
+ Object[] array,
+ int maxBufferCapacity) {
+ this.subscriber = subscriber;
+ this.executor = executor;
+ this.onNextHandler = onNextHandler;
+ this.array = array;
+ this.maxCapacity = maxBufferCapacity;
+ }
+
+ // Wrappers for some VarHandle methods
+
+ final boolean weakCasCtl(int cmp, int val) {
+ return CTL.weakCompareAndSet(this, cmp, val);
+ }
+
+ final int getAndBitwiseOrCtl(int bits) {
+ return (int)CTL.getAndBitwiseOr(this, bits);
+ }
+
+ final long subtractDemand(int k) {
+ long n = (long)(-k);
+ return n + (long)DEMAND.getAndAdd(this, n);
+ }
+
+ final boolean casDemand(long cmp, long val) {
+ return DEMAND.compareAndSet(this, cmp, val);
+ }
+
+ // Utilities used by SubmissionPublisher
+
+ /**
+ * Returns true if closed (consumer task may still be running).
+ */
+ final boolean isClosed() {
+ return (ctl & CLOSED) != 0;
+ }
+
+ /**
+ * Returns estimated number of buffered items, or negative if
+ * closed.
+ */
+ final int estimateLag() {
+ int c = ctl, n = tail - head;
+ return ((c & CLOSED) != 0) ? -1 : (n < 0) ? 0 : n;
+ }
+
+ // Methods for submitting items
+
+ /**
+ * Tries to add item and start consumer task if necessary.
+ * @return negative if closed, 0 if saturated, else estimated lag
+ */
+ final int offer(T item, boolean unowned) {
+ Object[] a;
+ int stat = 0, cap = ((a = array) == null) ? 0 : a.length;
+ int t = tail, i = t & (cap - 1), n = t + 1 - head;
+ if (cap > 0) {
+ boolean added;
+ if (n >= cap && cap < maxCapacity) // resize
+ added = growAndOffer(item, a, t);
+ else if (n >= cap || unowned) // need volatile CAS
+ added = QA.compareAndSet(a, i, null, item);
+ else { // can use release mode
+ QA.setRelease(a, i, item);
+ added = true;
+ }
+ if (added) {
+ tail = t + 1;
+ stat = n;
+ }
+ }
+ return startOnOffer(stat);
+ }
+
+ /**
+ * Tries to expand buffer and add item, returning true on
+ * success. Currently fails only if out of memory.
+ */
+ final boolean growAndOffer(T item, Object[] a, int t) {
+ int cap = 0, newCap = 0;
+ Object[] newArray = null;
+ if (a != null && (cap = a.length) > 0 && (newCap = cap << 1) > 0) {
+ try {
+ newArray = new Object[newCap];
+ } catch (OutOfMemoryError ex) {
+ }
+ }
+ if (newArray == null)
+ return false;
+ else { // take and move items
+ int newMask = newCap - 1;
+ newArray[t-- & newMask] = item;
+ for (int mask = cap - 1, k = mask; k >= 0; --k) {
+ Object x = QA.getAndSet(a, t & mask, null);
+ if (x == null)
+ break; // already consumed
+ else
+ newArray[t-- & newMask] = x;
+ }
+ array = newArray;
+ VarHandle.releaseFence(); // release array and slots
+ return true;
+ }
+ }
+
+ /**
+ * Version of offer for retries (no resize or bias)
+ */
+ final int retryOffer(T item) {
+ Object[] a;
+ int stat = 0, t = tail, h = head, cap;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ QA.compareAndSet(a, (cap - 1) & t, null, item))
+ stat = (tail = t + 1) - h;
+ return startOnOffer(stat);
+ }
+
+ /**
+ * Tries to start consumer task after offer.
+ * @return negative if now closed, else argument
+ */
+ final int startOnOffer(int stat) {
+ int c; // start or keep alive if requests exist and not active
+ if (((c = ctl) & (REQS | ACTIVE)) == REQS &&
+ ((c = getAndBitwiseOrCtl(RUN | ACTIVE)) & (RUN | CLOSED)) == 0)
+ tryStart();
+ else if ((c & CLOSED) != 0)
+ stat = -1;
+ return stat;
+ }
+
+ /**
+ * Tries to start consumer task. Sets error state on failure.
+ */
+ final void tryStart() {
+ try {
+ Executor e;
+ ConsumerTask<T> task = new ConsumerTask<T>(this);
+ if ((e = executor) != null) // skip if disabled on error
+ e.execute(task);
+ } catch (RuntimeException | Error ex) {
+ getAndBitwiseOrCtl(ERROR | CLOSED);
+ throw ex;
+ }
+ }
+
+ // Signals to consumer tasks
+
+ /**
+ * Sets the given control bits, starting task if not running or closed.
+ * @param bits state bits, assumed to include RUN but not CLOSED
+ */
+ final void startOnSignal(int bits) {
+ if ((ctl & bits) != bits &&
+ (getAndBitwiseOrCtl(bits) & (RUN | CLOSED)) == 0)
+ tryStart();
+ }
+
+ final void onSubscribe() {
+ startOnSignal(RUN | ACTIVE);
+ }
+
+ final void onComplete() {
+ startOnSignal(RUN | ACTIVE | COMPLETE);
+ }
+
+ final void onError(Throwable ex) {
+ int c; Object[] a; // to null out buffer on async error
+ if (ex != null)
+ pendingError = ex; // races are OK
+ if (((c = getAndBitwiseOrCtl(ERROR | RUN | ACTIVE)) & CLOSED) == 0) {
+ if ((c & RUN) == 0)
+ tryStart();
+ else if ((a = array) != null)
+ Arrays.fill(a, null);
+ }
+ }
+
+ public final void cancel() {
+ onError(null);
+ }
+
+ public final void request(long n) {
+ if (n > 0L) {
+ for (;;) {
+ long p = demand, d = p + n; // saturate
+ if (casDemand(p, d < p ? Long.MAX_VALUE : d))
+ break;
+ }
+ startOnSignal(RUN | ACTIVE | REQS);
+ }
+ else
+ onError(new IllegalArgumentException(
+ "non-positive subscription request"));
+ }
+
+ // Consumer task actions
+
+ /**
+ * Consumer loop, called from ConsumerTask, or indirectly when
+ * helping during submit.
+ */
+ final void consume() {
+ Subscriber<? super T> s;
+ if ((s = subscriber) != null) { // hoist checks
+ subscribeOnOpen(s);
+ long d = demand;
+ for (int h = head, t = tail;;) {
+ int c, taken; boolean empty;
+ if (((c = ctl) & ERROR) != 0) {
+ closeOnError(s, null);
+ break;
+ }
+ else if ((taken = takeItems(s, d, h)) > 0) {
+ head = h += taken;
+ d = subtractDemand(taken);
+ }
+ else if ((d = demand) == 0L && (c & REQS) != 0)
+ weakCasCtl(c, c & ~REQS); // exhausted demand
+ else if (d != 0L && (c & REQS) == 0)
+ weakCasCtl(c, c | REQS); // new demand
+ else if (t == (t = tail)) { // stability check
+ if ((empty = (t == h)) && (c & COMPLETE) != 0) {
+ closeOnComplete(s); // end of stream
+ break;
+ }
+ else if (empty || d == 0L) {
+ int bit = ((c & ACTIVE) != 0) ? ACTIVE : RUN;
+ if (weakCasCtl(c, c & ~bit) && bit == RUN)
+ break; // un-keep-alive or exit
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Consumes some items until unavailable or bound or error.
+ *
+ * @param s subscriber
+ * @param d current demand
+ * @param h current head
+ * @return number taken
+ */
+ final int takeItems(Subscriber<? super T> s, long d, int h) {
+ Object[] a;
+ int k = 0, cap;
+ if ((a = array) != null && (cap = a.length) > 0) {
+ int m = cap - 1, b = (m >>> 3) + 1; // min(1, cap/8)
+ int n = (d < (long)b) ? (int)d : b;
+ for (; k < n; ++h, ++k) {
+ Object x = QA.getAndSet(a, h & m, null);
+ if (waiting != 0)
+ signalWaiter();
+ if (x == null)
+ break;
+ else if (!consumeNext(s, x))
+ break;
+ }
+ }
+ return k;
+ }
+
+ final boolean consumeNext(Subscriber<? super T> s, Object x) {
+ try {
+ @SuppressWarnings("unchecked") T y = (T) x;
+ if (s != null)
+ s.onNext(y);
+ return true;
+ } catch (Throwable ex) {
+ handleOnNext(s, ex);
+ return false;
+ }
+ }
+
+ /**
+ * Processes exception in Subscriber.onNext.
+ */
+ final void handleOnNext(Subscriber<? super T> s, Throwable ex) {
+ BiConsumer<? super Subscriber<? super T>, ? super Throwable> h;
+ try {
+ if ((h = onNextHandler) != null)
+ h.accept(s, ex);
+ } catch (Throwable ignore) {
+ }
+ closeOnError(s, ex);
+ }
+
+ /**
+ * Issues subscriber.onSubscribe if this is first signal.
+ */
+ final void subscribeOnOpen(Subscriber<? super T> s) {
+ if ((ctl & OPEN) == 0 && (getAndBitwiseOrCtl(OPEN) & OPEN) == 0)
+ consumeSubscribe(s);
+ }
+
+ final void consumeSubscribe(Subscriber<? super T> s) {
+ try {
+ if (s != null) // ignore if disabled
+ s.onSubscribe(this);
+ } catch (Throwable ex) {
+ closeOnError(s, ex);
+ }
+ }
+
+ /**
+ * Issues subscriber.onComplete unless already closed.
+ */
+ final void closeOnComplete(Subscriber<? super T> s) {
+ if ((getAndBitwiseOrCtl(CLOSED) & CLOSED) == 0)
+ consumeComplete(s);
+ }
+
+ final void consumeComplete(Subscriber<? super T> s) {
+ try {
+ if (s != null)
+ s.onComplete();
+ } catch (Throwable ignore) {
+ }
+ }
+
+ /**
+ * Issues subscriber.onError, and unblocks producer if needed.
+ */
+ final void closeOnError(Subscriber<? super T> s, Throwable ex) {
+ if ((getAndBitwiseOrCtl(ERROR | CLOSED) & CLOSED) == 0) {
+ if (ex == null)
+ ex = pendingError;
+ pendingError = null; // detach
+ executor = null; // suppress racing start calls
+ signalWaiter();
+ consumeError(s, ex);
+ }
+ }
+
+ final void consumeError(Subscriber<? super T> s, Throwable ex) {
+ try {
+ if (ex != null && s != null)
+ s.onError(ex);
+ } catch (Throwable ignore) {
+ }
+ }
+
+ // Blocking support
+
+ /**
+ * Unblocks waiting producer.
+ */
+ final void signalWaiter() {
+ Thread w;
+ waiting = 0;
+ if ((w = waiter) != null)
+ LockSupport.unpark(w);
+ }
+
+ /**
+ * Returns true if closed or space available.
+ * For ManagedBlocker.
+ */
+ public final boolean isReleasable() {
+ Object[] a; int cap;
+ return ((ctl & CLOSED) != 0 ||
+ ((a = array) != null && (cap = a.length) > 0 &&
+ QA.getAcquire(a, (cap - 1) & tail) == null));
+ }
+
+ /**
+ * Helps or blocks until timeout, closed, or space available.
+ */
+ final void awaitSpace(long nanos) {
+ if (!isReleasable()) {
+ ForkJoinPool.helpAsyncBlocker(executor, this);
+ if (!isReleasable()) {
+ timeout = nanos;
+ try {
+ ForkJoinPool.managedBlock(this);
+ } catch (InterruptedException ie) {
+ timeout = INTERRUPTED;
+ }
+ if (timeout == INTERRUPTED)
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Blocks until closed, space available or timeout.
+ * For ManagedBlocker.
+ */
+ public final boolean block() {
+ long nanos = timeout;
+ boolean timed = (nanos < Long.MAX_VALUE);
+ long deadline = timed ? System.nanoTime() + nanos : 0L;
+ while (!isReleasable()) {
+ if (Thread.interrupted()) {
+ timeout = INTERRUPTED;
+ if (timed)
+ break;
+ }
+ else if (timed && (nanos = deadline - System.nanoTime()) <= 0L)
+ break;
+ else if (waiter == null)
+ waiter = Thread.currentThread();
+ else if (waiting == 0)
+ waiting = 1;
+ else if (timed)
+ LockSupport.parkNanos(this, nanos);
+ else
+ LockSupport.park(this);
+ }
+ waiter = null;
+ waiting = 0;
+ return true;
+ }
+
+ // VarHandle mechanics
+ static final VarHandle CTL;
+ static final VarHandle DEMAND;
+ static final VarHandle QA;
+
+ static {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
+ int.class);
+ DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
+ long.class);
+ QA = MethodHandles.arrayElementVarHandle(Object[].class);
+ } catch (ReflectiveOperationException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
+ }
+ }
+}
diff --git a/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java b/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
index 9655205..d15c3b5 100644
--- a/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -36,19 +36,18 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
/**
* A {@linkplain BlockingQueue blocking queue} in which each insert
* operation must wait for a corresponding remove operation by another
@@ -77,9 +76,12 @@
* is not guaranteed. However, a queue constructed with fairness set
* to {@code true} grants threads access in FIFO order.
*
- * <p>This class and its iterator implement all of the
- * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
*
* @since 1.5
* @author Doug Lea and Bill Scherer and Michael Scott
@@ -247,7 +249,7 @@
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ SNEXT.compareAndSet(this, cmp, val);
}
/**
@@ -260,7 +262,7 @@
*/
boolean tryMatch(SNode s) {
if (match == null &&
- U.compareAndSwapObject(this, MATCH, null, s)) {
+ SMATCH.compareAndSet(this, null, s)) {
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
@@ -275,26 +277,23 @@
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
- U.compareAndSwapObject(this, MATCH, null, this);
+ SMATCH.compareAndSet(this, null, this);
}
boolean isCancelled() {
return match == this;
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long MATCH;
- private static final long NEXT;
-
+ // VarHandle mechanics
+ private static final VarHandle SMATCH;
+ private static final VarHandle SNEXT;
static {
try {
- MATCH = U.objectFieldOffset
- (SNode.class.getDeclaredField("match"));
- NEXT = U.objectFieldOffset
- (SNode.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
+ SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -304,7 +303,7 @@
boolean casHead(SNode h, SNode nh) {
return h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh);
+ SHEAD.compareAndSet(this, h, nh);
}
/**
@@ -451,8 +450,11 @@
continue;
}
}
- if (spins > 0)
+ if (spins > 0) {
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // Thread.onSpinWait();
spins = shouldSpin(s) ? (spins - 1) : 0;
+ }
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
@@ -508,15 +510,14 @@
}
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
+ // VarHandle mechanics
+ private static final VarHandle SHEAD;
static {
try {
- HEAD = U.objectFieldOffset
- (TransferStack.class.getDeclaredField("head"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -546,19 +547,19 @@
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ QNEXT.compareAndSet(this, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
- U.compareAndSwapObject(this, ITEM, cmp, val);
+ QITEM.compareAndSet(this, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
- U.compareAndSwapObject(this, ITEM, cmp, this);
+ QITEM.compareAndSet(this, cmp, this);
}
boolean isCancelled() {
@@ -574,19 +575,16 @@
return next == this;
}
- // Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long ITEM;
- private static final long NEXT;
-
+ // VarHandle mechanics
+ private static final VarHandle QITEM;
+ private static final VarHandle QNEXT;
static {
try {
- ITEM = U.objectFieldOffset
- (QNode.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (QNode.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ QITEM = l.findVarHandle(QNode.class, "item", Object.class);
+ QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -614,7 +612,7 @@
*/
void advanceHead(QNode h, QNode nh) {
if (h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh))
+ QHEAD.compareAndSet(this, h, nh))
h.next = h; // forget old next
}
@@ -623,7 +621,7 @@
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
- U.compareAndSwapObject(this, TAIL, t, nt);
+ QTAIL.compareAndSet(this, t, nt);
}
/**
@@ -631,7 +629,7 @@
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
- U.compareAndSwapObject(this, CLEANME, cmp, val);
+ QCLEANME.compareAndSet(this, cmp, val);
}
/**
@@ -752,8 +750,11 @@
continue;
}
}
- if (spins > 0)
+ if (spins > 0) {
--spins;
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // Thread.onSpinWait();
+ }
else if (s.waiter == null)
s.waiter = w;
else if (!timed)
@@ -817,20 +818,21 @@
}
}
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
- private static final long CLEANME;
+ // VarHandle mechanics
+ private static final VarHandle QHEAD;
+ private static final VarHandle QTAIL;
+ private static final VarHandle QCLEANME;
static {
try {
- HEAD = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("tail"));
- CLEANME = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("cleanMe"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ QHEAD = l.findVarHandle(TransferQueue.class, "head",
+ QNode.class);
+ QTAIL = l.findVarHandle(TransferQueue.class, "tail",
+ QNode.class);
+ QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
+ QNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -1066,7 +1068,7 @@
/**
* Returns an empty spliterator in which calls to
- * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+ * {@link Spliterator#trySplit() trySplit} always return {@code null}.
*
* @return an empty spliterator
* @since 1.8
@@ -1112,15 +1114,12 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
int n = 0;
- for (E e; (e = poll()) != null;) {
+ for (E e; (e = poll()) != null; n++)
c.add(e);
- ++n;
- }
return n;
}
@@ -1131,15 +1130,12 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- if (c == null)
- throw new NullPointerException();
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
int n = 0;
- for (E e; n < maxElements && (e = poll()) != null;) {
+ for (E e; n < maxElements && (e = poll()) != null; n++)
c.add(e);
- ++n;
- }
return n;
}
diff --git a/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index 195f8ac..c20d2b3 100644
--- a/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -36,6 +36,7 @@
package java.util.concurrent;
import java.io.ObjectStreamField;
+import java.security.AccessControlContext;
import java.util.Random;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
@@ -47,6 +48,8 @@
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.StreamSupport;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.misc.VM;
/**
* A random number generator isolated to the current thread. Like the
@@ -64,7 +67,7 @@
* {@code ThreadLocalRandom.current().nextX(...)} (where
* {@code X} is {@code Int}, {@code Long}, etc).
* When all usages are of this form, it is never possible to
- * accidently share a {@code ThreadLocalRandom} across multiple threads.
+ * accidentally share a {@code ThreadLocalRandom} across multiple threads.
*
* <p>This class also provides additional commonly used bounded random
* generation methods.
@@ -95,7 +98,9 @@
* ThreadLocalRandom sequence. The dual use is a marriage of
* convenience, but is a simple and efficient way of reducing
* application-level overhead and footprint of most concurrent
- * programs.
+ * programs. Even more opportunistically, we also define here
+ * other package-private utilities that access Thread class
+ * fields.
*
* Even though this class subclasses java.util.Random, it uses the
* same basic algorithm as java.util.SplittableRandom. (See its
@@ -193,9 +198,17 @@
return r;
}
- // We must define this, but never use it.
+ /**
+ * Generates a pseudorandom number with the indicated number of
+ * low-order bits. Because this class has no subclasses, this
+ * method cannot be invoked or overridden.
+ *
+ * @param bits random bits
+ * @return the next pseudorandom value from this random number
+ * generator's sequence
+ */
protected int next(int bits) {
- return (int)(mix64(nextSeed()) >>> (64 - bits));
+ return nextInt() >>> (32 - bits);
}
/**
@@ -455,7 +468,7 @@
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
- nextLocalGaussian.set(new Double(v2 * multiplier));
+ nextLocalGaussian.set(Double.valueOf(v2 * multiplier));
return v1 * multiplier;
}
@@ -687,8 +700,7 @@
* @return a stream of pseudorandom {@code double} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
- * less than zero
- * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * less than zero, or {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
@@ -958,6 +970,21 @@
return r;
}
+ // Support for other package-private ThreadLocal access
+
+ /**
+ * Erases ThreadLocals by nulling out Thread maps.
+ */
+ static final void eraseThreadLocals(Thread thread) {
+ U.putObject(thread, THREADLOCALS, null);
+ U.putObject(thread, INHERITABLETHREADLOCALS, null);
+ }
+
+ static final void setInheritedAccessControlContext(Thread thread,
+ AccessControlContext acc) {
+ U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
+ }
+
// Serialization support
private static final long serialVersionUID = -5851777807851030925L;
@@ -1012,7 +1039,10 @@
*/
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
- // Constants from SplittableRandom
+ /**
+ * The least non-zero value returned by nextDouble(). This value
+ * is scaled by a random value of 53 bits to produce a result.
+ */
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24)
@@ -1022,22 +1052,19 @@
static final String BAD_SIZE = "size must be non-negative";
// Unsafe mechanics
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long SEED;
- private static final long PROBE;
- private static final long SECONDARY;
- static {
- try {
- SEED = U.objectFieldOffset
- (Thread.class.getDeclaredField("threadLocalRandomSeed"));
- PROBE = U.objectFieldOffset
- (Thread.class.getDeclaredField("threadLocalRandomProbe"));
- SECONDARY = U.objectFieldOffset
- (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
+ private static final Unsafe U = Unsafe.getUnsafe();
+ private static final long SEED = U.objectFieldOffset
+ (Thread.class, "threadLocalRandomSeed");
+ private static final long PROBE = U.objectFieldOffset
+ (Thread.class, "threadLocalRandomProbe");
+ private static final long SECONDARY = U.objectFieldOffset
+ (Thread.class, "threadLocalRandomSecondarySeed");
+ private static final long THREADLOCALS = U.objectFieldOffset
+ (Thread.class, "threadLocals");
+ private static final long INHERITABLETHREADLOCALS = U.objectFieldOffset
+ (Thread.class, "inheritableThreadLocals");
+ private static final long INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+ (Thread.class, "inheritedAccessControlContext");
/** Rarely-used holder for the second of a pair of Gaussians */
private static final ThreadLocal<Double> nextLocalGaussian =
@@ -1058,11 +1085,8 @@
// at end of <clinit> to survive static initialization circularity
static {
- if (java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Boolean>() {
- public Boolean run() {
- return Boolean.getBoolean("java.util.secureRandomSeed");
- }})) {
+ String sec = VM.getSavedProperty("java.util.secureRandomSeed");
+ if (Boolean.parseBoolean(sec)) {
byte[] seedBytes = java.security.SecureRandom.getSeed(8);
long s = (long)seedBytes[0] & 0xffL;
for (int i = 1; i < 8; ++i)
diff --git a/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index b0096a4..f88242b 100644
--- a/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -79,31 +79,28 @@
*
* <dt>Core and maximum pool sizes</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * A {@code ThreadPoolExecutor} will automatically adjust the
+ * <dd>A {@code ThreadPoolExecutor} will automatically adjust the
* pool size (see {@link #getPoolSize})
* according to the bounds set by
* corePoolSize (see {@link #getCorePoolSize}) and
* maximumPoolSize (see {@link #getMaximumPoolSize}).
*
* When a new task is submitted in method {@link #execute(Runnable)},
- * and fewer than corePoolSize threads are running, a new thread is
+ * if fewer than corePoolSize threads are running, a new thread is
* created to handle the request, even if other worker threads are
- * idle. If there are more than corePoolSize but less than
- * maximumPoolSize threads running, a new thread will be created only
- * if the queue is full. By setting corePoolSize and maximumPoolSize
- * the same, you create a fixed-size thread pool. By setting
- * maximumPoolSize to an essentially unbounded value such as {@code
- * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
- * number of concurrent tasks. Most typically, core and maximum pool
- * sizes are set only upon construction, but they may also be changed
- * dynamically using {@link #setCorePoolSize} and {@link
- * #setMaximumPoolSize}. </dd>
+ * idle. Else if fewer than maximumPoolSize threads are running, a
+ * new thread will be created to handle the request only if the queue
+ * is full. By setting corePoolSize and maximumPoolSize the same, you
+ * create a fixed-size thread pool. By setting maximumPoolSize to an
+ * essentially unbounded value such as {@code Integer.MAX_VALUE}, you
+ * allow the pool to accommodate an arbitrary number of concurrent
+ * tasks. Most typically, core and maximum pool sizes are set only
+ * upon construction, but they may also be changed dynamically using
+ * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd>
*
* <dt>On-demand construction</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * By default, even core threads are initially created and
+ * <dd>By default, even core threads are initially created and
* started only when new tasks arrive, but this can be overridden
* dynamically using method {@link #prestartCoreThread} or {@link
* #prestartAllCoreThreads}. You probably want to prestart threads if
@@ -111,8 +108,7 @@
*
* <dt>Creating new threads</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * New threads are created using a {@link ThreadFactory}. If not
+ * <dd>New threads are created using a {@link ThreadFactory}. If not
* otherwise specified, a {@link Executors#defaultThreadFactory} is
* used, that creates threads to all be in the same {@link
* ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
@@ -129,8 +125,7 @@
*
* <dt>Keep-alive times</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * If the pool currently has more than corePoolSize threads,
+ * <dd>If the pool currently has more than corePoolSize threads,
* excess threads will be terminated if they have been idle for more
* than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
* This provides a means of reducing resource consumption when the
@@ -147,8 +142,7 @@
*
* <dt>Queuing</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * Any {@link BlockingQueue} may be used to transfer and hold
+ * <dd>Any {@link BlockingQueue} may be used to transfer and hold
* submitted tasks. The use of this queue interacts with pool sizing:
*
* <ul>
@@ -213,8 +207,7 @@
*
* <dt>Rejected tasks</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * New tasks submitted in method {@link #execute(Runnable)} will be
+ * <dd>New tasks submitted in method {@link #execute(Runnable)} will be
* <em>rejected</em> when the Executor has been shut down, and also when
* the Executor uses finite bounds for both maximum threads and work queue
* capacity, and is saturated. In either case, the {@code execute} method
@@ -225,9 +218,8 @@
*
* <ol>
*
- * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
- * handler throws a runtime {@link RejectedExecutionException} upon
- * rejection.
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the handler
+ * throws a runtime {@link RejectedExecutionException} upon rejection.
*
* <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
* that invokes {@code execute} itself runs the task. This provides a
@@ -251,8 +243,7 @@
*
* <dt>Hook methods</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * This class provides {@code protected} overridable
+ * <dd>This class provides {@code protected} overridable
* {@link #beforeExecute(Thread, Runnable)} and
* {@link #afterExecute(Runnable, Throwable)} methods that are called
* before and after execution of each task. These can be used to
@@ -268,22 +259,19 @@
*
* <dt>Queue maintenance</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * Method {@link #getQueue()} allows access to the work queue
+ * <dd>Method {@link #getQueue()} allows access to the work queue
* for purposes of monitoring and debugging. Use of this method for
* any other purpose is strongly discouraged. Two supplied methods,
* {@link #remove(Runnable)} and {@link #purge} are available to
* assist in storage reclamation when large numbers of queued tasks
* become cancelled.</dd>
*
- * <dt>Finalization</dt>
+ * <dt>Reclamation</dt>
*
- * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
- * A pool that is no longer referenced in a program <em>AND</em>
- * has no remaining threads will be {@code shutdown} automatically. If
- * you would like to ensure that unreferenced pools are reclaimed even
- * if users forget to call {@link #shutdown}, then you must arrange
- * that unused threads eventually die, by setting appropriate
+ * <dd>A pool that is no longer referenced in a program <em>AND</em>
+ * has no remaining threads may be reclaimed (garbage collected)
+ * without being explicitly shutdown. You can configure a pool to
+ * allow all unused threads to eventually die by setting appropriate
* keep-alive times, using a lower bound of zero core threads and/or
* setting {@link #allowCoreThreadTimeOut(boolean)}. </dd>
*
@@ -374,7 +362,7 @@
* time, but need not hit each state. The transitions are:
*
* RUNNING -> SHUTDOWN
- * On invocation of shutdown(), perhaps implicitly in finalize()
+ * On invocation of shutdown()
* (RUNNING or SHUTDOWN) -> STOP
* On invocation of shutdownNow()
* SHUTDOWN -> TIDYING
@@ -398,7 +386,7 @@
@ReachabilitySensitive
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
- private static final int CAPACITY = (1 << COUNT_BITS) - 1;
+ private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
@@ -408,8 +396,8 @@
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
- private static int runStateOf(int c) { return c & ~CAPACITY; }
- private static int workerCountOf(int c) { return c & CAPACITY; }
+ private static int runStateOf(int c) { return c & ~COUNT_MASK; }
+ private static int workerCountOf(int c) { return c & COUNT_MASK; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
@@ -449,7 +437,7 @@
* decrements are performed within getTask.
*/
private void decrementWorkerCount() {
- do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+ ctl.addAndGet(-1);
}
/**
@@ -555,12 +543,17 @@
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
+ *
+ * Since the worker count is actually stored in COUNT_BITS bits,
+ * the effective limit is {@code corePoolSize & COUNT_MASK}.
*/
private volatile int corePoolSize;
/**
- * Maximum pool size. Note that the actual maximum is internally
- * bounded by CAPACITY.
+ * Maximum pool size.
+ *
+ * Since the worker count is actually stored in COUNT_BITS bits,
+ * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
*/
private volatile int maximumPoolSize;
@@ -626,6 +619,9 @@
/** Per-thread task counter */
volatile long completedTasks;
+ // TODO: switch to AbstractQueuedLongSynchronizer and move
+ // completedTasks into the lock word.
+
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
@@ -716,7 +712,7 @@
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
- (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+ (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
@@ -755,17 +751,12 @@
* specially.
*/
private void checkShutdownAccess() {
+ // assert mainLock.isHeldByCurrentThread();
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers)
- security.checkAccess(w.thread);
- } finally {
- mainLock.unlock();
- }
+ for (Worker w : workers)
+ security.checkAccess(w.thread);
}
}
@@ -774,14 +765,9 @@
* (in which case some threads may remain uninterrupted).
*/
private void interruptWorkers() {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers)
- w.interruptIfStarted();
- } finally {
- mainLock.unlock();
- }
+ // assert mainLock.isHeldByCurrentThread();
+ for (Worker w : workers)
+ w.interruptIfStarted();
}
/**
@@ -857,17 +843,6 @@
}
/**
- * State check needed by ScheduledThreadPoolExecutor to
- * enable running tasks during shutdown.
- *
- * @param shutdownOK true if should return true if SHUTDOWN
- */
- final boolean isRunningOrShutdown(boolean shutdownOK) {
- int rs = runStateOf(ctl.get());
- return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
- }
-
- /**
* Drains the task queue into a new list, normally using
* drainTo. But if the queue is a DelayQueue or any other kind of
* queue for which poll or drainTo may fail to remove some
@@ -918,26 +893,22 @@
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
-
+ for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
- if (rs >= SHUTDOWN &&
- ! (rs == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty()))
+ if (runStateAtLeast(c, SHUTDOWN)
+ && (runStateAtLeast(c, STOP)
+ || firstTask != null
+ || workQueue.isEmpty()))
return false;
for (;;) {
- int wc = workerCountOf(c);
- if (wc >= CAPACITY ||
- wc >= (core ? corePoolSize : maximumPoolSize))
+ if (workerCountOf(c)
+ >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
- if (runStateOf(c) != rs)
+ if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
@@ -956,10 +927,10 @@
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
- int rs = runStateOf(ctl.get());
+ int c = ctl.get();
- if (rs < SHUTDOWN ||
- (rs == SHUTDOWN && firstTask == null)) {
+ if (isRunning(c) ||
+ (runStateLessThan(c, STOP) && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
@@ -1066,10 +1037,10 @@
for (;;) {
int c = ctl.get();
- int rs = runStateOf(c);
// Check if queue empty only if necessary.
- if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+ if (runStateAtLeast(c, SHUTDOWN)
+ && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
@@ -1162,17 +1133,12 @@
wt.interrupt();
try {
beforeExecute(wt, task);
- Throwable thrown = null;
try {
task.run();
- } catch (RuntimeException x) {
- thrown = x; throw x;
- } catch (Error x) {
- thrown = x; throw x;
- } catch (Throwable x) {
- thrown = x; throw new Error(x);
- } finally {
- afterExecute(task, thrown);
+ afterExecute(task, null);
+ } catch (Throwable ex) {
+ afterExecute(task, ex);
+ throw ex;
}
} finally {
task = null;
@@ -1190,9 +1156,11 @@
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
- * parameters and default thread factory and rejected execution handler.
- * It may be more convenient to use one of the {@link Executors} factory
- * methods instead of this general purpose constructor.
+ * parameters, the default thread factory and the default rejected
+ * execution handler.
+ *
+ * <p>It may be more convenient to use one of the {@link Executors}
+ * factory methods instead of this general purpose constructor.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1223,7 +1191,8 @@
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
- * parameters and default rejected execution handler.
+ * parameters and {@linkplain ThreadPoolExecutor.AbortPolicy
+ * default rejected execution handler}.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1258,7 +1227,8 @@
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
- * parameters and default thread factory.
+ * parameters and
+ * {@linkplain Executors#defaultThreadFactory default thread factory}.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -1346,7 +1316,7 @@
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
- * the task is handled by the current {@code RejectedExecutionHandler}.
+ * the task is handled by the current {@link RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
@@ -1451,7 +1421,12 @@
}
public boolean isShutdown() {
- return ! isRunning(ctl.get());
+ return runStateAtLeast(ctl.get(), SHUTDOWN);
+ }
+
+ /** Used by ScheduledThreadPoolExecutor. */
+ boolean isStopped() {
+ return runStateAtLeast(ctl.get(), STOP);
}
/**
@@ -1467,7 +1442,7 @@
*/
public boolean isTerminating() {
int c = ctl.get();
- return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+ return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
@@ -1480,7 +1455,7 @@
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
- while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+ while (runStateLessThan(ctl.get(), TERMINATED)) {
if (nanos <= 0L)
return false;
nanos = termination.awaitNanos(nanos);
@@ -1491,13 +1466,21 @@
}
}
+ // Override without "throws Throwable" for compatibility with subclasses
+ // whose finalize method invokes super.finalize() (as is recommended).
+ // Before JDK 11, finalize() had a non-empty method body.
+
+ // Android-added: The @deprecated javadoc tag
/**
- * Invokes {@code shutdown} when this executor is no longer
- * referenced and it has no threads.
+ * @implNote Previous versions of this class had a finalize method
+ * that shut down this executor, but in this version, finalize
+ * does nothing.
+ *
+ * @deprecated Subclass is not recommended to override finalize(). If it
+ * must, please always invoke super.finalize().
*/
- protected void finalize() {
- shutdown();
- }
+ @Deprecated(since="9")
+ protected void finalize() {}
/**
* Sets the thread factory used to create new threads.
@@ -1946,7 +1929,7 @@
}
int c = ctl.get();
String runState =
- runStateLessThan(c, SHUTDOWN) ? "Running" :
+ isRunning(c) ? "Running" :
runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down";
return super.toString() +
@@ -2065,7 +2048,10 @@
/**
* A handler for rejected tasks that throws a
- * {@code RejectedExecutionException}.
+ * {@link RejectedExecutionException}.
+ *
+ * This is the default handler for {@link ThreadPoolExecutor} and
+ * {@link ScheduledThreadPoolExecutor}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
diff --git a/ojluni/src/main/java/java/util/concurrent/TimeUnit.java b/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
index 44d7964..f02aa9f 100644
--- a/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/ojluni/src/main/java/java/util/concurrent/TimeUnit.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
import java.util.Objects;
/**
@@ -74,136 +76,93 @@
/**
* Time unit representing one thousandth of a microsecond.
*/
- NANOSECONDS {
- public long toNanos(long d) { return d; }
- public long toMicros(long d) { return d/(C1/C0); }
- public long toMillis(long d) { return d/(C2/C0); }
- public long toSeconds(long d) { return d/(C3/C0); }
- public long toMinutes(long d) { return d/(C4/C0); }
- public long toHours(long d) { return d/(C5/C0); }
- public long toDays(long d) { return d/(C6/C0); }
- public long convert(long d, TimeUnit u) { return u.toNanos(d); }
- int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
- },
-
+ NANOSECONDS(TimeUnit.NANO_SCALE),
/**
* Time unit representing one thousandth of a millisecond.
*/
- MICROSECONDS {
- public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
- public long toMicros(long d) { return d; }
- public long toMillis(long d) { return d/(C2/C1); }
- public long toSeconds(long d) { return d/(C3/C1); }
- public long toMinutes(long d) { return d/(C4/C1); }
- public long toHours(long d) { return d/(C5/C1); }
- public long toDays(long d) { return d/(C6/C1); }
- public long convert(long d, TimeUnit u) { return u.toMicros(d); }
- int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
- },
-
+ MICROSECONDS(TimeUnit.MICRO_SCALE),
/**
* Time unit representing one thousandth of a second.
*/
- MILLISECONDS {
- public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
- public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); }
- public long toMillis(long d) { return d; }
- public long toSeconds(long d) { return d/(C3/C2); }
- public long toMinutes(long d) { return d/(C4/C2); }
- public long toHours(long d) { return d/(C5/C2); }
- public long toDays(long d) { return d/(C6/C2); }
- public long convert(long d, TimeUnit u) { return u.toMillis(d); }
- int excessNanos(long d, long m) { return 0; }
- },
-
+ MILLISECONDS(TimeUnit.MILLI_SCALE),
/**
* Time unit representing one second.
*/
- SECONDS {
- public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
- public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); }
- public long toMillis(long d) { return x(d, C3/C2, MAX/(C3/C2)); }
- public long toSeconds(long d) { return d; }
- public long toMinutes(long d) { return d/(C4/C3); }
- public long toHours(long d) { return d/(C5/C3); }
- public long toDays(long d) { return d/(C6/C3); }
- public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
- int excessNanos(long d, long m) { return 0; }
- },
-
+ SECONDS(TimeUnit.SECOND_SCALE),
/**
* Time unit representing sixty seconds.
* @since 1.6
*/
- MINUTES {
- public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); }
- public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); }
- public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); }
- public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
- public long toMinutes(long d) { return d; }
- public long toHours(long d) { return d/(C5/C4); }
- public long toDays(long d) { return d/(C6/C4); }
- public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
- int excessNanos(long d, long m) { return 0; }
- },
-
+ MINUTES(TimeUnit.MINUTE_SCALE),
/**
* Time unit representing sixty minutes.
* @since 1.6
*/
- HOURS {
- public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); }
- public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); }
- public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); }
- public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
- public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
- public long toHours(long d) { return d; }
- public long toDays(long d) { return d/(C6/C5); }
- public long convert(long d, TimeUnit u) { return u.toHours(d); }
- int excessNanos(long d, long m) { return 0; }
- },
-
+ HOURS(TimeUnit.HOUR_SCALE),
/**
* Time unit representing twenty four hours.
* @since 1.6
*/
- DAYS {
- public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); }
- public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); }
- public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); }
- public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
- public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
- public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); }
- public long toDays(long d) { return d; }
- public long convert(long d, TimeUnit u) { return u.toDays(d); }
- int excessNanos(long d, long m) { return 0; }
- };
+ DAYS(TimeUnit.DAY_SCALE);
- // Handy constants for conversion methods
- static final long C0 = 1L;
- static final long C1 = C0 * 1000L;
- static final long C2 = C1 * 1000L;
- static final long C3 = C2 * 1000L;
- static final long C4 = C3 * 60L;
- static final long C5 = C4 * 60L;
- static final long C6 = C5 * 24L;
+ // Scales as constants
+ private static final long NANO_SCALE = 1L;
+ private static final long MICRO_SCALE = 1000L * NANO_SCALE;
+ private static final long MILLI_SCALE = 1000L * MICRO_SCALE;
+ private static final long SECOND_SCALE = 1000L * MILLI_SCALE;
+ private static final long MINUTE_SCALE = 60L * SECOND_SCALE;
+ private static final long HOUR_SCALE = 60L * MINUTE_SCALE;
+ private static final long DAY_SCALE = 24L * HOUR_SCALE;
- static final long MAX = Long.MAX_VALUE;
-
- /**
- * Scale d by m, checking for overflow.
- * This has a short name to make above code more readable.
+ /*
+ * Instances cache conversion ratios and saturation cutoffs for
+ * the units up through SECONDS. Other cases compute them, in
+ * method cvt.
*/
- static long x(long d, long m, long over) {
- if (d > +over) return Long.MAX_VALUE;
- if (d < -over) return Long.MIN_VALUE;
- return d * m;
+
+ private final long scale;
+ private final long maxNanos;
+ private final long maxMicros;
+ private final long maxMillis;
+ private final long maxSecs;
+ private final long microRatio;
+ private final int milliRatio; // fits in 32 bits
+ private final int secRatio; // fits in 32 bits
+
+ private TimeUnit(long s) {
+ this.scale = s;
+ this.maxNanos = Long.MAX_VALUE / s;
+ long ur = (s >= MICRO_SCALE) ? (s / MICRO_SCALE) : (MICRO_SCALE / s);
+ this.microRatio = ur;
+ this.maxMicros = Long.MAX_VALUE / ur;
+ long mr = (s >= MILLI_SCALE) ? (s / MILLI_SCALE) : (MILLI_SCALE / s);
+ this.milliRatio = (int)mr;
+ this.maxMillis = Long.MAX_VALUE / mr;
+ long sr = (s >= SECOND_SCALE) ? (s / SECOND_SCALE) : (SECOND_SCALE / s);
+ this.secRatio = (int)sr;
+ this.maxSecs = Long.MAX_VALUE / sr;
}
- // To maintain full signature compatibility with 1.5, and to improve the
- // clarity of the generated javadoc (see 6287639: Abstract methods in
- // enum classes should not be listed as abstract), method convert
- // etc. are not declared abstract but otherwise act as abstract methods.
+ /**
+ * General conversion utility.
+ *
+ * @param d duration
+ * @param dst result unit scale
+ * @param src source unit scale
+ */
+ private static long cvt(long d, long dst, long src) {
+ long r, m;
+ if (src == dst)
+ return d;
+ else if (src < dst)
+ return d / (dst / src);
+ else if (d > (m = Long.MAX_VALUE / (r = src / dst)))
+ return Long.MAX_VALUE;
+ else if (d < -m)
+ return Long.MIN_VALUE;
+ else
+ return d * r;
+ }
/**
* Converts the given time duration in the given unit to this unit.
@@ -220,11 +179,65 @@
* @param sourceDuration the time duration in the given {@code sourceUnit}
* @param sourceUnit the unit of the {@code sourceDuration} argument
* @return the converted duration in this unit,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
*/
public long convert(long sourceDuration, TimeUnit sourceUnit) {
- throw new AbstractMethodError();
+ switch (this) {
+ case NANOSECONDS: return sourceUnit.toNanos(sourceDuration);
+ case MICROSECONDS: return sourceUnit.toMicros(sourceDuration);
+ case MILLISECONDS: return sourceUnit.toMillis(sourceDuration);
+ case SECONDS: return sourceUnit.toSeconds(sourceDuration);
+ default: return cvt(sourceDuration, scale, sourceUnit.scale);
+ }
+ }
+
+ /**
+ * Converts the given time duration to this unit.
+ *
+ * <p>For any TimeUnit {@code unit},
+ * {@code unit.convert(Duration.ofNanos(n))}
+ * is equivalent to
+ * {@code unit.convert(n, NANOSECONDS)}, and
+ * {@code unit.convert(Duration.of(n, unit.toChronoUnit()))}
+ * is equivalent to {@code n} (in the absence of overflow).
+ *
+ * @apiNote
+ * This method differs from {@link Duration#toNanos()} in that it
+ * does not throw {@link ArithmeticException} on numeric overflow.
+ *
+ * @param duration the time duration
+ * @return the converted duration in this unit,
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
+ * @throws NullPointerException if {@code duration} is null
+ * @see Duration#of(long,TemporalUnit)
+ * @since 11
+ */
+ public long convert(Duration duration) {
+ long secs = duration.getSeconds();
+ int nano = duration.getNano();
+ if (secs < 0 && nano > 0) {
+ // use representation compatible with integer division
+ secs++;
+ nano -= (int) SECOND_SCALE;
+ }
+ final long s, nanoVal;
+ // Optimize for the common case - NANOSECONDS without overflow
+ if (this == NANOSECONDS)
+ nanoVal = nano;
+ else if ((s = scale) < SECOND_SCALE)
+ nanoVal = nano / s;
+ else if (this == SECONDS)
+ return secs;
+ else
+ return secs / secRatio;
+ long val = secs * secRatio + nanoVal;
+ return ((secs < maxSecs && secs > -maxSecs) ||
+ (secs == maxSecs && val > 0) ||
+ (secs == -maxSecs && val < 0))
+ ? val
+ : (secs > 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
}
/**
@@ -232,11 +245,19 @@
* {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
*/
public long toNanos(long duration) {
- throw new AbstractMethodError();
+ long s, m;
+ if ((s = scale) == NANO_SCALE)
+ return duration;
+ else if (duration > (m = maxNanos))
+ return Long.MAX_VALUE;
+ else if (duration < -m)
+ return Long.MIN_VALUE;
+ else
+ return duration * s;
}
/**
@@ -244,11 +265,19 @@
* {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
*/
public long toMicros(long duration) {
- throw new AbstractMethodError();
+ long s, m;
+ if ((s = scale) <= MICRO_SCALE)
+ return (s == MICRO_SCALE) ? duration : duration / microRatio;
+ else if (duration > (m = maxMicros))
+ return Long.MAX_VALUE;
+ else if (duration < -m)
+ return Long.MIN_VALUE;
+ else
+ return duration * microRatio;
}
/**
@@ -256,11 +285,19 @@
* {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
*/
public long toMillis(long duration) {
- throw new AbstractMethodError();
+ long s, m;
+ if ((s = scale) <= MILLI_SCALE)
+ return (s == MILLI_SCALE) ? duration : duration / milliRatio;
+ else if (duration > (m = maxMillis))
+ return Long.MAX_VALUE;
+ else if (duration < -m)
+ return Long.MIN_VALUE;
+ else
+ return duration * milliRatio;
}
/**
@@ -268,11 +305,19 @@
* {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
*/
public long toSeconds(long duration) {
- throw new AbstractMethodError();
+ long s, m;
+ if ((s = scale) <= SECOND_SCALE)
+ return (s == SECOND_SCALE) ? duration : duration / secRatio;
+ else if (duration > (m = maxSecs))
+ return Long.MAX_VALUE;
+ else if (duration < -m)
+ return Long.MIN_VALUE;
+ else
+ return duration * secRatio;
}
/**
@@ -280,12 +325,12 @@
* {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
* @since 1.6
*/
public long toMinutes(long duration) {
- throw new AbstractMethodError();
+ return cvt(duration, MINUTE_SCALE, scale);
}
/**
@@ -293,12 +338,12 @@
* {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
* @param duration the duration
* @return the converted duration,
- * or {@code Long.MIN_VALUE} if conversion would negatively
- * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+ * or {@code Long.MAX_VALUE} if it would positively overflow.
* @since 1.6
*/
public long toHours(long duration) {
- throw new AbstractMethodError();
+ return cvt(duration, HOUR_SCALE, scale);
}
/**
@@ -309,7 +354,7 @@
* @since 1.6
*/
public long toDays(long duration) {
- throw new AbstractMethodError();
+ return cvt(duration, DAY_SCALE, scale);
}
/**
@@ -319,7 +364,15 @@
* @param m the number of milliseconds
* @return the number of nanoseconds
*/
- abstract int excessNanos(long d, long m);
+ private int excessNanos(long d, long m) {
+ long s;
+ if ((s = scale) == NANO_SCALE)
+ return (int)(d - (m * MILLI_SCALE));
+ else if (s == MICRO_SCALE)
+ return (int)((d * 1000L) - (m * MILLI_SCALE));
+ else
+ return 0;
+ }
/**
* Performs a timed {@link Object#wait(long, int) Object.wait}
@@ -327,16 +380,18 @@
* This is a convenience method that converts timeout arguments
* into the form required by the {@code Object.wait} method.
*
- * <p>For example, you could implement a blocking {@code poll}
- * method (see {@link BlockingQueue#poll BlockingQueue.poll})
+ * <p>For example, you could implement a blocking {@code poll} method
+ * (see {@link BlockingQueue#poll(long, TimeUnit) BlockingQueue.poll})
* using:
*
* <pre> {@code
- * public synchronized Object poll(long timeout, TimeUnit unit)
+ * public E poll(long timeout, TimeUnit unit)
* throws InterruptedException {
- * while (empty) {
- * unit.timedWait(this, timeout);
- * ...
+ * synchronized (lock) {
+ * while (isEmpty()) {
+ * unit.timedWait(lock, timeout);
+ * ...
+ * }
* }
* }}</pre>
*
@@ -392,14 +447,12 @@
}
}
- // BEGIN Android-removed: OpenJDK 9 ChronoUnit related code.
- /*
/**
* Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
*
* @return the converted equivalent ChronoUnit
* @since 9
- *
+ */
public ChronoUnit toChronoUnit() {
switch (this) {
case NANOSECONDS: return ChronoUnit.NANOS;
@@ -422,7 +475,7 @@
* equivalent TimeUnit
* @throws NullPointerException if {@code chronoUnit} is null
* @since 9
- *
+ */
public static TimeUnit of(ChronoUnit chronoUnit) {
switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
case NANOS: return TimeUnit.NANOSECONDS;
@@ -437,7 +490,5 @@
"No TimeUnit equivalent for " + chronoUnit);
}
}
- */
- // END Android-removed: OpenJDK 9 ChronoUnit related code.
}
diff --git a/ojluni/src/main/java/java/util/concurrent/TransferQueue.java b/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
index 53da597..72a4108 100644
--- a/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/ojluni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -35,10 +35,6 @@
package java.util.concurrent;
-// BEGIN android-note
-// removed link to collections framework docs
-// END android-note
-
/**
* A {@link BlockingQueue} in which producers may wait for consumers
* to receive elements. A {@code TransferQueue} may be useful for
@@ -61,6 +57,10 @@
* with zero capacity, such as {@link SynchronousQueue}, {@code put}
* and {@code transfer} are effectively synonymous.
*
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
* @since 1.7
* @author Doug Lea
* @param <E> the type of elements held in this queue
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index 447a642..34a200b 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -40,10 +40,13 @@
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
/**
* A reflection-based utility that enables atomic updates to
@@ -59,6 +62,10 @@
* guarantee atomicity only with respect to other invocations of
* {@code compareAndSet} and {@code set} on the same updater.
*
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
* @since 1.5
* @author Doug Lea
* @param <T> The type of the object holding the updatable field
@@ -107,8 +114,6 @@
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful
- * @throws ClassCastException if {@code obj} is not an instance
- * of the class possessing the field established in the constructor
*/
public abstract boolean compareAndSet(T obj, long expect, long update);
@@ -127,8 +132,6 @@
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful
- * @throws ClassCastException if {@code obj} is not an instance
- * of the class possessing the field established in the constructor
*/
public abstract boolean weakCompareAndSet(T obj, long expect, long update);
@@ -153,8 +156,8 @@
public abstract void lazySet(T obj, long newValue);
/**
- * Gets the current value held in the field of the given object managed
- * by this updater.
+ * Returns the current value held in the field of the given object
+ * managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@@ -276,10 +279,12 @@
}
/**
- * Atomically updates the field of the given object managed by this updater
- * with the results of applying the given function, returning the previous
- * value. The function should be side-effect-free, since it may be
- * re-applied when attempted updates fail due to contention among threads.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given
+ * function, returning the previous value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
+ * updates fail due to contention among threads.
*
* @param obj An object whose field to get and set
* @param updateFunction a side-effect-free function
@@ -296,10 +301,12 @@
}
/**
- * Atomically updates the field of the given object managed by this updater
- * with the results of applying the given function, returning the updated
- * value. The function should be side-effect-free, since it may be
- * re-applied when attempted updates fail due to contention among threads.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given
+ * function, returning the updated value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
+ * updates fail due to contention among threads.
*
* @param obj An object whose field to get and set
* @param updateFunction a side-effect-free function
@@ -316,13 +323,14 @@
}
/**
- * Atomically updates the field of the given object managed by this
- * updater with the results of applying the given function to the
- * current and given values, returning the previous value. The
- * function should be side-effect-free, since it may be re-applied
- * when attempted updates fail due to contention among threads. The
- * function is applied with the current value as its first argument,
- * and the given update as the second argument.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given function
+ * to the current and given values, returning the previous value.
+ * The function should be side-effect-free, since it may be
+ * re-applied when attempted updates fail due to contention among
+ * threads. The function is applied with the current value as its
+ * first argument, and the given update as the second argument.
*
* @param obj An object whose field to get and set
* @param x the update value
@@ -341,13 +349,14 @@
}
/**
- * Atomically updates the field of the given object managed by this
- * updater with the results of applying the given function to the
- * current and given values, returning the updated value. The
- * function should be side-effect-free, since it may be re-applied
- * when attempted updates fail due to contention among threads. The
- * function is applied with the current value as its first argument,
- * and the given update as the second argument.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given function
+ * to the current and given values, returning the updated value.
+ * The function should be side-effect-free, since it may be
+ * re-applied when attempted updates fail due to contention among
+ * threads. The function is applied with the current value as its
+ * first argument, and the given update as the second argument.
*
* @param obj An object whose field to get and set
* @param x the update value
@@ -366,7 +375,7 @@
}
private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
@@ -418,7 +427,17 @@
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ // Access to protected field members is restricted to receivers only
+ // of the accessing class, or one of its subclasses, and the
+ // accessing class must in turn be a subclass (or package sibling)
+ // of the protected member's defining class.
+ // If the updater refers to a protected field of a declaring class
+ // outside the current package, the receiver argument will be
+ // narrowed to the type of the accessing class.
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ tclass.isAssignableFrom(caller) &&
+ !isSamePackage(tclass, caller))
+ ? caller : tclass;
this.tclass = tclass;
this.offset = U.objectFieldOffset(field);
}
@@ -452,12 +471,12 @@
public final boolean compareAndSet(T obj, long expect, long update) {
accessCheck(obj);
- return U.compareAndSwapLong(obj, offset, expect, update);
+ return U.compareAndSetLong(obj, offset, expect, update);
}
public final boolean weakCompareAndSet(T obj, long expect, long update) {
accessCheck(obj);
- return U.compareAndSwapLong(obj, offset, expect, update);
+ return U.compareAndSetLong(obj, offset, expect, update);
}
public final void set(T obj, long newValue) {
@@ -467,7 +486,7 @@
public final void lazySet(T obj, long newValue) {
accessCheck(obj);
- U.putOrderedLong(obj, offset, newValue);
+ U.putLongRelease(obj, offset, newValue);
}
public final long get(T obj) {
@@ -507,7 +526,7 @@
}
private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
@@ -519,8 +538,8 @@
LockedUpdater(final Class<T> tclass, final String fieldName,
final Class<?> caller) {
- Field field = null;
- int modifiers = 0;
+ final Field field;
+ final int modifiers;
try {
// Android-changed: Skip privilege escalation which is a noop on Android.
/*
@@ -559,7 +578,17 @@
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ // Access to protected field members is restricted to receivers only
+ // of the accessing class, or one of its subclasses, and the
+ // accessing class must in turn be a subclass (or package sibling)
+ // of the protected member's defining class.
+ // If the updater refers to a protected field of a declaring class
+ // outside the current package, the receiver argument will be
+ // narrowed to the type of the accessing class.
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ tclass.isAssignableFrom(caller) &&
+ !isSamePackage(tclass, caller))
+ ? caller : tclass;
this.tclass = tclass;
this.offset = U.objectFieldOffset(field);
}
@@ -643,4 +672,13 @@
return false;
}
*/
+
+ /**
+ * Returns true if the two classes have the same class loader and
+ * package qualifier
+ */
+ static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+ return class1.getClassLoader() == class2.getClassLoader()
+ && Objects.equals(class1.getPackageName(), class2.getPackageName());
+ }
}
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
index b49118b..51ea84c 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -35,6 +35,9 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* An {@code AtomicMarkableReference} maintains an object reference
* along with a mark bit, that can be updated atomically.
@@ -188,20 +191,19 @@
casPair(current, Pair.of(expectedReference, newMark)));
}
- // Unsafe mechanics
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PAIR;
+ // VarHandle mechanics
+ private static final VarHandle PAIR;
static {
try {
- PAIR = U.objectFieldOffset
- (AtomicMarkableReference.class.getDeclaredField("pair"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
+ Pair.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
- return U.compareAndSwapObject(this, PAIR, cmp, val);
+ return PAIR.compareAndSet(this, cmp, val);
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 17423ad..513a243 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -40,10 +40,13 @@
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
/**
* A reflection-based utility that enables atomic updates to
@@ -76,6 +79,10 @@
* guarantee atomicity only with respect to other invocations of
* {@code compareAndSet} and {@code set} on the same updater.
*
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
* @since 1.5
* @author Doug Lea
* @param <T> The type of the object holding the updatable field
@@ -168,8 +175,8 @@
public abstract void lazySet(T obj, V newValue);
/**
- * Gets the current value held in the field of the given object managed
- * by this updater.
+ * Returns the current value held in the field of the given object
+ * managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@@ -193,10 +200,12 @@
}
/**
- * Atomically updates the field of the given object managed by this updater
- * with the results of applying the given function, returning the previous
- * value. The function should be side-effect-free, since it may be
- * re-applied when attempted updates fail due to contention among threads.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given
+ * function, returning the previous value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
+ * updates fail due to contention among threads.
*
* @param obj An object whose field to get and set
* @param updateFunction a side-effect-free function
@@ -213,10 +222,12 @@
}
/**
- * Atomically updates the field of the given object managed by this updater
- * with the results of applying the given function, returning the updated
- * value. The function should be side-effect-free, since it may be
- * re-applied when attempted updates fail due to contention among threads.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given
+ * function, returning the updated value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
+ * updates fail due to contention among threads.
*
* @param obj An object whose field to get and set
* @param updateFunction a side-effect-free function
@@ -233,13 +244,14 @@
}
/**
- * Atomically updates the field of the given object managed by this
- * updater with the results of applying the given function to the
- * current and given values, returning the previous value. The
- * function should be side-effect-free, since it may be re-applied
- * when attempted updates fail due to contention among threads. The
- * function is applied with the current value as its first argument,
- * and the given update as the second argument.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given function
+ * to the current and given values, returning the previous value.
+ * The function should be side-effect-free, since it may be
+ * re-applied when attempted updates fail due to contention among
+ * threads. The function is applied with the current value as its
+ * first argument, and the given update as the second argument.
*
* @param obj An object whose field to get and set
* @param x the update value
@@ -258,13 +270,14 @@
}
/**
- * Atomically updates the field of the given object managed by this
- * updater with the results of applying the given function to the
- * current and given values, returning the updated value. The
- * function should be side-effect-free, since it may be re-applied
- * when attempted updates fail due to contention among threads. The
- * function is applied with the current value as its first argument,
- * and the given update as the second argument.
+ * Atomically updates (with memory effects as specified by {@link
+ * VarHandle#compareAndSet}) the field of the given object managed
+ * by this updater with the results of applying the given function
+ * to the current and given values, returning the updated value.
+ * The function should be side-effect-free, since it may be
+ * re-applied when attempted updates fail due to contention among
+ * threads. The function is applied with the current value as its
+ * first argument, and the given update as the second argument.
*
* @param obj An object whose field to get and set
* @param x the update value
@@ -284,7 +297,7 @@
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
@@ -356,7 +369,17 @@
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
- this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+ // Access to protected field members is restricted to receivers only
+ // of the accessing class, or one of its subclasses, and the
+ // accessing class must in turn be a subclass (or package sibling)
+ // of the protected member's defining class.
+ // If the updater refers to a protected field of a declaring class
+ // outside the current package, the receiver argument will be
+ // narrowed to the type of the accessing class.
+ this.cclass = (Modifier.isProtected(modifiers) &&
+ tclass.isAssignableFrom(caller) &&
+ !isSamePackage(tclass, caller))
+ ? caller : tclass;
this.tclass = tclass;
this.vclass = vclass;
this.offset = U.objectFieldOffset(field);
@@ -382,6 +405,15 @@
*/
/**
+ * Returns true if the two classes have the same class loader and
+ * package qualifier
+ */
+ private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+ return class1.getClassLoader() == class2.getClassLoader()
+ && Objects.equals(class1.getPackageName(), class2.getPackageName());
+ }
+
+ /**
* Checks that target argument is instance of cclass. On
* failure, throws cause.
*/
@@ -420,14 +452,14 @@
public final boolean compareAndSet(T obj, V expect, V update) {
accessCheck(obj);
valueCheck(update);
- return U.compareAndSwapObject(obj, offset, expect, update);
+ return U.compareAndSetObject(obj, offset, expect, update);
}
public final boolean weakCompareAndSet(T obj, V expect, V update) {
// same implementation as strong form for now
accessCheck(obj);
valueCheck(update);
- return U.compareAndSwapObject(obj, offset, expect, update);
+ return U.compareAndSetObject(obj, offset, expect, update);
}
public final void set(T obj, V newValue) {
@@ -439,7 +471,7 @@
public final void lazySet(T obj, V newValue) {
accessCheck(obj);
valueCheck(newValue);
- U.putOrderedObject(obj, offset, newValue);
+ U.putObjectRelease(obj, offset, newValue);
}
@SuppressWarnings("unchecked")
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
index 40ceeb2..47b7c7b 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -35,6 +35,9 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* An {@code AtomicStampedReference} maintains an object reference
* along with an integer "stamp", that can be updated atomically.
@@ -188,20 +191,19 @@
casPair(current, Pair.of(expectedReference, newStamp)));
}
- // Unsafe mechanics
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long PAIR;
+ // VarHandle mechanics
+ private static final VarHandle PAIR;
static {
try {
- PAIR = U.objectFieldOffset
- (AtomicStampedReference.class.getDeclaredField("pair"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
+ Pair.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
- return U.compareAndSwapObject(this, PAIR, cmp, val);
+ return PAIR.compareAndSet(this, cmp, val);
}
}
diff --git a/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java b/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java
index 2a8f327..2d83d61 100644
--- a/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java
+++ b/ojluni/src/main/java/java/util/concurrent/atomic/Striped64.java
@@ -119,8 +119,7 @@
* JVM intrinsics note: It would be possible to use a release-only
* form of CAS here, if it were provided.
*/
- // Android-removed: @Contended, this hint is not used by the Android runtime.
- // @jdk.internal.vm.annotation.Contended
+ @jdk.internal.vm.annotation.Contended
static final class Cell {
volatile long value;
Cell(long x) { value = x; }
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 50e3c52..4ecfff0 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -903,8 +903,6 @@
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
@@ -1237,8 +1235,6 @@
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
@@ -1302,8 +1298,6 @@
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
@@ -1384,8 +1378,6 @@
* and can represent anything you like.
* @return the value returned from {@link #tryReleaseShared}
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
index 0c5b3e6..1cb7d89 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
@@ -37,6 +37,7 @@
import java.util.Collection;
import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* A reentrant mutual exclusion {@link Lock} with the same basic
@@ -121,8 +122,7 @@
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
@@ -142,8 +142,7 @@
return false;
}
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
@@ -210,8 +209,7 @@
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
index d01e67a..c92e213 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -37,6 +37,7 @@
import java.util.Collection;
import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* An implementation of {@link ReadWriteLock} supporting similar
@@ -365,8 +366,7 @@
* both read and write holds that are all released during a
* condition wait and re-established in tryAcquire.
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
@@ -378,8 +378,7 @@
return free;
}
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
@@ -412,8 +411,7 @@
return true;
}
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
@@ -451,8 +449,7 @@
"attempt to unlock read lock, not locked by current thread");
}
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
@@ -563,8 +560,7 @@
* This is identical in effect to tryAcquire except for lack
* of calls to writerShouldBlock.
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
@@ -586,8 +582,7 @@
* This is identical in effect to tryAcquireShared except for
* lack of calls to readerShouldBlock.
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
diff --git a/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java b/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java
index 8a2cd35..dbcf9c3 100644
--- a/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java
+++ b/ojluni/src/main/java/java/util/concurrent/locks/StampedLock.java
@@ -38,6 +38,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* A capability-based lock with three modes for controlling read/write
@@ -454,8 +455,7 @@
*
* @return a write stamp that can be used to unlock or convert mode
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long writeLock() {
long next;
return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
@@ -467,8 +467,7 @@
* @return a write stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long tryWriteLock() {
long s;
return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
@@ -514,8 +513,7 @@
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long writeLockInterruptibly() throws InterruptedException {
long next;
if (!Thread.interrupted() &&
@@ -530,8 +528,7 @@
*
* @return a read stamp that can be used to unlock or convert mode
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long readLock() {
long s, next;
// bypass acquireRead on common uncontended case
@@ -548,8 +545,7 @@
* @return a read stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long tryReadLock() {
long s, m, next;
while ((m = (s = state) & ABITS) != WBIT) {
@@ -576,8 +572,7 @@
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long tryReadLock(long time, TimeUnit unit)
throws InterruptedException {
long s, m, next, deadline;
@@ -611,8 +606,7 @@
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public long readLockInterruptibly() throws InterruptedException {
long s, next;
if (!Thread.interrupted()
@@ -680,8 +674,7 @@
* @throws IllegalMonitorStateException if the stamp does
* not match the current state of this lock
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public void unlockWrite(long stamp) {
if (state != stamp || (stamp & WBIT) == 0L)
throw new IllegalMonitorStateException();
@@ -696,8 +689,7 @@
* @throws IllegalMonitorStateException if the stamp does
* not match the current state of this lock
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public void unlockRead(long stamp) {
long s, m; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)
@@ -724,8 +716,7 @@
* @throws IllegalMonitorStateException if the stamp does
* not match the current state of this lock
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public void unlock(long stamp) {
if ((stamp & WBIT) != 0L)
unlockWrite(stamp);
@@ -858,8 +849,7 @@
*
* @return {@code true} if the lock was held, else false
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public boolean tryUnlockWrite() {
long s;
if (((s = state) & WBIT) != 0L) {
@@ -876,8 +866,7 @@
*
* @return {@code true} if the read lock was held, else false
*/
- // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
- // @ReservedStackAccess
+ @ReservedStackAccess
public boolean tryUnlockRead() {
long s, m; WNode h;
while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
@@ -1176,8 +1165,9 @@
}
else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
- else
- Thread.onSpinWait();
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // else
+ // Thread.onSpinWait();
return 0L;
}
@@ -1204,8 +1194,9 @@
}
else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
- else
- Thread.onSpinWait();
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // else
+ // Thread.onSpinWait();
return 0L;
}
@@ -1251,7 +1242,8 @@
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) {
--spins;
- Thread.onSpinWait();
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // Thread.onSpinWait();
}
else if ((p = wtail) == null) { // initialize queue
WNode hd = new WNode(WMODE, null);
@@ -1287,8 +1279,9 @@
return ns;
}
}
- else
- Thread.onSpinWait();
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // else
+ // Thread.onSpinWait();
}
}
else if (h != null) { // help release stale waiters
@@ -1364,7 +1357,8 @@
else if (m >= WBIT) {
if (spins > 0) {
--spins;
- Thread.onSpinWait();
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // Thread.onSpinWait();
}
else {
if (spins == 0) {
@@ -1473,8 +1467,9 @@
}
else if (m >= WBIT && --k <= 0)
break;
- else
- Thread.onSpinWait();
+ // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+ // else
+ // Thread.onSpinWait();
}
}
else if (h != null) {
diff --git a/ojluni/src/main/java/java/util/concurrent/package-info.java b/ojluni/src/main/java/java/util/concurrent/package-info.java
index 387068d..0e992a2 100644
--- a/ojluni/src/main/java/java/util/concurrent/package-info.java
+++ b/ojluni/src/main/java/java/util/concurrent/package-info.java
@@ -200,7 +200,7 @@
* concurrent collection is thread-safe, but not governed by a
* single exclusion lock. In the particular case of
* ConcurrentHashMap, it safely permits any number of
- * concurrent reads as well as a tunable number of concurrent
+ * concurrent reads as well as a large number of concurrent
* writes. "Synchronized" classes can be useful when you need
* to prevent all access to a collection via a single lock, at
* the expense of poorer scalability. In other cases in which
@@ -262,7 +262,6 @@
*
* </ul>
*
- *
* The methods of all classes in {@code java.util.concurrent} and its
* subpackages extend these guarantees to higher-level
* synchronization. In particular:
diff --git a/ojluni/src/main/java/java/util/zip/GZIPInputStream.java b/ojluni/src/main/java/java/util/zip/GZIPInputStream.java
index e259505..b2482f4 100644
--- a/ojluni/src/main/java/java/util/zip/GZIPInputStream.java
+++ b/ojluni/src/main/java/java/util/zip/GZIPInputStream.java
@@ -66,6 +66,14 @@
/**
* Creates a new input stream with the specified buffer size.
+ *
+ * Android-note: Android limits the number of UnbufferedIO operations that can be performed, so
+ * consider using buffered inputs with this class. More information can be found in the
+ * <a href="https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder#detectUnbufferedIo()">
+ * UnbufferedIO</a> and
+ * <a href="https://developer.android.com/reference/android/os/StrictMode"> StrictMode</a>
+ * documentation.
+ *
* @param in the input stream
* @param size the input buffer size
*
diff --git a/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java b/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java
index 9ff56f1..cad62dc 100644
--- a/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java
+++ b/ojluni/src/main/java/java/util/zip/GZIPOutputStream.java
@@ -59,6 +59,13 @@
* <p>The new output stream instance is created as if by invoking
* the 3-argument constructor GZIPOutputStream(out, size, false).
*
+ * Android-note: Android limits the number of UnbufferedIO operations that can be performed, so
+ * consider using buffered inputs with this class. More information can be found in the
+ * <a href="https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder#detectUnbufferedIo()">
+ * UnbufferedIO</a> and
+ * <a href="https://developer.android.com/reference/android/os/StrictMode"> StrictMode</a>
+ * documentation.
+ *
* @param out the output stream
* @param size the output buffer size
* @exception IOException If an I/O error has occurred.
diff --git a/ojluni/src/main/java/java/util/zip/ZipInputStream.java b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
index 6ca359d..068c277 100644
--- a/ojluni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
@@ -324,7 +324,7 @@
e.method = get16(tmpbuf, LOCHOW);
e.xdostime = get32(tmpbuf, LOCTIM);
if ((flag & 8) == 8) {
- // Android-Changed: Remove the requirement that only DEFLATED entries
+ // Android-changed: Remove the requirement that only DEFLATED entries
// can have data descriptors. This is not required by the ZIP spec and
// is inconsistent with the behaviour of ZipFile and versions of Android
// prior to Android N.
diff --git a/ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java b/ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java
new file mode 100644
index 0000000..cfba310
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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
+ * 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;
+
+import java.lang.annotation.*;
+
+// Android-note: HotSpot-specific implementation notes not relevant for Android.
+/**
+ * The {@code @HotSpotIntrinsicCandidate} annotation is specific to the
+ * HotSpot Virtual Machine. It indicates that an annotated method
+ * may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method
+ * is intrinsified if the HotSpot VM replaces the annotated method with hand-written
+ * assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve
+ * performance. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the
+ * Java libraries and is therefore not supposed to have any relevance for application
+ * code.
+ *
+ * Maintainers of the Java libraries must consider the following when
+ * modifying methods annotated with {@code @HotSpotIntrinsicCandidate}.
+ *
+ * <ul>
+ * <li>When modifying a method annotated with {@code @HotSpotIntrinsicCandidate},
+ * the corresponding intrinsic code in the HotSpot VM implementation must be
+ * updated to match the semantics of the annotated method.</li>
+ * <li>For some annotated methods, the corresponding intrinsic may omit some low-level
+ * checks that would be performed as a matter of course if the intrinsic is implemented
+ * using Java bytecodes. This is because individual Java bytecodes implicitly check
+ * for exceptions like {@code NullPointerException} and {@code ArrayStoreException}.
+ * If such a method is replaced by an intrinsic coded in assembly language, any
+ * checks performed as a matter of normal bytecode operation must be performed
+ * before entry into the assembly code. These checks must be performed, as
+ * appropriate, on all arguments to the intrinsic, and on other values (if any) obtained
+ * by the intrinsic through those arguments. The checks may be deduced by inspecting
+ * the non-intrinsic Java code for the method, and determining exactly which exceptions
+ * may be thrown by the code, including undeclared implicit {@code RuntimeException}s.
+ * Therefore, depending on the data accesses performed by the intrinsic,
+ * the checks may include:
+ *
+ * <ul>
+ * <li>null checks on references</li>
+ * <li>range checks on primitive values used as array indexes</li>
+ * <li>other validity checks on primitive values (e.g., for divide-by-zero conditions)</li>
+ * <li>store checks on reference values stored into arrays</li>
+ * <li>array length checks on arrays indexed from within the intrinsic</li>
+ * <li>reference casts (when formal parameters are {@code Object} or some other weak type)</li>
+ * </ul>
+ *
+ * </li>
+ *
+ * <li>Note that the receiver value ({@code this}) is passed as a extra argument
+ * to all non-static methods. If a non-static method is an intrinsic, the receiver
+ * value does not need a null check, but (as stated above) any values loaded by the
+ * intrinsic from object fields must also be checked. As a matter of clarity, it is
+ * better to make intrinisics be static methods, to make the dependency on {@code this}
+ * clear. Also, it is better to explicitly load all required values from object
+ * fields before entering the intrinsic code, and pass those values as explicit arguments.
+ * First, this may be necessary for null checks (or other checks). Second, if the
+ * intrinsic reloads the values from fields and operates on those without checks,
+ * race conditions may be able to introduce unchecked invalid values into the intrinsic.
+ * If the intrinsic needs to store a value back to an object field, that value should be
+ * returned explicitly from the intrinsic; if there are multiple return values, coders
+ * should consider buffering them in an array. Removing field access from intrinsics
+ * not only clarifies the interface with between the JVM and JDK; it also helps decouple
+ * the HotSpot and JDK implementations, since if JDK code before and after the intrinsic
+ * manages all field accesses, then intrinsics can be coded to be agnostic of object
+ * layouts.</li>
+ *
+ * Maintainers of the HotSpot VM must consider the following when modifying
+ * intrinsics.
+ *
+ * <ul>
+ * <li>When adding a new intrinsic, make sure that the corresponding method
+ * in the Java libraries is annotated with {@code @HotSpotIntrinsicCandidate}
+ * and that all possible call sequences that result in calling the intrinsic contain
+ * the checks omitted by the intrinsic (if any).</li>
+ * <li>When modifying an existing intrinsic, the Java libraries must be updated
+ * to match the semantics of the intrinsic and to execute all checks omitted
+ * by the intrinsic (if any).</li>
+ * </ul>
+ *
+ * Persons not directly involved with maintaining the Java libraries or the
+ * HotSpot VM can safely ignore the fact that a method is annotated with
+ * {@code @HotSpotIntrinsicCandidate}.
+ *
+ * The HotSpot VM defines (internally) a list of intrinsics. Not all intrinsic
+ * are available on all platforms supported by the HotSpot VM. Furthermore,
+ * the availability of an intrinsic on a given platform depends on the
+ * configuration of the HotSpot VM (e.g., the set of VM flags enabled).
+ * Therefore, annotating a method with {@code @HotSpotIntrinsicCandidate} does
+ * not guarantee that the marked method is intrinsified by the HotSpot VM.
+ *
+ * If the {@code CheckIntrinsics} VM flag is enabled, the HotSpot VM checks
+ * (when loading a class) that (1) all methods of that class that are also on
+ * the VM's list of intrinsics are annotated with {@code @HotSpotIntrinsicCandidate}
+ * and that (2) for all methods of that class annotated with
+ * {@code @HotSpotIntrinsicCandidate} there is an intrinsic in the list.
+ *
+ * @since 9
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+public @interface HotSpotIntrinsicCandidate {
+}
diff --git a/ojluni/src/main/java/jdk/internal/misc/Unsafe.java b/ojluni/src/main/java/jdk/internal/misc/Unsafe.java
index c6a350b..c7ff084 100644
--- a/ojluni/src/main/java/jdk/internal/misc/Unsafe.java
+++ b/ojluni/src/main/java/jdk/internal/misc/Unsafe.java
@@ -26,6 +26,7 @@
package jdk.internal.misc;
import dalvik.annotation.optimization.FastNative;
+import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.Reflection;
import java.lang.reflect.Field;
@@ -129,6 +130,42 @@
return getArrayBaseOffsetForComponentType(component);
}
+ /** The value of {@code arrayBaseOffset(boolean[].class)} */
+ public static final int ARRAY_BOOLEAN_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(boolean[].class);
+
+ /** The value of {@code arrayBaseOffset(byte[].class)} */
+ public static final int ARRAY_BYTE_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(byte[].class);
+
+ /** The value of {@code arrayBaseOffset(short[].class)} */
+ public static final int ARRAY_SHORT_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(short[].class);
+
+ /** The value of {@code arrayBaseOffset(char[].class)} */
+ public static final int ARRAY_CHAR_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(char[].class);
+
+ /** The value of {@code arrayBaseOffset(int[].class)} */
+ public static final int ARRAY_INT_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(int[].class);
+
+ /** The value of {@code arrayBaseOffset(long[].class)} */
+ public static final int ARRAY_LONG_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(long[].class);
+
+ /** The value of {@code arrayBaseOffset(float[].class)} */
+ public static final int ARRAY_FLOAT_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(float[].class);
+
+ /** The value of {@code arrayBaseOffset(double[].class)} */
+ public static final int ARRAY_DOUBLE_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(double[].class);
+
+ /** The value of {@code arrayBaseOffset(Object[].class)} */
+ public static final int ARRAY_OBJECT_BASE_OFFSET
+ = theUnsafe.arrayBaseOffset(Object[].class);
+
/**
* Gets the size of each element of the given array class.
*
@@ -143,12 +180,163 @@
return getArrayIndexScaleForComponentType(component);
}
+ /** The value of {@code arrayIndexScale(boolean[].class)} */
+ public static final int ARRAY_BOOLEAN_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(boolean[].class);
+
+ /** The value of {@code arrayIndexScale(byte[].class)} */
+ public static final int ARRAY_BYTE_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(byte[].class);
+
+ /** The value of {@code arrayIndexScale(short[].class)} */
+ public static final int ARRAY_SHORT_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(short[].class);
+
+ /** The value of {@code arrayIndexScale(char[].class)} */
+ public static final int ARRAY_CHAR_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(char[].class);
+
+ /** The value of {@code arrayIndexScale(int[].class)} */
+ public static final int ARRAY_INT_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(int[].class);
+
+ /** The value of {@code arrayIndexScale(long[].class)} */
+ public static final int ARRAY_LONG_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(long[].class);
+
+ /** The value of {@code arrayIndexScale(float[].class)} */
+ public static final int ARRAY_FLOAT_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(float[].class);
+
+ /** The value of {@code arrayIndexScale(double[].class)} */
+ public static final int ARRAY_DOUBLE_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(double[].class);
+
+ /** The value of {@code arrayIndexScale(Object[].class)} */
+ public static final int ARRAY_OBJECT_INDEX_SCALE
+ = theUnsafe.arrayIndexScale(Object[].class);
+
@FastNative
private static native int getArrayBaseOffsetForComponentType(Class component_class);
@FastNative
private static native int getArrayIndexScaleForComponentType(Class component_class);
/**
+ * Fetches a value at some byte offset into a given Java object.
+ * More specifically, fetches a value within the given object
+ * <code>o</code> at the given offset, or (if <code>o</code> is
+ * null) from the memory address whose numerical value is the
+ * given offset. <p>
+ *
+ * The specification of this method is the same as {@link
+ * #getLong(Object, long)} except that the offset does not need to
+ * have been obtained from {@link #objectFieldOffset} on the
+ * {@link java.lang.reflect.Field} of some Java field. The value
+ * in memory is raw data, and need not correspond to any Java
+ * variable. Unless <code>o</code> is null, the value accessed
+ * must be entirely within the allocated object. The endianness
+ * of the value in memory is the endianness of the native platform.
+ *
+ * <p> The read will be atomic with respect to the largest power
+ * of two that divides the GCD of the offset and the storage size.
+ * For example, getLongUnaligned will make atomic reads of 2-, 4-,
+ * or 8-byte storage units if the offset is zero mod 2, 4, or 8,
+ * respectively. There are no other guarantees of atomicity.
+ * <p>
+ * 8-byte atomicity is only guaranteed on platforms on which
+ * support atomic accesses to longs.
+ *
+ * @param o Java heap object in which the value resides, if any, else
+ * null
+ * @param offset The offset in bytes from the start of the object
+ * @return the value fetched from the indicated object
+ * @throws RuntimeException No defined exceptions are thrown, not even
+ * {@link NullPointerException}
+ * @since 9
+ */
+ public final long getLongUnaligned(Object o, long offset) {
+ if ((offset & 7) == 0) {
+ return getLong(o, offset);
+ } else if ((offset & 3) == 0) {
+ return makeLong(getInt(o, offset),
+ getInt(o, offset + 4));
+ } else if ((offset & 1) == 0) {
+ return makeLong(getShort(o, offset),
+ getShort(o, offset + 2),
+ getShort(o, offset + 4),
+ getShort(o, offset + 6));
+ } else {
+ return makeLong(getByte(o, offset),
+ getByte(o, offset + 1),
+ getByte(o, offset + 2),
+ getByte(o, offset + 3),
+ getByte(o, offset + 4),
+ getByte(o, offset + 5),
+ getByte(o, offset + 6),
+ getByte(o, offset + 7));
+ }
+ }
+
+ /** @see #getLongUnaligned(Object, long) */
+ public final int getIntUnaligned(Object o, long offset) {
+ if ((offset & 3) == 0) {
+ return getInt(o, offset);
+ } else if ((offset & 1) == 0) {
+ return makeInt(getShort(o, offset),
+ getShort(o, offset + 2));
+ } else {
+ return makeInt(getByte(o, offset),
+ getByte(o, offset + 1),
+ getByte(o, offset + 2),
+ getByte(o, offset + 3));
+ }
+ }
+
+ // These methods construct integers from bytes. The byte ordering
+ // is the native endianness of this platform.
+ private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
+ return ((toUnsignedLong(i0))
+ | (toUnsignedLong(i1) << 8)
+ | (toUnsignedLong(i2) << 16)
+ | (toUnsignedLong(i3) << 24)
+ | (toUnsignedLong(i4) << 32)
+ | (toUnsignedLong(i5) << 40)
+ | (toUnsignedLong(i6) << 48)
+ | (toUnsignedLong(i7) << 56));
+ }
+ private static long makeLong(short i0, short i1, short i2, short i3) {
+ return ((toUnsignedLong(i0))
+ | (toUnsignedLong(i1) << 16)
+ | (toUnsignedLong(i2) << 32)
+ | (toUnsignedLong(i3) << 48));
+ }
+ private static long makeLong(int i0, int i1) {
+ return (toUnsignedLong(i0))
+ | (toUnsignedLong(i1) << 32);
+ }
+ private static int makeInt(short i0, short i1) {
+ return (toUnsignedInt(i0))
+ | (toUnsignedInt(i1) << 16);
+ }
+ private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
+ return ((toUnsignedInt(i0))
+ | (toUnsignedInt(i1) << 8)
+ | (toUnsignedInt(i2) << 16)
+ | (toUnsignedInt(i3) << 24));
+ }
+ private static short makeShort(byte i0, byte i1) {
+ return (short)((toUnsignedInt(i0))
+ | (toUnsignedInt(i1) << 8));
+ }
+
+ // Zero-extend an integer
+ private static int toUnsignedInt(byte n) { return n & 0xff; }
+ private static int toUnsignedInt(short n) { return n & 0xffff; }
+ private static long toUnsignedLong(byte n) { return n & 0xffL; }
+ private static long toUnsignedLong(short n) { return n & 0xffffL; }
+ private static long toUnsignedLong(int n) { return n & 0xffffffffL; }
+
+ /**
* Performs a compare-and-set operation on an {@code int}
* field within the given object.
*
@@ -722,7 +910,7 @@
*
* @return {@code true} if successful
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public final native boolean compareAndSetInt(Object o, long offset,
int expected,
@@ -737,7 +925,7 @@
*
* @return {@code true} if successful
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public final native boolean compareAndSetLong(Object o, long offset,
long expected,
@@ -752,7 +940,7 @@
*
* @return {@code true} if successful
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public final native boolean compareAndSetObject(Object o, long offset,
Object expected,
@@ -772,7 +960,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
@@ -792,7 +980,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {
long v;
do {
@@ -812,7 +1000,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
do {
@@ -832,7 +1020,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final long getAndSetLong(Object o, long offset, long newValue) {
long v;
do {
@@ -852,7 +1040,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final Object getAndSetObject(Object o, long offset, Object newValue) {
Object v;
do {
@@ -862,37 +1050,37 @@
}
/** Release version of {@link #putIntVolatile(Object, long, int)} */
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final void putIntRelease(Object o, long offset, int x) {
putIntVolatile(o, offset, x);
}
/** Acquire version of {@link #getIntVolatile(Object, long)} */
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final int getIntAcquire(Object o, long offset) {
return getIntVolatile(o, offset);
}
/** Release version of {@link #putLongVolatile(Object, long, long)} */
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final void putLongRelease(Object o, long offset, long x) {
putLongVolatile(o, offset, x);
}
/** Acquire version of {@link #getLongVolatile(Object, long)} */
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final long getLongAcquire(Object o, long offset) {
return getLongVolatile(o, offset);
}
/** Release version of {@link #putObjectVolatile(Object, long, Object)} */
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final void putObjectRelease(Object o, long offset, Object x) {
putObjectVolatile(o, offset, x);
}
/** Acquire version of {@link #getObjectVolatile(Object, long)} */
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final Object getObjectAcquire(Object o, long offset) {
return getObjectVolatile(o, offset);
}
@@ -909,7 +1097,7 @@
* provide a LoadLoad barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public native void loadFence();
@@ -925,7 +1113,7 @@
* provide a StoreStore barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public native void storeFence();
@@ -938,7 +1126,7 @@
* Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public native void fullFence();
diff --git a/ojluni/src/main/java/jdk/internal/util/ArraysSupport.java b/ojluni/src/main/java/jdk/internal/util/ArraysSupport.java
new file mode 100644
index 0000000..50ea4f0
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/util/ArraysSupport.java
@@ -0,0 +1,575 @@
+/*
+ * 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 jdk.internal.util;
+
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Utility methods to find a mismatch between two primitive arrays.
+ *
+ * <p>Array equality and lexicographical comparison can be built on top of
+ * array mismatch functionality.
+ *
+ * <p>The mismatch method implementation, {@link #vectorizedMismatch}, leverages
+ * vector-based techniques to access and compare the contents of two arrays.
+ * The Java implementation uses {@code Unsafe.getLongUnaligned} to access the
+ * content of an array, thus access is supported on platforms that do not
+ * support unaligned access. For a byte[] array, 8 bytes (64 bits) can be
+ * accessed and compared as a unit rather than individually, which increases
+ * the performance when the method is compiled by the HotSpot VM. On supported
+ * platforms the mismatch implementation is intrinsified to leverage SIMD
+ * instructions. So for a byte[] array, 16 bytes (128 bits), 32 bytes
+ * (256 bits), and perhaps in the future even 64 bytes (512 bits), platform
+ * permitting, can be accessed and compared as a unit, which further increases
+ * the performance over the Java implementation.
+ *
+ * <p>None of the mismatch methods perform array bounds checks. It is the
+ * responsibility of the caller (direct or otherwise) to perform such checks
+ * before calling this method.
+ */
+public class ArraysSupport {
+ static final Unsafe U = Unsafe.getUnsafe();
+
+ // Android-changed: Android is little endian.
+ private static final boolean BIG_ENDIAN = false;
+
+ public static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);
+ public static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);
+ public static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);
+ public static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);
+ public static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);
+ public static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);
+ public static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);
+ public static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+
+ private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE);
+
+ private static int exactLog2(int scale) {
+ if ((scale & (scale - 1)) != 0)
+ throw new Error("data type scale not a power of two");
+ return Integer.numberOfTrailingZeros(scale);
+ }
+
+ private ArraysSupport() {}
+
+ /**
+ * Find the relative index of the first mismatching pair of elements in two
+ * primitive arrays of the same component type. Pairs of elements will be
+ * tested in order relative to given offsets into both arrays.
+ *
+ * <p>This method does not perform type checks or bounds checks. It is the
+ * responsibility of the caller to perform such checks before calling this
+ * method.
+ *
+ * <p>The given offsets, in bytes, need not be aligned according to the
+ * given log<sub>2</sub> size the array elements. More specifically, an
+ * offset modulus the size need not be zero.
+ *
+ * @param a the first array to be tested for mismatch, or {@code null} for
+ * direct memory access
+ * @param aOffset the relative offset, in bytes, from the base address of
+ * the first array to test from, otherwise if the first array is
+ * {@code null}, an absolute address pointing to the first element to test.
+ * @param b the second array to be tested for mismatch, or {@code null} for
+ * direct memory access
+ * @param bOffset the relative offset, in bytes, from the base address of
+ * the second array to test from, otherwise if the second array is
+ * {@code null}, an absolute address pointing to the first element to test.
+ * @param length the number of array elements to test
+ * @param log2ArrayIndexScale log<sub>2</sub> of the array index scale, that
+ * corresponds to the size, in bytes, of an array element.
+ * @return if a mismatch is found a relative index, between 0 (inclusive)
+ * and {@code length} (exclusive), of the first mismatching pair of elements
+ * in the two arrays. Otherwise, if a mismatch is not found the bitwise
+ * compliment of the number of remaining pairs of elements to be checked in
+ * the tail of the two arrays.
+ */
+ @HotSpotIntrinsicCandidate
+ public static int vectorizedMismatch(Object a, long aOffset,
+ Object b, long bOffset,
+ int length,
+ int log2ArrayIndexScale) {
+ // assert a.getClass().isArray();
+ // assert b.getClass().isArray();
+ // assert 0 <= length <= sizeOf(a)
+ // assert 0 <= length <= sizeOf(b)
+ // assert 0 <= log2ArrayIndexScale <= 3
+
+ int log2ValuesPerWidth = LOG2_ARRAY_LONG_INDEX_SCALE - log2ArrayIndexScale;
+ int wi = 0;
+ for (; wi < length >> log2ValuesPerWidth; wi++) {
+ long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
+ long av = U.getLongUnaligned(a, aOffset + bi);
+ long bv = U.getLongUnaligned(b, bOffset + bi);
+ if (av != bv) {
+ long x = av ^ bv;
+ int o = BIG_ENDIAN
+ ? Long.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
+ : Long.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
+ return (wi << log2ValuesPerWidth) + o;
+ }
+ }
+
+ // Calculate the tail of remaining elements to check
+ int tail = length - (wi << log2ValuesPerWidth);
+
+ if (log2ArrayIndexScale < LOG2_ARRAY_INT_INDEX_SCALE) {
+ int wordTail = 1 << (LOG2_ARRAY_INT_INDEX_SCALE - log2ArrayIndexScale);
+ // Handle 4 bytes or 2 chars in the tail using int width
+ if (tail >= wordTail) {
+ long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
+ int av = U.getIntUnaligned(a, aOffset + bi);
+ int bv = U.getIntUnaligned(b, bOffset + bi);
+ if (av != bv) {
+ int x = av ^ bv;
+ int o = BIG_ENDIAN
+ ? Integer.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
+ : Integer.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
+ return (wi << log2ValuesPerWidth) + o;
+ }
+ tail -= wordTail;
+ }
+ return ~tail;
+ }
+ else {
+ return ~tail;
+ }
+ }
+
+ // Booleans
+ // Each boolean element takes up one byte
+
+ public static int mismatch(boolean[] a,
+ boolean[] b,
+ int length) {
+ int i = 0;
+ if (length > 7) {
+ if (a[0] != b[0])
+ return 0;
+ i = vectorizedMismatch(
+ a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
+ b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
+ length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[i] != b[i])
+ return i;
+ }
+ return -1;
+ }
+
+ public static int mismatch(boolean[] a, int aFromIndex,
+ boolean[] b, int bFromIndex,
+ int length) {
+ int i = 0;
+ if (length > 7) {
+ if (a[aFromIndex] != b[bFromIndex])
+ return 0;
+ int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex;
+ int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex;
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[aFromIndex + i] != b[bFromIndex + i])
+ return i;
+ }
+ return -1;
+ }
+
+
+ // Bytes
+
+ /**
+ * Find the index of a mismatch between two arrays.
+ *
+ * <p>This method does not perform bounds checks. It is the responsibility
+ * of the caller to perform such bounds checks before calling this method.
+ *
+ * @param a the first array to be tested for a mismatch
+ * @param b the second array to be tested for a mismatch
+ * @param length the number of bytes from each array to check
+ * @return the index of a mismatch between the two arrays, otherwise -1 if
+ * no mismatch. The index will be within the range of (inclusive) 0 to
+ * (exclusive) the smaller of the two array lengths.
+ */
+ public static int mismatch(byte[] a,
+ byte[] b,
+ int length) {
+ // ISSUE: defer to index receiving methods if performance is good
+ // assert length <= a.length
+ // assert length <= b.length
+
+ int i = 0;
+ if (length > 7) {
+ if (a[0] != b[0])
+ return 0;
+ i = vectorizedMismatch(
+ a, Unsafe.ARRAY_BYTE_BASE_OFFSET,
+ b, Unsafe.ARRAY_BYTE_BASE_OFFSET,
+ length, LOG2_ARRAY_BYTE_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ // Align to tail
+ i = length - ~i;
+// assert i >= 0 && i <= 7;
+ }
+ // Tail < 8 bytes
+ for (; i < length; i++) {
+ if (a[i] != b[i])
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Find the relative index of a mismatch between two arrays starting from
+ * given indexes.
+ *
+ * <p>This method does not perform bounds checks. It is the responsibility
+ * of the caller to perform such bounds checks before calling this method.
+ *
+ * @param a the first array to be tested for a mismatch
+ * @param aFromIndex the index of the first element (inclusive) in the first
+ * array to be compared
+ * @param b the second array to be tested for a mismatch
+ * @param bFromIndex the index of the first element (inclusive) in the
+ * second array to be compared
+ * @param length the number of bytes from each array to check
+ * @return the relative index of a mismatch between the two arrays,
+ * otherwise -1 if no mismatch. The index will be within the range of
+ * (inclusive) 0 to (exclusive) the smaller of the two array bounds.
+ */
+ public static int mismatch(byte[] a, int aFromIndex,
+ byte[] b, int bFromIndex,
+ int length) {
+ // assert 0 <= aFromIndex < a.length
+ // assert 0 <= aFromIndex + length <= a.length
+ // assert 0 <= bFromIndex < b.length
+ // assert 0 <= bFromIndex + length <= b.length
+ // assert length >= 0
+
+ int i = 0;
+ if (length > 7) {
+ if (a[aFromIndex] != b[bFromIndex])
+ return 0;
+ int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex;
+ int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex;
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_BYTE_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[aFromIndex + i] != b[bFromIndex + i])
+ return i;
+ }
+ return -1;
+ }
+
+
+ // Chars
+
+ public static int mismatch(char[] a,
+ char[] b,
+ int length) {
+ int i = 0;
+ if (length > 3) {
+ if (a[0] != b[0])
+ return 0;
+ i = vectorizedMismatch(
+ a, Unsafe.ARRAY_CHAR_BASE_OFFSET,
+ b, Unsafe.ARRAY_CHAR_BASE_OFFSET,
+ length, LOG2_ARRAY_CHAR_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[i] != b[i])
+ return i;
+ }
+ return -1;
+ }
+
+ public static int mismatch(char[] a, int aFromIndex,
+ char[] b, int bFromIndex,
+ int length) {
+ int i = 0;
+ if (length > 3) {
+ if (a[aFromIndex] != b[bFromIndex])
+ return 0;
+ int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
+ int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_CHAR_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[aFromIndex + i] != b[bFromIndex + i])
+ return i;
+ }
+ return -1;
+ }
+
+
+ // Shorts
+
+ public static int mismatch(short[] a,
+ short[] b,
+ int length) {
+ int i = 0;
+ if (length > 3) {
+ if (a[0] != b[0])
+ return 0;
+ i = vectorizedMismatch(
+ a, Unsafe.ARRAY_SHORT_BASE_OFFSET,
+ b, Unsafe.ARRAY_SHORT_BASE_OFFSET,
+ length, LOG2_ARRAY_SHORT_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[i] != b[i])
+ return i;
+ }
+ return -1;
+ }
+
+ public static int mismatch(short[] a, int aFromIndex,
+ short[] b, int bFromIndex,
+ int length) {
+ int i = 0;
+ if (length > 3) {
+ if (a[aFromIndex] != b[bFromIndex])
+ return 0;
+ int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
+ int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_SHORT_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[aFromIndex + i] != b[bFromIndex + i])
+ return i;
+ }
+ return -1;
+ }
+
+
+ // Ints
+
+ public static int mismatch(int[] a,
+ int[] b,
+ int length) {
+ int i = 0;
+ if (length > 1) {
+ if (a[0] != b[0])
+ return 0;
+ i = vectorizedMismatch(
+ a, Unsafe.ARRAY_INT_BASE_OFFSET,
+ b, Unsafe.ARRAY_INT_BASE_OFFSET,
+ length, LOG2_ARRAY_INT_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[i] != b[i])
+ return i;
+ }
+ return -1;
+ }
+
+ public static int mismatch(int[] a, int aFromIndex,
+ int[] b, int bFromIndex,
+ int length) {
+ int i = 0;
+ if (length > 1) {
+ if (a[aFromIndex] != b[bFromIndex])
+ return 0;
+ int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
+ int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_INT_INDEX_SCALE);
+ if (i >= 0)
+ return i;
+ i = length - ~i;
+ }
+ for (; i < length; i++) {
+ if (a[aFromIndex + i] != b[bFromIndex + i])
+ return i;
+ }
+ return -1;
+ }
+
+
+ // Floats
+
+ public static int mismatch(float[] a,
+ float[] b,
+ int length) {
+ return mismatch(a, 0, b, 0, length);
+ }
+
+ public static int mismatch(float[] a, int aFromIndex,
+ float[] b, int bFromIndex,
+ int length) {
+ int i = 0;
+ if (length > 1) {
+ if (Float.floatToRawIntBits(a[aFromIndex]) == Float.floatToRawIntBits(b[bFromIndex])) {
+ int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
+ int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_FLOAT_INDEX_SCALE);
+ }
+ // Mismatched
+ if (i >= 0) {
+ // Check if mismatch is not associated with two NaN values
+ if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i]))
+ return i;
+
+ // Mismatch on two different NaN values that are normalized to match
+ // Fall back to slow mechanism
+ // ISSUE: Consider looping over vectorizedMismatch adjusting ranges
+ // However, requires that returned value be relative to input ranges
+ i++;
+ }
+ // Matched
+ else {
+ i = length - ~i;
+ }
+ }
+ for (; i < length; i++) {
+ if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i]))
+ return i;
+ }
+ return -1;
+ }
+
+ // 64 bit sizes
+
+ // Long
+
+ public static int mismatch(long[] a,
+ long[] b,
+ int length) {
+ if (length == 0) {
+ return -1;
+ }
+ if (a[0] != b[0])
+ return 0;
+ int i = vectorizedMismatch(
+ a, Unsafe.ARRAY_LONG_BASE_OFFSET,
+ b, Unsafe.ARRAY_LONG_BASE_OFFSET,
+ length, LOG2_ARRAY_LONG_INDEX_SCALE);
+ return i >= 0 ? i : -1;
+ }
+
+ public static int mismatch(long[] a, int aFromIndex,
+ long[] b, int bFromIndex,
+ int length) {
+ if (length == 0) {
+ return -1;
+ }
+ if (a[aFromIndex] != b[bFromIndex])
+ return 0;
+ int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
+ int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
+ int i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_LONG_INDEX_SCALE);
+ return i >= 0 ? i : -1;
+ }
+
+
+ // Double
+
+ public static int mismatch(double[] a,
+ double[] b,
+ int length) {
+ return mismatch(a, 0, b, 0, length);
+ }
+
+ public static int mismatch(double[] a, int aFromIndex,
+ double[] b, int bFromIndex,
+ int length) {
+ if (length == 0) {
+ return -1;
+ }
+ int i = 0;
+ if (Double.doubleToRawLongBits(a[aFromIndex]) == Double.doubleToRawLongBits(b[bFromIndex])) {
+ int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
+ int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
+ i = vectorizedMismatch(
+ a, aOffset,
+ b, bOffset,
+ length, LOG2_ARRAY_DOUBLE_INDEX_SCALE);
+ }
+ if (i >= 0) {
+ // Check if mismatch is not associated with two NaN values
+ if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i]))
+ return i;
+
+ // Mismatch on two different NaN values that are normalized to match
+ // Fall back to slow mechanism
+ // ISSUE: Consider looping over vectorizedMismatch adjusting ranges
+ // However, requires that returned value be relative to input ranges
+ i++;
+ for (; i < length; i++) {
+ if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i]))
+ return i;
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/ojluni/src/main/java/jdk/internal/util/Preconditions.java b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
index 0e91afd..cb1b748 100644
--- a/ojluni/src/main/java/jdk/internal/util/Preconditions.java
+++ b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
@@ -24,6 +24,8 @@
*/
package jdk.internal.util;
+import jdk.internal.HotSpotIntrinsicCandidate;
+
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -238,8 +240,7 @@
* length is a non-negative value (such as that of an array length or from
* the upper bound of a loop)
*/
- // Android-removed: @HotSpotIntrinsicCandidate not present on Android yet (could reconsider).
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public static <X extends RuntimeException>
int checkIndex(int index, int length,
BiFunction<String, List<Integer>, X> oobef) {
diff --git a/ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java b/ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java
new file mode 100644
index 0000000..fd616cc
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, 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.vm.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// Android-note: Contended-specific implementation notes not relevant for Android.
+/**
+ * <p>An annotation expressing that objects and/or their fields are
+ * expected to encounter memory contention, generally in the form of
+ * "false sharing". This annotation serves as a hint that such objects
+ * and fields should reside in locations isolated from those of other
+ * objects or fields. Susceptibility to memory contention is a
+ * property of the intended usages of objects and fields, not their
+ * types or qualifiers. The effects of this annotation will nearly
+ * always add significant space overhead to objects. The use of
+ * {@code @Contended} is warranted only when the performance impact of
+ * this time/space tradeoff is intrinsically worthwhile; for example,
+ * in concurrent contexts in which each instance of the annotated
+ * class is often accessed by a different thread.
+ *
+ * <p>A {@code @Contended} field annotation may optionally include a
+ * <i>contention group</i> tag. A contention group defines a set of one
+ * or more fields that collectively must be isolated from all other
+ * contention groups. The fields in the same contention group may not be
+ * pairwise isolated. With no contention group tag (or with the default
+ * empty tag: "") each {@code @Contended} field resides in its own
+ * <i>distinct</i> and <i>anonymous</i> contention group.
+ *
+ * <p>When the annotation is used at the class level, the effect is
+ * equivalent to grouping all the declared fields not already having the
+ * {@code @Contended} annotation into the same anonymous group.
+ * With the class level annotation, implementations may choose different
+ * isolation techniques, such as isolating the entire object, rather than
+ * isolating distinct fields. A contention group tag has no meaning
+ * in a class level {@code @Contended} annotation, and is ignored.
+ *
+ * <p>The class level {@code @Contended} annotation is not inherited and has
+ * no effect on the fields declared in any sub-classes. The effects of all
+ * {@code @Contended} annotations, however, remain in force for all
+ * subclass instances, providing isolation of all the defined contention
+ * groups. Contention group tags are not inherited, and the same tag used
+ * in a superclass and subclass, represent distinct contention groups.
+ *
+ * @since 1.8
+ */
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.FIELD, ElementType.TYPE})
+public @interface Contended {
+
+ /**
+ * The (optional) contention group tag.
+ * This tag is only meaningful for field level annotations.
+ *
+ * @return contention group tag.
+ */
+ String value() default "";
+}
diff --git a/ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java b/ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java
new file mode 100644
index 0000000..91ea865
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 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
+ * 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.vm.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// Android-note: ReservedStackAccess-specific implementation not available on Android.
+/**
+ * <p>An annotation expressing that a method is especially sensitive
+ * to stack overflows. This is a hint the JVM can use to grant access to
+ * extra stack space when executing this code if such feature is supported
+ * by the JVM. The JVM is free to ignore this annotation.
+ *
+ * A possible way for the JVM to improve the execution context for methods
+ * with this annotation is to reserve part of the thread's execution stack
+ * for them. Access to this section of the stack would be denied by default
+ * but could be granted if the JVM detects a possible stack overflow and
+ * the thread's call stack includes at least one annotated method. Even if
+ * access to this reserved area has been granted, the JVM might decide to
+ * throw a delayed StackOverflowError when the thread exits the annotated
+ * method.
+ *
+ * @since 9
+ */
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface ReservedStackAccess { }
+
diff --git a/ojluni/src/main/java/sun/misc/Unsafe.java b/ojluni/src/main/java/sun/misc/Unsafe.java
index e538b73..59d8df5 100644
--- a/ojluni/src/main/java/sun/misc/Unsafe.java
+++ b/ojluni/src/main/java/sun/misc/Unsafe.java
@@ -26,6 +26,7 @@
package sun.misc;
import dalvik.annotation.optimization.FastNative;
+import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.Reflection;
import java.lang.reflect.Field;
@@ -698,7 +699,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
@@ -718,7 +719,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {
long v;
do {
@@ -738,7 +739,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
do {
@@ -758,7 +759,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final long getAndSetLong(Object o, long offset, long newValue) {
long v;
do {
@@ -778,7 +779,7 @@
* @return the previous value
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
public final Object getAndSetObject(Object o, long offset, Object newValue) {
Object v;
do {
@@ -800,7 +801,7 @@
* provide a LoadLoad barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public native void loadFence();
@@ -816,7 +817,7 @@
* provide a StoreStore barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public native void storeFence();
@@ -829,7 +830,7 @@
* Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
* @since 1.8
*/
- // @HotSpotIntrinsicCandidate
+ @HotSpotIntrinsicCandidate
@FastNative
public native void fullFence();
}
diff --git a/ojluni/src/main/java/sun/security/util/HexDumpEncoder.java b/ojluni/src/main/java/sun/security/util/HexDumpEncoder.java
new file mode 100644
index 0000000..9726a4f
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/util/HexDumpEncoder.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1995, 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
+ * 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.security.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This class encodes a buffer into the classic: "Hexadecimal Dump" format of
+ * the past. It is useful for analyzing the contents of binary buffers.
+ * The format produced is as follows:
+ * <pre>
+ * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................
+ * </pre>
+ * Where xxxx is the offset into the buffer in 16 byte chunks, followed
+ * by ascii coded hexadecimal bytes followed by the ASCII representation of
+ * the bytes or '.' if they are not valid bytes.
+ *
+ * @author Chuck McManis
+ */
+
+public class HexDumpEncoder {
+
+ private int offset;
+ private int thisLineLength;
+ private int currentByte;
+ private byte thisLine[] = new byte[16];
+
+ static void hexDigit(PrintStream p, byte x) {
+ char c;
+
+ c = (char) ((x >> 4) & 0xf);
+ if (c > 9)
+ c = (char) ((c-10) + 'A');
+ else
+ c = (char)(c + '0');
+ p.write(c);
+ c = (char) (x & 0xf);
+ if (c > 9)
+ c = (char)((c-10) + 'A');
+ else
+ c = (char)(c + '0');
+ p.write(c);
+ }
+
+ protected int bytesPerAtom() {
+ return (1);
+ }
+
+ protected int bytesPerLine() {
+ return (16);
+ }
+
+ protected void encodeBufferPrefix(OutputStream o) throws IOException {
+ offset = 0;
+ pStream = new PrintStream(o);
+ }
+
+ protected void encodeLinePrefix(OutputStream o, int len) throws IOException {
+ hexDigit(pStream, (byte)((offset >>> 8) & 0xff));
+ hexDigit(pStream, (byte)(offset & 0xff));
+ pStream.print(": ");
+ currentByte = 0;
+ thisLineLength = len;
+ }
+
+ protected void encodeAtom(OutputStream o, byte buf[], int off, int len) throws IOException {
+ thisLine[currentByte] = buf[off];
+ hexDigit(pStream, buf[off]);
+ pStream.print(" ");
+ currentByte++;
+ if (currentByte == 8)
+ pStream.print(" ");
+ }
+
+ protected void encodeLineSuffix(OutputStream o) throws IOException {
+ if (thisLineLength < 16) {
+ for (int i = thisLineLength; i < 16; i++) {
+ pStream.print(" ");
+ if (i == 7)
+ pStream.print(" ");
+ }
+ }
+ pStream.print(" ");
+ for (int i = 0; i < thisLineLength; i++) {
+ if ((thisLine[i] < ' ') || (thisLine[i] > 'z')) {
+ pStream.print(".");
+ } else {
+ pStream.write(thisLine[i]);
+ }
+ }
+ pStream.println();
+ offset += thisLineLength;
+ }
+
+ /** Stream that understands "printing" */
+ protected PrintStream pStream;
+
+ /**
+ * This method works around the bizarre semantics of BufferedInputStream's
+ * read method.
+ */
+ protected int readFully(InputStream in, byte buffer[])
+ throws java.io.IOException {
+ for (int i = 0; i < buffer.length; i++) {
+ int q = in.read();
+ if (q == -1)
+ return i;
+ buffer[i] = (byte)q;
+ }
+ return buffer.length;
+ }
+
+ /**
+ * Encode bytes from the input stream, and write them as text characters
+ * to the output stream. This method will run until it exhausts the
+ * input stream, but does not print the line suffix for a final
+ * line that is shorter than bytesPerLine().
+ */
+ public void encode(InputStream inStream, OutputStream outStream)
+ throws IOException
+ {
+ int j;
+ int numBytes;
+ byte tmpbuffer[] = new byte[bytesPerLine()];
+
+ encodeBufferPrefix(outStream);
+
+ while (true) {
+ numBytes = readFully(inStream, tmpbuffer);
+ if (numBytes == 0) {
+ break;
+ }
+ encodeLinePrefix(outStream, numBytes);
+ for (j = 0; j < numBytes; j += bytesPerAtom()) {
+
+ if ((j + bytesPerAtom()) <= numBytes) {
+ encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+ } else {
+ encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
+ }
+ }
+ if (numBytes < bytesPerLine()) {
+ break;
+ } else {
+ encodeLineSuffix(outStream);
+ }
+ }
+ }
+
+ /**
+ * A 'streamless' version of encode that simply takes a buffer of
+ * bytes and returns a string containing the encoded buffer.
+ */
+ public String encode(byte aBuffer[]) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+ String retVal = null;
+ try {
+ encode(inStream, outStream);
+ // explicit ascii->unicode conversion
+ retVal = outStream.toString("ISO-8859-1");
+ } catch (Exception IOException) {
+ // This should never happen.
+ throw new Error("CharacterEncoder.encode internal error");
+ }
+ return (retVal);
+ }
+
+ /**
+ * Return a byte array from the remaining bytes in this ByteBuffer.
+ * <P>
+ * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+ * <P>
+ * To avoid an extra copy, the implementation will attempt to return the
+ * byte array backing the ByteBuffer. If this is not possible, a
+ * new byte array will be created.
+ */
+ private byte [] getBytes(ByteBuffer bb) {
+ /*
+ * This should never return a BufferOverflowException, as we're
+ * careful to allocate just the right amount.
+ */
+ byte [] buf = null;
+
+ /*
+ * If it has a usable backing byte buffer, use it. Use only
+ * if the array exactly represents the current ByteBuffer.
+ */
+ if (bb.hasArray()) {
+ byte [] tmp = bb.array();
+ if ((tmp.length == bb.capacity()) &&
+ (tmp.length == bb.remaining())) {
+ buf = tmp;
+ bb.position(bb.limit());
+ }
+ }
+
+ if (buf == null) {
+ /*
+ * This class doesn't have a concept of encode(buf, len, off),
+ * so if we have a partial buffer, we must reallocate
+ * space.
+ */
+ buf = new byte[bb.remaining()];
+
+ /*
+ * position() automatically updated
+ */
+ bb.get(buf);
+ }
+
+ return buf;
+ }
+
+ /**
+ * A 'streamless' version of encode that simply takes a ByteBuffer
+ * and returns a string containing the encoded buffer.
+ * <P>
+ * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+ */
+ public String encode(ByteBuffer aBuffer) {
+ byte [] buf = getBytes(aBuffer);
+ return encode(buf);
+ }
+
+ /**
+ * Encode bytes from the input stream, and write them as text characters
+ * to the output stream. This method will run until it exhausts the
+ * input stream. It differs from encode in that it will add the
+ * line at the end of a final line that is shorter than bytesPerLine().
+ */
+ public void encodeBuffer(InputStream inStream, OutputStream outStream)
+ throws IOException
+ {
+ int j;
+ int numBytes;
+ byte tmpbuffer[] = new byte[bytesPerLine()];
+
+ encodeBufferPrefix(outStream);
+
+ while (true) {
+ numBytes = readFully(inStream, tmpbuffer);
+ if (numBytes == 0) {
+ break;
+ }
+ encodeLinePrefix(outStream, numBytes);
+ for (j = 0; j < numBytes; j += bytesPerAtom()) {
+ if ((j + bytesPerAtom()) <= numBytes) {
+ encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+ } else {
+ encodeAtom(outStream, tmpbuffer, j, (numBytes)- j);
+ }
+ }
+ encodeLineSuffix(outStream);
+ if (numBytes < bytesPerLine()) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Encode the buffer in <i>aBuffer</i> and write the encoded
+ * result to the OutputStream <i>aStream</i>.
+ */
+ public void encodeBuffer(byte aBuffer[], OutputStream aStream)
+ throws IOException
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+ encodeBuffer(inStream, aStream);
+ }
+
+ /**
+ * A 'streamless' version of encode that simply takes a buffer of
+ * bytes and returns a string containing the encoded buffer.
+ */
+ public String encodeBuffer(byte aBuffer[]) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+ try {
+ encodeBuffer(inStream, outStream);
+ } catch (Exception IOException) {
+ // This should never happen.
+ throw new Error("CharacterEncoder.encodeBuffer internal error");
+ }
+ return (outStream.toString());
+ }
+
+ /**
+ * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
+ * result to the OutputStream <i>aStream</i>.
+ * <P>
+ * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+ */
+ public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
+ throws IOException
+ {
+ byte [] buf = getBytes(aBuffer);
+ encodeBuffer(buf, aStream);
+ }
+
+}
diff --git a/ojluni/src/main/native/zip_util.c b/ojluni/src/main/native/zip_util.c
index 85ea608..01dcce7 100644
--- a/ojluni/src/main/native/zip_util.c
+++ b/ojluni/src/main/native/zip_util.c
@@ -775,7 +775,7 @@
jzfile *zip = NULL;
/* Clear zip error message */
- // BEGIN: Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
+ // BEGIN Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
/*
if (pmsg != 0) {
*pmsg = NULL;
@@ -806,7 +806,7 @@
} else {
*pmsg = localPmsg;
}
- // END: Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
+ // END Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
return zip;
}
diff --git a/ojluni/src/test/java/io/ByteArrayOutputStream/EncodingTest.java b/ojluni/src/test/java/io/ByteArrayOutputStream/EncodingTest.java
new file mode 100644
index 0000000..34a6b73
--- /dev/null
+++ b/ojluni/src/test/java/io/ByteArrayOutputStream/EncodingTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * 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 test.java.io.ByteArrayOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183743
+ * @summary Test to verify the new overload method with Charset functions the same
+ * as the existing method that takes a charset name.
+ * @run testng EncodingTest
+ */
+public class EncodingTest {
+ /*
+ * DataProvider for the toString method test. Provides the following fields:
+ * byte array, charset name string, charset object
+ */
+ @DataProvider(name = "parameters")
+ public Object[][] getParameters() throws IOException {
+ byte[] data = getData();
+ return new Object[][]{
+ {data, StandardCharsets.UTF_8.name(), StandardCharsets.UTF_8},
+ {data, StandardCharsets.ISO_8859_1.name(), StandardCharsets.ISO_8859_1},
+ };
+ }
+
+ /**
+ * Verifies that the new overload method that takes a Charset is equivalent to
+ * the existing one that takes a charset name.
+ * @param data a byte array
+ * @param csn the charset name
+ * @param charset the charset
+ * @throws Exception if the test fails
+ */
+ @Test(dataProvider = "parameters")
+ public void test(byte[] data, String csn, Charset charset) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(data);
+ String str1 = baos.toString(csn);
+ String str2 = baos.toString(charset);
+ Assert.assertEquals(str1, str2);
+ }
+
+ /*
+ * Returns an array containing a character that's invalid for UTF-8
+ * but valid for ISO-8859-1
+ */
+ byte[] getData() throws IOException {
+ String str1 = "A string that contains ";
+ String str2 = " , an invalid character for UTF-8.";
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(str1.getBytes());
+ baos.write(0xFA);
+ baos.write(str2.getBytes());
+ return baos.toByteArray();
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/FileReader/ConstructorTest.java b/ojluni/src/test/java/io/FileReader/ConstructorTest.java
new file mode 100644
index 0000000..30b5504
--- /dev/null
+++ b/ojluni/src/test/java/io/FileReader/ConstructorTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 test.java.io.FileReader;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183554
+ * @summary Test to verify the new Constructors that take a Charset.
+ * @run testng ConstructorTest
+ */
+public class ConstructorTest {
+ static String USER_DIR = System.getProperty("user.dir", ".");
+
+ public static enum ConstructorType {
+ STRING,
+ FILE
+ }
+
+ static final String TEST_STRING = "abc \u0100 \u0101 \u0555 \u07FD \u07FF";
+ static final int BUFFER_SIZE = 8192;
+
+ @DataProvider(name = "parameters")
+ public Object[][] getParameters() throws IOException {
+ File file1 = new File(USER_DIR, "FileReaderTest1.txt");
+ File file2 = new File(USER_DIR, "FileReaderTest2.txt");
+
+ return new Object[][]{
+ {ConstructorType.STRING, file1, file2, StandardCharsets.UTF_8},
+ {ConstructorType.FILE, file1, file2, StandardCharsets.UTF_8},
+ {ConstructorType.STRING, file1, file2, StandardCharsets.ISO_8859_1},
+ {ConstructorType.FILE, file1, file2, StandardCharsets.ISO_8859_1},
+ };
+ }
+
+ /**
+ * Verifies that the new constructors that take a Charset function the same
+ * as an InputStreamReader on a FileInputStream as was recommended before
+ * this change.
+ *
+ * @param type the type of the constructor
+ * @param file1 file1 to be read with a FileReader
+ * @param file2 file2 to be read with an InputStreamReader
+ * @param charset the charset
+ * @throws IOException
+ */
+ @Test(dataProvider = "parameters")
+ void test(ConstructorType type, File file1, File file2, Charset charset)
+ throws Exception {
+ prepareFile(file1, TEST_STRING, charset);
+ prepareFile(file2, TEST_STRING, charset);
+
+ try (FileReader fr = getFileReader(type, file1, charset);
+ FileInputStream is = new FileInputStream(file2);
+ InputStreamReader isr = new InputStreamReader(is, charset);) {
+ String result1 = readAll(fr, BUFFER_SIZE);
+ String result2 = readAll(isr, BUFFER_SIZE);
+ Assert.assertEquals(result1, result2);
+ }
+ }
+
+ public String readAll(Reader reader, int bufferSize) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ char[] buf = new char[bufferSize];
+ int numRead;
+ while ((numRead = reader.read(buf)) != -1) {
+ if (numRead == buf.length) {
+ sb.append(buf);
+ } else {
+ sb.append(String.valueOf(buf, 0, numRead));
+ }
+ }
+ return sb.toString();
+ }
+
+ /*
+ * Creates a FileReader over the given input file.
+ */
+ FileReader getFileReader(ConstructorType type, File file, Charset charset)
+ throws IOException {
+ switch (type) {
+ case STRING:
+ return new FileReader(file.getPath(), charset);
+ case FILE:
+ return new FileReader(file, charset);
+ }
+
+ return null;
+ }
+
+ void prepareFile(File file, String content, Charset charset) throws IOException {
+ try (FileWriter writer = new FileWriter(file, charset);) {
+ writer.write(content);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/FileWriter/ConstructorTest.java b/ojluni/src/test/java/io/FileWriter/ConstructorTest.java
new file mode 100644
index 0000000..c95ba89
--- /dev/null
+++ b/ojluni/src/test/java/io/FileWriter/ConstructorTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 test.java.io.FileWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183554
+ * @summary Test to verify the new Constructors that take a Charset.
+ * @run testng ConstructorTest
+ */
+public class ConstructorTest {
+
+ public static enum ConstructorType {
+ STRING,
+ FILE,
+ STRING_APPEND,
+ FILE_APPEND
+ }
+
+ static final String TEST_STRING = "abc \u0100 \u0101 \u0555 \u07FD \u07FF";
+ static final int BUFFER_SIZE = 8192;
+
+ @DataProvider(name = "parameters")
+ public Object[][] getParameters() throws IOException {
+ File file1 = File.createTempFile("FileWriterTest1", "txt");
+ File file2 = File.createTempFile("FileWriterTest2", "txt");
+
+ return new Object[][]{
+ {ConstructorType.STRING, file1, file2, StandardCharsets.UTF_8},
+ {ConstructorType.FILE, file1, file2, StandardCharsets.UTF_8},
+ {ConstructorType.STRING_APPEND, file1, file2, StandardCharsets.UTF_8},
+ {ConstructorType.FILE_APPEND, file1, file2, StandardCharsets.UTF_8},
+ {ConstructorType.STRING, file1, file2, StandardCharsets.ISO_8859_1},
+ {ConstructorType.FILE, file1, file2, StandardCharsets.ISO_8859_1},
+ {ConstructorType.STRING_APPEND, file1, file2, StandardCharsets.ISO_8859_1},
+ {ConstructorType.FILE_APPEND, file1, file2, StandardCharsets.ISO_8859_1},
+ };
+ }
+
+ /**
+ * Verifies that the new constructors that take a Charset function the same
+ * as an OutputStreamWriter on a FileOutputStream as was recommended before
+ * this change.
+ *
+ * @param type the type of the constructor
+ * @param file1 file1 to be written with a FileWriter
+ * @param file2 file2 to be written with an OutputStreamWriter
+ * @param charset the charset
+ * @throws IOException
+ */
+ @Test(dataProvider = "parameters")
+ void test(ConstructorType type, File file1, File file2, Charset charset)
+ throws Exception {
+ writeWithFileWriter(type, file1, TEST_STRING, charset);
+ writeWithOutputStreamWriter(type, file2, TEST_STRING, charset);
+
+ try (
+ FileReader r1 = getFileReader(type, file1, charset);
+ FileReader r2 = getFileReader(type, file2, charset);
+ ) {
+ String result1 = readAll(r1, BUFFER_SIZE);
+ String result2 = readAll(r2, BUFFER_SIZE);
+ Assert.assertEquals(result1, result2);
+ }
+ }
+
+ public String readAll(Reader reader, int bufferSize) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ char[] buf = new char[bufferSize];
+ int numRead;
+ while ((numRead = reader.read(buf)) != -1) {
+ if (numRead == buf.length) {
+ sb.append(buf);
+ } else {
+ sb.append(String.valueOf(buf, 0, numRead));
+ }
+ }
+ return sb.toString();
+ }
+
+ /*
+ * Creates a FileReader over the given input file.
+ */
+ FileReader getFileReader(ConstructorType type, File file, Charset charset)
+ throws IOException {
+ switch (type) {
+ case STRING:
+ case STRING_APPEND:
+ return new FileReader(file.getPath(), charset);
+ case FILE:
+ case FILE_APPEND:
+ return new FileReader(file, charset);
+ }
+
+ return null;
+ }
+
+ /*
+ * Creates a FileWriter using the constructor as specified.
+ */
+ FileWriter getFileWriter(ConstructorType type, File file, Charset charset)
+ throws IOException {
+ switch (type) {
+ case STRING:
+ return new FileWriter(file.getPath(), charset);
+ case FILE:
+ return new FileWriter(file, charset);
+ case STRING_APPEND:
+ return new FileWriter(file.getPath(), charset, true);
+ case FILE_APPEND:
+ return new FileWriter(file, charset, true);
+ }
+
+ return null;
+ }
+
+ void writeWithFileWriter(ConstructorType type, File file, String content, Charset charset)
+ throws IOException {
+ if (type == ConstructorType.STRING_APPEND || type == ConstructorType.FILE_APPEND) {
+ try (FileWriter writer = getFileWriter(ConstructorType.FILE, file, charset);) {
+ writer.write(content);
+ }
+ }
+ try (FileWriter writer = getFileWriter(type, file, charset);) {
+ writer.write(content);
+ }
+ }
+
+ void writeWithOutputStreamWriter(ConstructorType type, File file, String content, Charset charset)
+ throws IOException {
+ try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), charset)) {
+ writer.write(content);
+ if (type == ConstructorType.STRING_APPEND || type == ConstructorType.FILE_APPEND) {
+ writer.write(content);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/PrintStream/EncodingTest.java b/ojluni/src/test/java/io/PrintStream/EncodingTest.java
new file mode 100644
index 0000000..41caec7
--- /dev/null
+++ b/ojluni/src/test/java/io/PrintStream/EncodingTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ *
+ * 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 test.java.io.PrintStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183743
+ * @summary Test to verify the new overload method with Charset functions the same
+ * as the existing method that takes a charset name.
+ * @run testng EncodingTest
+ */
+public class EncodingTest {
+ static boolean AUTOFLUSH = true;
+ public static enum ConstructorType {
+ STRING,
+ FILE,
+ OUTPUTSTREAM
+ }
+
+ /*
+ * DataProvider fields:
+ * Type of the constructor, a file to be written with a charset name,
+ * a file to be written with a charset, charset name, charset.
+ */
+ @DataProvider(name = "parameters")
+ public Object[][] getParameters() throws IOException {
+ String csn = StandardCharsets.UTF_8.name();
+ Charset charset = StandardCharsets.UTF_8;
+ File file1 = File.createTempFile("PSCharsetTest1", "txt");
+ File file2 = File.createTempFile("PSCharsetTest2", "txt");
+
+ return new Object[][]{
+ {ConstructorType.STRING, file1, file2, csn, charset},
+ {ConstructorType.FILE, file1, file2, csn, charset},
+ {ConstructorType.OUTPUTSTREAM, file1, file2, csn, charset}
+ };
+ }
+
+ /**
+ * Verifies that the overloading constructor behaves the same as the existing
+ * one.
+ * @param type the type of the constructor
+ * @param file1 file1 written with the name of a charset
+ * @param file2 file2 written with a charset
+ * @param csn the charset name
+ * @param charset the charset
+ * @throws IOException
+ */
+ @Test(dataProvider = "parameters")
+ public void test(ConstructorType type, File file1, File file2, String csn, Charset charset)
+ throws Exception {
+ createFile(getPrintStream(type, file1.getPath(), csn, null));
+ createFile(getPrintStream(type, file2.getPath(), null, charset));
+
+ Assert.assertEquals(Files.readAllLines(Paths.get(file1.getPath()), charset),
+ Files.readAllLines(Paths.get(file2.getPath()), charset));
+ }
+
+ public void createFile(PrintStream out) throws IOException {
+ out.println("high surrogate");
+ out.println(Character.MIN_HIGH_SURROGATE);
+ out.println("low surrogate");
+ out.println(Character.MIN_LOW_SURROGATE);
+ out.flush();
+ out.close();
+ }
+
+ PrintStream getPrintStream(ConstructorType type, String path, String csn, Charset charset)
+ throws IOException {
+ PrintStream out = null;
+ if (csn != null) {
+ switch (type) {
+ case STRING:
+ out = new PrintStream(path, csn);
+ break;
+ case FILE:
+ out = new PrintStream(new File(path), csn);
+ break;
+ case OUTPUTSTREAM:
+ FileOutputStream fout = new FileOutputStream(path);
+ out = new PrintStream(fout, AUTOFLUSH, csn);
+ break;
+ }
+ } else {
+ switch (type) {
+ case STRING:
+ out = new PrintStream(path, charset);
+ break;
+ case FILE:
+ out = new PrintStream(new File(path), charset);
+ break;
+ case OUTPUTSTREAM:
+ FileOutputStream fout = new FileOutputStream(path);
+ out = new PrintStream(fout, AUTOFLUSH, charset);
+ break;
+ }
+ }
+
+ return out;
+ }
+
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/PrintWriter/EncodingTest.java b/ojluni/src/test/java/io/PrintWriter/EncodingTest.java
new file mode 100644
index 0000000..7f2608b
--- /dev/null
+++ b/ojluni/src/test/java/io/PrintWriter/EncodingTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ *
+ * 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 test.java.io.PrintWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8183743
+ * @bug 8183743
+ * @summary Test to verify the new overload method with Charset functions the same
+ * as the existing method that takes a charset name.
+ * @run testng EncodingTest
+ */
+public class EncodingTest {
+ static boolean AUTOFLUSH = true;
+ public static enum ConstructorType {
+ STRING,
+ FILE,
+ OUTPUTSTREAM
+ }
+
+ /*
+ * DataProvider fields:
+ * Type of the constructor, a file to be written with a charset name,
+ * a file to be written with a charset, charset name, charset.
+ */
+ @DataProvider(name = "parameters")
+ public Object[][] getParameters() throws IOException {
+ String csn = StandardCharsets.UTF_8.name();
+ Charset charset = StandardCharsets.UTF_8;
+ File file1 = File.createTempFile("PSCharsetTest1", "txt");
+ File file2 = File.createTempFile("PSCharsetTest2", "txt");
+
+ return new Object[][]{
+ {ConstructorType.STRING, file1, file2, csn, charset},
+ {ConstructorType.FILE, file1, file2, csn, charset},
+ {ConstructorType.OUTPUTSTREAM, file1, file2, csn, charset}
+ };
+ }
+
+ /**
+ * Verifies that the overloading constructor behaves the same as the existing
+ * one.
+ *
+ * @param type the type of the constructor
+ * @param file1 file1 written with the name of a charset
+ * @param file2 file2 written with a charset
+ * @param csn the charset name
+ * @param charset the charset
+ * @throws IOException
+ */
+ @Test(dataProvider = "parameters")
+ public void test(ConstructorType type, File file1, File file2, String csn, Charset charset)
+ throws Exception {
+ createFile(getWriter(type, file1.getPath(), csn, null));
+ createFile(getWriter(type, file2.getPath(), null, charset));
+
+ Assert.assertEquals(Files.readAllLines(Paths.get(file1.getPath()), charset),
+ Files.readAllLines(Paths.get(file2.getPath()), charset));
+ }
+
+ void createFile(PrintWriter out) throws IOException {
+ out.println("high surrogate");
+ out.println(Character.MIN_HIGH_SURROGATE);
+ out.println("low surrogate");
+ out.println(Character.MIN_LOW_SURROGATE);
+ out.flush();
+ out.close();
+ }
+
+ PrintWriter getWriter(ConstructorType type, String path, String csn, Charset charset)
+ throws IOException {
+ PrintWriter out = null;
+ if (csn != null) {
+ switch (type) {
+ case STRING:
+ out = new PrintWriter(path, csn);
+ break;
+ case FILE:
+ out = new PrintWriter(new File(path), csn);
+ break;
+ case OUTPUTSTREAM:
+ // No corresponding method with charset name
+ // compare with PrintWriter(path, csn) instead
+ out = new PrintWriter(path, csn);
+ break;
+ }
+ } else {
+ switch (type) {
+ case STRING:
+ out = new PrintWriter(path, charset);
+ break;
+ case FILE:
+ out = new PrintWriter(new File(path), charset);
+ break;
+ case OUTPUTSTREAM:
+ FileOutputStream fout = new FileOutputStream(path);
+ out = new PrintWriter(fout, AUTOFLUSH, charset);
+ break;
+ }
+ }
+
+ return out;
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/Reader/NullReader.java b/ojluni/src/test/java/io/Reader/NullReader.java
new file mode 100644
index 0000000..67083f1
--- /dev/null
+++ b/ojluni/src/test/java/io/Reader/NullReader.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 test.java.io.Reader;
+
+import java.io.Reader;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.CharBuffer;
+import java.nio.ReadOnlyBufferException;
+
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug 8196298 8204930
+ * @run testng NullReader
+ * @summary Check for expected behavior of Reader.nullReader().
+ */
+public class NullReader {
+ private static Reader openReader;
+ private static Reader closedReader;
+
+ @BeforeGroups(groups = "open")
+ public static void openStream() {
+ openReader = Reader.nullReader();
+ }
+
+ @BeforeGroups(groups = "closed")
+ public static void openAndCloseStream() throws IOException {
+ closedReader = Reader.nullReader();
+ closedReader.close();
+ }
+
+ @AfterGroups(groups = "open")
+ public static void closeStream() throws IOException {
+ openReader.close();
+ }
+
+ @Test(groups = "open")
+ public static void testOpen() {
+ assertNotNull(openReader, "Reader.nullReader() returned null");
+ }
+
+ @Test(groups = "open")
+ public static void testRead() throws IOException {
+ assertEquals(-1, openReader.read(), "read() != -1");
+ }
+
+ @Test(groups = "open")
+ public static void testReadBII() throws IOException {
+ assertEquals(-1, openReader.read(new char[1], 0, 1),
+ "read(char[],int,int) != -1");
+ }
+
+ @Test(groups = "open")
+ public static void testReadBIILenZero() throws IOException {
+ assertEquals(0, openReader.read(new char[1], 0, 0),
+ "read(char[],int,int) != 0");
+ }
+
+ @Test(groups = "open")
+ public static void testReadCharBuffer() throws IOException {
+ CharBuffer charBuffer = CharBuffer.allocate(1);
+ assertEquals(-1, openReader.read(charBuffer),
+ "read(CharBuffer) != -1");
+ }
+
+ @Test(groups = "open")
+ public static void testReadCharBufferZeroRemaining() throws IOException {
+ CharBuffer charBuffer = CharBuffer.allocate(0);
+ assertEquals(0, openReader.read(charBuffer),
+ "read(CharBuffer) != 0");
+ }
+
+ @Test(groups = "open")
+ public static void testReady() throws IOException {
+ assertFalse(openReader.ready());
+ }
+
+ @Test(groups = "open")
+ public static void testSkip() throws IOException {
+ assertEquals(0, openReader.skip(1), "skip() != 0");
+ }
+
+ @Test(groups = "open")
+ public static void testTransferTo() throws IOException {
+ assertEquals(0, openReader.transferTo(new StringWriter(7)),
+ "transferTo() != 0");
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testReadClosed() throws IOException {
+ closedReader.read();
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testReadBIIClosed() throws IOException {
+ closedReader.read(new char[1], 0, 1);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testReadCharBufferClosed() throws IOException {
+ CharBuffer charBuffer = CharBuffer.allocate(0);
+ closedReader.read(charBuffer);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testReadCharBufferZeroRemainingClosed() throws IOException {
+ CharBuffer charBuffer = CharBuffer.allocate(0);
+ closedReader.read(charBuffer);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testReadyClosed() throws IOException {
+ closedReader.ready();
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testSkipClosed() throws IOException {
+ closedReader.skip(1);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testTransferToClosed() throws IOException {
+ closedReader.transferTo(new StringWriter(7));
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/Reader/TransferTo.java b/ojluni/src/test/java/io/Reader/TransferTo.java
new file mode 100644
index 0000000..de1102d
--- /dev/null
+++ b/ojluni/src/test/java/io/Reader/TransferTo.java
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ *
+ * This code is distributed source 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 source 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 Franklsource 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 test.java.io.Reader;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.Random;
+import org.testng.annotations.Test;
+
+import static java.lang.String.format;
+
+/*
+ * @test
+ * @bug 8191706
+ * @summary tests whether java.io.Reader.transferTo conforms to its
+ * contract defined source the javadoc
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main TransferTo
+ * @key randomness
+ * @author Patrick Reinhart
+ */
+public class TransferTo {
+
+ private static Random generator = new Random();
+
+ @Test
+ public void ifOutIsNullThenNpeIsThrown() throws IOException {
+ try (Reader in = input()) {
+ assertThrowsNPE(() -> in.transferTo(null), "out");
+ }
+
+ try (Reader in = input((char) 1)) {
+ assertThrowsNPE(() -> in.transferTo(null), "out");
+ }
+
+ try (Reader in = input((char) 1, (char) 2)) {
+ assertThrowsNPE(() -> in.transferTo(null), "out");
+ }
+
+ Reader in = null;
+ try {
+ Reader fin = in = new ThrowingReader();
+ // null check should precede everything else:
+ // Reader shouldn't be touched if Writer is null
+ assertThrowsNPE(() -> fin.transferTo(null), "out");
+ } finally {
+ if (in != null)
+ try {
+ in.close();
+ } catch (IOException ignored) { }
+ }
+ }
+
+ @Test
+ public void ifExceptionInInputNeitherStreamIsClosed()
+ throws IOException {
+ transferToThenCheckIfAnyClosed(input(0, new char[]{1, 2, 3}), output());
+ transferToThenCheckIfAnyClosed(input(1, new char[]{1, 2, 3}), output());
+ transferToThenCheckIfAnyClosed(input(2, new char[]{1, 2, 3}), output());
+ }
+
+ @Test
+ public void ifExceptionInOutputNeitherStreamIsClosed()
+ throws IOException {
+ transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(0));
+ transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(1));
+ transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(2));
+ }
+
+ private static void transferToThenCheckIfAnyClosed(Reader input,
+ Writer output)
+ throws IOException {
+ try (CloseLoggingReader in = new CloseLoggingReader(input);
+ CloseLoggingWriter out =
+ new CloseLoggingWriter(output)) {
+ boolean thrown = false;
+ try {
+ in.transferTo(out);
+ } catch (IOException ignored) {
+ thrown = true;
+ }
+ if (!thrown)
+ throw new AssertionError();
+
+ if (in.wasClosed() || out.wasClosed()) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ @Test
+ public void onReturnNeitherStreamIsClosed()
+ throws IOException {
+ try (CloseLoggingReader in =
+ new CloseLoggingReader(input(new char[]{1, 2, 3}));
+ CloseLoggingWriter out =
+ new CloseLoggingWriter(output())) {
+
+ in.transferTo(out);
+
+ if (in.wasClosed() || out.wasClosed()) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ @Test
+ public void onReturnInputIsAtEnd() throws IOException {
+ try (Reader in = input(new char[]{1, 2, 3});
+ Writer out = output()) {
+
+ in.transferTo(out);
+
+ if (in.read() != -1) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ @Test
+ public void contents() throws IOException {
+ checkTransferredContents(new char[0]);
+ checkTransferredContents(createRandomChars(1024, 4096));
+ // to span through several batches
+ checkTransferredContents(createRandomChars(16384, 16384));
+ }
+
+ private static void checkTransferredContents(char[] chars)
+ throws IOException {
+ try (Reader in = input(chars);
+ StringWriter out = new StringWriter()) {
+ in.transferTo(out);
+
+ char[] outChars = out.toString().toCharArray();
+ if (!Arrays.equals(chars, outChars)) {
+ throw new AssertionError(
+ format("chars.length=%s, outChars.length=%s",
+ chars.length, outChars.length));
+ }
+ }
+ }
+
+ private static char[] createRandomChars(int min, int maxRandomAdditive) {
+ char[] chars = new char[min + generator.nextInt(maxRandomAdditive)];
+ for (int index=0; index<chars.length; index++) {
+ chars[index] = (char)generator.nextInt();
+ }
+ return chars;
+ }
+
+ private static Writer output() {
+ return output(-1);
+ }
+
+ private static Writer output(int exceptionPosition) {
+ return new Writer() {
+
+ int pos;
+
+ @Override
+ public void write(int b) throws IOException {
+ if (pos++ == exceptionPosition)
+ throw new IOException();
+ }
+
+ @Override
+ public void write(char[] chars, int off, int len) throws IOException {
+ for (int i=0; i<len; i++) {
+ write(chars[off + i]);
+ }
+ }
+
+ @Override
+ public Writer append(CharSequence csq, int start, int end) throws IOException {
+ for (int i = start; i < end; i++) {
+ write(csq.charAt(i));
+ }
+ return this;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+ };
+ }
+
+ private static Reader input(char... chars) {
+ return input(-1, chars);
+ }
+
+ private static Reader input(int exceptionPosition, char... chars) {
+ return new Reader() {
+
+ int pos;
+
+ @Override
+ public int read() throws IOException {
+ if (pos == exceptionPosition) {
+ throw new IOException();
+ }
+
+ if (pos >= chars.length)
+ return -1;
+ return chars[pos++];
+ }
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ int c = read();
+ if (c == -1) {
+ return -1;
+ }
+ cbuf[off] = (char)c;
+
+ int i = 1;
+ for (; i < len ; i++) {
+ c = read();
+ if (c == -1) {
+ break;
+ }
+ cbuf[off + i] = (char)c;
+ }
+ return i;
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+ };
+ }
+
+ private static class ThrowingReader extends Reader {
+
+ boolean closed;
+
+ @Override
+ public int read(char[] b, int off, int len) throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (!closed) {
+ closed = true;
+ throw new IOException();
+ }
+ }
+ @Override
+ public int read() throws IOException {
+ throw new IOException();
+ }
+ }
+
+ private static class CloseLoggingReader extends FilterReader {
+
+ boolean closed;
+
+ CloseLoggingReader(Reader in) {
+ super(in);
+ }
+
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ super.close();
+ }
+
+ boolean wasClosed() {
+ return closed;
+ }
+ }
+
+ private static class CloseLoggingWriter extends FilterWriter {
+
+ boolean closed;
+
+ CloseLoggingWriter(Writer out) {
+ super(out);
+ }
+
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ super.close();
+ }
+
+ boolean wasClosed() {
+ return closed;
+ }
+ }
+
+ public interface Thrower {
+ public void run() throws Throwable;
+ }
+
+ public static void assertThrowsNPE(Thrower thrower, String message) {
+ assertThrows(thrower, NullPointerException.class, message);
+ }
+
+ public static <T extends Throwable> void assertThrows(Thrower thrower,
+ Class<T> throwable,
+ String message) {
+ Throwable thrown;
+ try {
+ thrower.run();
+ thrown = null;
+ } catch (Throwable caught) {
+ thrown = caught;
+ }
+
+ if (!throwable.isInstance(thrown)) {
+ String caught = thrown == null ?
+ "nothing" : thrown.getClass().getCanonicalName();
+ throw new AssertionError(
+ format("Expected to catch %s, but caught %s",
+ throwable, caught), thrown);
+ }
+
+ if (thrown != null && !message.equals(thrown.getMessage())) {
+ throw new AssertionError(
+ format("Expected exception message to be '%s', but it's '%s'",
+ message, thrown.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/io/Writer/NullWriter.java b/ojluni/src/test/java/io/Writer/NullWriter.java
new file mode 100644
index 0000000..e80b8a0
--- /dev/null
+++ b/ojluni/src/test/java/io/Writer/NullWriter.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @bug 8196298
+ * @run testng NullWriter
+ * @summary Check for expected behavior of Writer.nullWriter().
+ */
+public class NullWriter {
+ private static Writer openWriter;
+ private static Writer closedWriter;
+
+ @BeforeGroups(groups = "open")
+ public static void openStream() {
+ openWriter = Writer.nullWriter();
+ }
+
+ @BeforeGroups(groups = "closed")
+ public static void openAndCloseStream() throws IOException {
+ closedWriter = Writer.nullWriter();
+ closedWriter.close();
+ }
+
+ @AfterGroups(groups = "open")
+ public static void closeStream() throws IOException {
+ openWriter.close();
+ }
+
+ @Test(groups = "open")
+ public static void testOpen() {
+ assertNotNull(openWriter, "Writer.nullWriter() returned null");
+ }
+
+ @Test(groups = "open")
+ public static void testAppendChar() throws IOException {
+ assertSame(openWriter, openWriter.append('x'));
+ }
+
+ @Test(groups = "open")
+ public static void testAppendCharSequence() throws IOException {
+ CharSequence cs = "abc";
+ assertSame(openWriter, openWriter.append(cs));
+ }
+
+ @Test(groups = "open")
+ public static void testAppendCharSequenceNull() throws IOException {
+ assertSame(openWriter, openWriter.append(null));
+ }
+
+ @Test(groups = "open")
+ public static void testAppendCharSequenceII() throws IOException {
+ CharSequence cs = "abc";
+ assertSame(openWriter, openWriter.append(cs, 0, 1));
+ }
+
+ @Test(groups = "open")
+ public static void testAppendCharSequenceIINull() throws IOException {
+ assertSame(openWriter, openWriter.append(null, 2, 1));
+ }
+
+ @Test(groups = "open")
+ public static void testFlush() throws IOException {
+ openWriter.flush();
+ }
+
+ @Test(groups = "open")
+ public static void testWrite() throws IOException {
+ openWriter.write(62832);
+ }
+
+ @Test(groups = "open")
+ public static void testWriteString() throws IOException {
+ openWriter.write("");
+ }
+
+ @Test(groups = "open")
+ public static void testWriteStringII() throws IOException {
+ openWriter.write("", 0, 0);
+ }
+
+ @Test(groups = "open")
+ public static void testWriteBII() throws IOException, Exception {
+ openWriter.write(new char[]{(char) 6}, 0, 1);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testAppendCharClosed() throws IOException {
+ closedWriter.append('x');
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testAppendCharSequenceClosed() throws IOException {
+ CharSequence cs = "abc";
+ closedWriter.append(cs);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testAppendCharSequenceNullClosed() throws IOException {
+ closedWriter.append(null);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testAppendCharSequenceIIClosed() throws IOException {
+ CharSequence cs = "abc";
+ closedWriter.append(cs, 0, 1);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testAppendCharSequenceIINullClosed() throws IOException {
+ closedWriter.append(null, 2, 1);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testFlushClosed() throws IOException {
+ closedWriter.flush();
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testWriteClosed() throws IOException {
+ closedWriter.write(62832);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testWriteStringClosed() throws IOException {
+ closedWriter.write("");
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testWriteStringIIClosed() throws IOException {
+ closedWriter.write("", 0, 0);
+ }
+
+ @Test(groups = "closed", expectedExceptions = IOException.class)
+ public static void testWriteBIIClosed() throws IOException {
+ closedWriter.write(new char[]{(char) 6}, 0, 1);
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java b/ojluni/src/test/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java
new file mode 100644
index 0000000..fda5277
--- /dev/null
+++ b/ojluni/src/test/java/lang/invoke/VarHandles/VarHandleTestAccessModeMethodNames.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+// Android-added: package name
+package test.java.lang.invoke.VarHandles;
+
+/*
+ * @test
+ * @run testng VarHandleTestAccessModeMethodNames
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.stream.Stream;
+
+import static org.testng.Assert.assertEquals;
+
+public class VarHandleTestAccessModeMethodNames {
+
+ @DataProvider
+ public static Object[][] accessModesProvider() {
+ return Stream.of(VarHandle.AccessMode.values()).
+ map(am -> new Object[]{am}).
+ toArray(Object[][]::new);
+ }
+
+ @Test(dataProvider = "accessModesProvider")
+ public void testMethodName(VarHandle.AccessMode am) {
+ assertEquals(am.methodName(), toMethodName(am.name()));
+ }
+
+ private static String toMethodName(String name) {
+ StringBuilder s = new StringBuilder(name.toLowerCase());
+ int i;
+ while ((i = s.indexOf("_")) != -1) {
+ s.deleteCharAt(i);
+ s.setCharAt(i, Character.toUpperCase(s.charAt(i)));
+ }
+ return s.toString();
+ }
+
+ // BEGIN Android-removed: test for AccessMode return type (not present on Android).
+ // @Test(dataProvider = "accessModesProvider")
+ // public void testReturnType(VarHandle.AccessMode am) throws Exception {
+ // assertEquals(getReturnType(am.methodName()), getAccessModeReturnType(am));
+ // }
+ //
+ // private static Class<?> getReturnType(String name) throws Exception {
+ // return VarHandle.class.getMethod(name, Object[].class).getReturnType();
+ // }
+ //
+ // private static Class<?> getAccessModeReturnType(VarHandle.AccessMode am) throws Exception {
+ // Field field_am_at = VarHandle.AccessMode.class.getDeclaredField("at");
+ // field_am_at.setAccessible(true);
+ // Field field_at_returnType = field_am_at.getType().getDeclaredField("returnType");
+ // field_at_returnType.setAccessible(true);
+ // return (Class<?>) field_at_returnType.get(field_am_at.get(am));
+ // }
+ // END Android-removed: test for AccessMode return type (not present on Android). */
+
+ // BEGIN Android-added: valueFromMethodName test (b/203822312)
+ @Test(dataProvider = "accessModesProvider")
+ public void testValueFromMethodName(VarHandle.AccessMode am) throws Exception {
+ VarHandle.AccessMode other = VarHandle.AccessMode.valueFromMethodName(am.methodName());
+ assertEquals(am, other);
+ }
+ // END Android-added: valueFromMethodName test (b/203822312)
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/AddTests.java b/ojluni/src/test/java/math/BigDecimal/AddTests.java
new file mode 100644
index 0000000..a7f13bd
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/AddTests.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6362557
+ * @summary Some tests of add(BigDecimal, mc)
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+import java.util.Set;
+import java.util.EnumSet;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class AddTests {
+
+ private static Set<RoundingMode> nonExactRoundingModes =
+ EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
+
+ /**
+ * Test for some simple additions, particularly, it will test
+ * the overflow case.
+ */
+ private static int simpleTests() {
+ int failures = 0;
+
+ BigDecimal[] bd1 = {
+ new BigDecimal(new BigInteger("7812404666936930160"), 11),
+ new BigDecimal(new BigInteger("7812404666936930160"), 12),
+ new BigDecimal(new BigInteger("7812404666936930160"), 13),
+ };
+ BigDecimal bd2 = new BigDecimal(new BigInteger("2790000"), 1);
+ BigDecimal[] expectedResult = {
+ new BigDecimal("78403046.66936930160"),
+ new BigDecimal("8091404.666936930160"),
+ new BigDecimal("1060240.4666936930160"),
+ };
+ for (int i = 0; i < bd1.length; i++) {
+ if (!bd1[i].add(bd2).equals(expectedResult[i]))
+ failures++;
+ }
+ return failures;
+ }
+
+ /**
+ * Test for extreme value of scale and rounding precision that
+ * could cause integer overflow in right-shift-into-sticky-bit
+ * computations.
+ */
+ @Test
+ public void extremaTests() {
+ addWithoutException(valueOf(1, -Integer.MAX_VALUE),
+ valueOf(2, Integer.MAX_VALUE), null);
+ addWithoutException(valueOf(1, -Integer.MAX_VALUE),
+ valueOf(-2, Integer.MAX_VALUE), null);
+ }
+
+ /**
+ * Print sum of b1 and b2; correct result will not throw an
+ * exception.
+ */
+ private static void addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc) {
+ if (mc == null)
+ mc = new MathContext(2, RoundingMode.DOWN);
+
+ try {
+ BigDecimal sum = b1.add(b2, mc);
+ } catch(ArithmeticException ae) {
+ Assert.fail("Unexpected ArithmeticException: " + ae.getMessage());
+ }
+ }
+
+ /**
+ * Test combinations of operands that may meet the condensation
+ * criteria when rounded to different precisions.
+ */
+ @Test
+ public void roundingGradationTests() {
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal( "1234e97"));
+
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal( "1234e96"));
+
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal( "1234e95"));
+
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal( "1234e94"));
+
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal( "1234e93"));
+
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal( "1234e92"));
+
+ roundAway(new BigDecimal("1234e100"),
+ new BigDecimal("1234e50"));
+
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal( "1234e97"));
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal( "1234e96"));
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal( "1234e95"));
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal( "1234e94"));
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal( "1234e93"));
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal( "1234e92"));
+
+ roundAway(new BigDecimal("1000e100"),
+ new BigDecimal("1234e50"));
+
+
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal( "1234e97"));
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal( "1234e96"));
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal( "1234e95"));
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal( "1234e94"));
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal( "1234e93"));
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal( "1234e92"));
+
+ roundAway(new BigDecimal("1999e100"),
+ new BigDecimal("1234e50"));
+
+
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal( "1234e97"));
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal( "1234e96"));
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal( "1234e95"));
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal( "1234e94"));
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal( "1234e93"));
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal( "1234e92"));
+
+ roundAway(new BigDecimal("9999e100"),
+ new BigDecimal("1234e50"));
+ }
+
+ private static void roundAway(BigDecimal b1, BigDecimal b2) {
+ b1.precision();
+ b2.precision();
+
+ BigDecimal b1_negate = b1.negate();
+ BigDecimal b2_negate = b2.negate();
+
+ b1_negate.precision();
+ b2_negate.precision();
+
+ roundAway1(b1, b2);
+ roundAway1(b1, b2_negate);
+ roundAway1(b1_negate, b2);
+ roundAway1(b1_negate, b2_negate);
+ }
+
+ private static void roundAway1(BigDecimal b1, BigDecimal b2) {
+ roundAway0(b1, b2);
+ roundAway0(b2, b1);
+ }
+
+ /**
+ * Compare b1.add(b2, mc) with b1.add(b2).round(mc) for a variety
+ * of MathContexts.
+ */
+ private static void roundAway0(BigDecimal b1, BigDecimal b2) {
+ BigDecimal exactSum = b1.add(b2);
+
+ for(int precision = 1 ; precision < exactSum.precision()+2; precision++) {
+ for(RoundingMode rm : nonExactRoundingModes) {
+ MathContext mc = new MathContext(precision, rm);
+ BigDecimal roundedExactSum = exactSum.round(mc);
+
+ try {
+ BigDecimal sum = b1.add(b2, mc);
+
+ Assert.assertEquals(sum, roundedExactSum, "Exact sum " + exactSum +
+ "\trounded by " + mc +
+ "\texpected: " + roundedExactSum + " got: ");
+ } catch (ArithmeticException ae) {
+ Assert.fail("Unexpected ArithmeticException: " + ae.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * Verify calling the precision method should not change the
+ * computed result.
+ */
+ @Test
+ public void precisionConsistencyTest() {
+ MathContext mc = new MathContext(1,RoundingMode.DOWN);
+ BigDecimal a = BigDecimal.valueOf(1999, -1); //value is equivalent to 19990
+
+ BigDecimal sum1 = a.add(BigDecimal.ONE, mc);
+ a.precision();
+ BigDecimal sum2 = a.add(BigDecimal.ONE, mc);
+
+ Assert.assertEquals(sum2, sum1, "Unequal sums after calling precision!" +
+ "Before:\t" + sum1.toString() +
+ "After:\t" + sum2.toString());
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/CompareToTests.java b/ojluni/src/test/java/math/BigDecimal/CompareToTests.java
new file mode 100644
index 0000000..4885944
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/CompareToTests.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6473768
+ * @summary Tests of BigDecimal.compareTo
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class CompareToTests {
+
+ @Test
+ public void compareToTests() {
+ final BigDecimal MINUS_ONE = BigDecimal.ONE.negate();
+
+ // First operand, second operand, expected compareTo result
+ BigDecimal [][] testCases = {
+ // Basics
+ {valueOf(0), valueOf(0), ZERO},
+ {valueOf(0), valueOf(1), MINUS_ONE},
+ {valueOf(1), valueOf(2), MINUS_ONE},
+ {valueOf(2), valueOf(1), ONE},
+ {valueOf(10), valueOf(10), ZERO},
+
+ // Significands would compare differently than scaled value
+ {valueOf(2,1), valueOf(2), MINUS_ONE},
+ {valueOf(2,-1), valueOf(2), ONE},
+ {valueOf(1,1), valueOf(2), MINUS_ONE},
+ {valueOf(1,-1), valueOf(2), ONE},
+ {valueOf(5,-1), valueOf(2), ONE},
+
+ // Boundary and near boundary values
+ {valueOf(Long.MAX_VALUE), valueOf(Long.MAX_VALUE), ZERO},
+ {valueOf(Long.MAX_VALUE).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+ {valueOf(Long.MAX_VALUE-1), valueOf(Long.MAX_VALUE), MINUS_ONE},
+ {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+ {valueOf(Long.MIN_VALUE), valueOf(Long.MAX_VALUE), MINUS_ONE},
+ {valueOf(Long.MIN_VALUE).negate(), valueOf(Long.MAX_VALUE), ONE},
+
+ {valueOf(Long.MIN_VALUE+1), valueOf(Long.MAX_VALUE), MINUS_ONE},
+ {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MAX_VALUE), ZERO},
+
+ {valueOf(Long.MAX_VALUE), valueOf(Long.MIN_VALUE), ONE},
+ {valueOf(Long.MAX_VALUE).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+ {valueOf(Long.MAX_VALUE-1), valueOf(Long.MIN_VALUE), ONE},
+ {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+ {valueOf(Long.MIN_VALUE), valueOf(Long.MIN_VALUE), ZERO},
+ {valueOf(Long.MIN_VALUE).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+ {valueOf(Long.MIN_VALUE+1), valueOf(Long.MIN_VALUE), ONE},
+ {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MIN_VALUE), ONE},
+ };
+
+ for (BigDecimal[] testCase : testCases) {
+ BigDecimal a = testCase[0];
+ BigDecimal a_negate = a.negate();
+ BigDecimal b = testCase[1];
+ BigDecimal b_negate = b.negate();
+ int expected = testCase[2].intValue();
+
+ compareToTest(a, b, expected);
+ compareToTest(a_negate, b_negate, -expected);
+ }
+ }
+
+ private static void compareToTest(BigDecimal a, BigDecimal b, int expected) {
+ int result = a.compareTo(b);
+ Assert.assertEquals(result, expected, "(" + a + ").compareTo(" + b + ") => " + result +
+ "\n\tExpected " + expected);
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/Constructor.java b/ojluni/src/test/java/math/BigDecimal/Constructor.java
new file mode 100644
index 0000000..25ad7bc
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/Constructor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4259453
+ * @summary Test string constructor of BigDecimal
+ */
+import java.math.BigDecimal;
+
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class Constructor {
+
+ @Test(expectedExceptions = NumberFormatException.class)
+ public void testConstructor() throws Exception {
+ BigDecimal bd = new BigDecimal("1.2e");
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/DivideMcTests.java b/ojluni/src/test/java/math/BigDecimal/DivideMcTests.java
new file mode 100644
index 0000000..acf717f
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/DivideMcTests.java
@@ -0,0 +1,5783 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 7036582
+ * @summary Some tests for the divide(..,MathContext) method.
+ * @run main DivideMcTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 DivideMcTests
+ * @author Sergey V. Kuksenko
+ */
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class DivideMcTests {
+
+ static String[] value = new String[75];
+ static String[][] results = new String[75][75];
+ static {
+ value[0]="11061";
+ value[1]="5030285645";
+ value[2]="224198292018431";
+ value[3]="19226185404220649458";
+ value[4]="2754593222460641763294400";
+ value[5]="88290e4";
+ value[6]="14207e-4";
+ value[7]="9206524943e4";
+ value[8]="9637167289e-4";
+ value[9]="987673128759528e4";
+ value[10]="270627774630281e-4";
+ value[11]="81503625886547904651e4";
+ value[12]="60700032235397315737e-4";
+ value[13]="6477954854329556663533122e4";
+ value[14]="8056417378028557868905113e-4";
+ value[15]="74996e8";
+ value[16]="65282e-8";
+ value[17]="6336626690e8";
+ value[18]="8318166778e-8";
+ value[19]="983114227763768e8";
+ value[20]="245802997834566e-8";
+ value[21]="52727924122290902686e8";
+ value[22]="42785567085625398961e-8";
+ value[23]="4810906998143118279742863e8";
+ value[24]="8077506080975981172874361e-8";
+ value[25]="80689e12";
+ value[26]="30125e-12";
+ value[27]="6921467144e12";
+ value[28]="1953347181e-12";
+ value[29]="405471649883944e12";
+ value[30]="866720590936024e-12";
+ value[31]="33231666378140173438e12";
+ value[32]="42631490906110209257e-12";
+ value[33]="7723154992826793726050991e12";
+ value[34]="1611437259018380210686834e-12";
+ value[35]="65645e16";
+ value[36]="31153e-16";
+ value[37]="7758733150e16";
+ value[38]="6365465077e-16";
+ value[39]="727973863299662e16";
+ value[40]="351084160935215e-16";
+ value[41]="45470432070181568402e16";
+ value[42]="97216256670931719037e-16";
+ value[43]="2520581904836081418366563e16";
+ value[44]="3700768934485477578987416e-16";
+ value[45]="28736e20";
+ value[46]="52779e-20";
+ value[47]="7904805864e20";
+ value[48]="6373815349e-20";
+ value[49]="186651310031326e20";
+ value[50]="189125880591366e-20";
+ value[51]="74987916068454915171e20";
+ value[52]="10554589082317914511e-20";
+ value[53]="3599986721169840668392202e20";
+ value[54]="2588106172836128849130551e-20";
+ value[55]="71080e24";
+ value[56]="61576e-24";
+ value[57]="7086656363e24";
+ value[58]="7703864845e-24";
+ value[59]="361167296280301e24";
+ value[60]="149150690375117e-24";
+ value[61]="78129219923655854302e24";
+ value[62]="20861932490694515212e-24";
+ value[63]="9185868654811652011998047e24";
+ value[64]="1996563690880014012200226e-24";
+ value[65]="84665e28";
+ value[66]="94968e-28";
+ value[67]="2622821029e28";
+ value[68]="4451579486e-28";
+ value[69]="590522407411869e28";
+ value[70]="606293232614518e-28";
+ value[71]="96628087822208148505e28";
+ value[72]="24875240094942654314e-28";
+ value[73]="5099400093819597146233149e28";
+ value[74]="8906650752845770170008864e-28";
+ //--------------------------------------------
+ initResults1();
+ initResults2();
+ }
+
+ private static void initResults1() {
+ results[0][0]="1";
+ results[0][1]="0.000002198881093560642";
+ results[0][2]="4.933579065397471E-11";
+ results[0][3]="5.753091300977375E-16";
+ results[0][4]="4.015474920147867E-21";
+ results[0][5]="0.00001252803261977574";
+ results[0][6]="7785.598648553530";
+ results[0][7]="1.201430514605841E-10";
+ results[0][8]="0.01147743903192921";
+ results[0][9]="1.119904923797219E-15";
+ results[0][10]="4.087163638363069E-7";
+ results[0][11]="1.357117536758031E-20";
+ results[0][12]="1.822239559462666E-12";
+ results[0][13]="1.707483341383177E-25";
+ results[0][14]="1.372942771084022E-17";
+ results[0][15]="1.474878660195210E-9";
+ results[0][16]="16943414.72381361";
+ results[0][17]="1.745565983468090E-14";
+ results[0][18]="132.9740109233477";
+ results[0][19]="1.125098151123273E-19";
+ results[0][20]="0.004499945117611804";
+ results[0][21]="2.097749946374985E-24";
+ results[0][22]="2.585217575324869E-8";
+ results[0][23]="2.299150660004288E-29";
+ results[0][24]="1.369358300583728E-13";
+ results[0][25]="1.370818822887878E-13";
+ results[0][26]="367170124481.3278";
+ results[0][27]="1.598071589430057E-18";
+ results[0][28]="5662587.842852089";
+ results[0][29]="2.727934247231818E-23";
+ results[0][30]="12.76189825841631";
+ results[0][31]="3.328451806821200E-28";
+ results[0][32]="0.0002594560913752765";
+ results[0][33]="1.432186717769276E-33";
+ results[0][34]="6.864058738928437E-9";
+ results[0][35]="1.684972198948892E-17";
+ results[0][36]="3550540878888069";
+ results[0][37]="1.425619335806130E-22";
+ results[0][38]="17376577934.52694";
+ results[0][39]="1.519422682273810E-27";
+ results[0][40]="315052.6634564146";
+ results[0][41]="2.432569803367569E-32";
+ results[0][42]="1.137772670824026";
+ results[0][43]="4.388272398043467E-37";
+ results[0][44]="0.00002988838318687904";
+ results[0][45]="3.849178730512249E-21";
+ results[0][46]="2.095719888592054E+19";
+ results[0][47]="1.399275351008165E-26";
+ results[0][48]="173538130528606.9";
+ results[0][49]="5.926023234524105E-31";
+ results[0][50]="5848485656.967753";
+ results[0][51]="1.475037656720937E-36";
+ results[0][52]="104798.0164242535";
+ results[0][53]="3.072511333154488E-41";
+ results[0][54]="0.4273781391232109";
+ results[0][55]="1.556133933595948E-25";
+ results[0][56]="1.796316746784461E+23";
+ results[0][57]="1.560820707738894E-30";
+ results[0][58]="1.435772852009322E+18";
+ results[0][59]="3.062569649555309E-35";
+ results[0][60]="74159898101586.80";
+ results[0][61]="1.415731529229177E-40";
+ results[0][62]="530200162.6615257";
+ results[0][63]="1.204132174718842E-45";
+ results[0][64]="5540.018608234184";
+ results[0][65]="1.306443040217327E-29";
+ results[0][66]="1.164708112206217E+27";
+ results[0][67]="4.217214929154817E-34";
+ results[0][68]="2.484736043641657E+22";
+ results[0][69]="1.873087263272185E-39";
+ results[0][70]="1.824364747121068E+17";
+ results[0][71]="1.144698218633054E-44";
+ results[0][72]="4446590247082.196";
+ results[0][73]="2.169078675235893E-49";
+ results[0][74]="12418809.61422664";
+ results[1][0]="454776.7511979025";
+ results[1][1]="1";
+ results[1][2]="0.00002243677059139446";
+ results[1][3]="2.616372171203405E-10";
+ results[1][4]="1.826144638701504E-15";
+ results[1][5]="5.697457973722958";
+ results[1][6]="3540709259.519955";
+ results[1][7]="0.00005463826662224685";
+ results[1][8]="5219.672435012765";
+ results[1][9]="5.093067228950338E-10";
+ results[1][10]="0.1858747001068956";
+ results[1][11]="6.171855043605175E-15";
+ results[1][12]="8.287121867567282E-7";
+ results[1][13]="7.765237267187802E-20";
+ results[1][14]="6.243824530142372E-12";
+ results[1][15]="0.0006707405254946931";
+ results[1][16]="7705471102294.660";
+ results[1][17]="7.938428269631898E-9";
+ results[1][18]="60473488.68147447";
+ results[1][19]="5.116684819466090E-14";
+ results[1][20]="2046.470421156359";
+ results[1][21]="9.540079054379898E-19";
+ results[1][22]="0.01175696850045963";
+ results[1][23]="1.045600267671264E-23";
+ results[1][24]="6.227523191653488E-8";
+ results[1][25]="6.234165307538822E-8";
+ results[1][26]="1.669804363485477E+17";
+ results[1][27]="7.267658056226699E-13";
+ results[1][28]="2575213302545.012";
+ results[1][29]="1.240601074437582E-17";
+ results[1][30]="5803814.629080740";
+ results[1][31]="1.513702499224934E-22";
+ results[1][32]="117.9945983141544";
+ results[1][33]="6.513252226158986E-28";
+ results[1][34]="0.003121614333321446";
+ results[1][35]="7.662861824967629E-12";
+ results[1][36]="1.614703445896061E+21";
+ results[1][37]="6.483385299828233E-17";
+ results[1][38]="7902463660001319";
+ results[1][39]="6.909981111408860E-22";
+ results[1][40]="143278626742.9544";
+ results[1][41]="1.106276192237624E-26";
+ results[1][42]="517432.5588391111";
+ results[1][43]="1.995684264553637E-31";
+ results[1][44]="13.59254180428686";
+ results[1][45]="1.750516997842428E-15";
+ results[1][46]="9.530846823547244E+24";
+ results[1][47]="6.363578981627979E-21";
+ results[1][48]="7.892110721075739E+19";
+ results[1][49]="2.695017594120158E-25";
+ results[1][50]="2659755306503325";
+ results[1][51]="6.708128334181145E-31";
+ results[1][52]="47659701441.40646";
+ results[1][53]="1.397306722110734E-35";
+ results[1][54]="194361.6416434591";
+ results[1][55]="7.076935347495779E-20";
+ results[1][56]="8.169230942250227E+28";
+ results[1][57]="7.098249706679054E-25";
+ results[1][58]="6.529561130949462E+23";
+ results[1][59]="1.392785475542062E-29";
+ results[1][60]="3.372619752780715E+19";
+ results[1][61]="6.438417854312836E-35";
+ results[1][62]="241122707459808.1";
+ results[1][63]="5.476113184315002E-40";
+ results[1][64]="2519471664.228668";
+ results[1][65]="5.941399214551468E-24";
+ results[1][66]="5.296821713629854E+32";
+ results[1][67]="1.917891304584321E-28";
+ results[1][68]="1.130000185511682E+28";
+ results[1][69]="8.518365403010947E-34";
+ results[1][70]="8.296786726957023E+22";
+ results[1][71]="5.205821369719668E-39";
+ results[1][72]="2.022205866476320E+18";
+ results[1][73]="9.864465530164297E-44";
+ results[1][74]="5647785890103.269";
+ results[2][0]="20269260647.17756";
+ results[2][1]="44569.69401753148";
+ results[2][2]="1";
+ results[2][3]="0.00001166109071065203";
+ results[2][4]="8.139070777868161E-11";
+ results[2][5]="253933.9585665772";
+ results[2][6]="157808328301844.9";
+ results[2][7]="2.435210825001846";
+ results[2][8]="232639203.3002624";
+ results[2][9]="0.00002269964480050335";
+ results[2][10]="8284.378509364762";
+ results[2][11]="2.750776908140411E-10";
+ results[2][12]="0.03693544859234678";
+ results[2][13]="3.460942489720927E-15";
+ results[2][14]="2.782853488076028E-7";
+ results[2][15]="29.89469998645674";
+ results[2][16]="3.434304892902040E+17";
+ results[2][17]="0.0003538133189576156";
+ results[2][18]="2695284886705.971";
+ results[2][19]="2.280490767877520E-9";
+ results[2][20]="91210560.48686773";
+ results[2][21]="4.251984043567731E-14";
+ results[2][22]="524.0044886392415";
+ results[2][23]="4.660208399475724E-19";
+ results[2][24]="0.002775588031390770";
+ results[2][25]="0.002778548402117154";
+ results[2][26]="7.442266954968664E+21";
+ results[2][27]="3.239172957900716E-8";
+ results[2][28]="1.147764689243079E+17";
+ results[2][29]="5.529321028550383E-13";
+ results[2][30]="258674242152.6016";
+ results[2][31]="6.746525722402801E-18";
+ results[2][32]="5258983.142583397";
+ results[2][33]="2.902936587789118E-23";
+ results[2][34]="139.1293956768774";
+ results[2][35]="3.415314068374301E-7";
+ results[2][36]="7.196683851264116E+25";
+ results[2][37]="2.889624990111060E-12";
+ results[2][38]="3.522103873109208E+20";
+ results[2][39]="3.079757438024150E-17";
+ results[2][40]="6385884553185581";
+ results[2][41]="4.930639138691073E-22";
+ results[2][42]="23061810822.16754";
+ results[2][43]="8.894703702675794E-27";
+ results[2][44]="605815.4291375707";
+ results[2][45]="7.802000696632482E-11";
+ results[2][46]="4.247869266534626E+29";
+ results[2][47]="2.836227680675536E-16";
+ results[2][48]="3.517489599908254E+24";
+ results[2][49]="1.201161095417993E-20";
+ results[2][50]="1.185444801723589E+20";
+ results[2][51]="2.989792272847868E-26";
+ results[2][52]="2124178310210390";
+ results[2][53]="6.227753305311532E-31";
+ results[2][54]="8662638896.794075";
+ results[2][55]="3.154168430197397E-15";
+ results[2][56]="3.641001234546430E+33";
+ results[2][57]="3.163668174867180E-20";
+ results[2][58]="2.910205416751843E+28";
+ results[2][59]="6.207602247697180E-25";
+ results[2][60]="1.503166304189191E+24";
+ results[2][61]="2.869583137237347E-30";
+ results[2][62]="1.074676529216240E+19";
+ results[2][63]="2.440686890302896E-35";
+ results[2][64]="112292081160512.5";
+ results[2][65]="2.648063450285608E-19";
+ results[2][66]="2.360777230418994E+37";
+ results[2][67]="8.547982860420744E-24";
+ results[2][68]="5.036376250800950E+32";
+ results[2][69]="3.796609395417242E-29";
+ results[2][70]="3.697852457491911E+27";
+ results[2][71]="2.320218655583322E-34";
+ results[2][72]="9.012909670930670E+22";
+ results[2][73]="4.396562103259092E-39";
+ results[2][74]="2.517200889984344E+17";
+ results[3][0]="1738195950114877";
+ results[3][1]="3822086211.611279";
+ results[3][2]="85755.27151045421";
+ results[3][3]="1";
+ results[3][4]="0.000006979682243988879";
+ results[3][5]="21776175562.60126";
+ results[3][6]="1.353289604013560E+19";
+ results[3][7]="208832.1654832305";
+ results[3][8]="19950038042989.76";
+ results[3][9]="1.946614203058035";
+ results[3][10]="710429128.3659471";
+ results[3][11]="0.00002358936206222687";
+ results[3][12]="3167.409422397122";
+ results[3][13]="2.967940628880855E-10";
+ results[3][14]="0.02386443564437743";
+ results[3][15]="2563628.114062170";
+ results[3][16]="2.945097485404958E+22";
+ results[3][17]="30.34135723122526";
+ results[3][18]="2.311348872574943E+17";
+ results[3][19]="0.0001955641049764209";
+ results[3][20]="7821786379172.049";
+ results[3][21]="3.646300461142698E-9";
+ results[3][22]="44936147.19595487";
+ results[3][23]="3.996374365923399E-14";
+ results[3][24]="238.0213052330826";
+ results[3][25]="238.2751726284952";
+ results[3][26]="6.382136233766191E+26";
+ results[3][27]="0.002777761564740970";
+ results[3][28]="9.842687255615237E+21";
+ results[3][29]="4.741684260718020E-8";
+ results[3][30]="2.218267986855733E+16";
+ results[3][31]="5.785501450769154E-13";
+ results[3][32]="450985527261.1410";
+ results[3][33]="2.489421152634873E-18";
+ results[3][34]="11931079.10135604";
+ results[3][35]="0.02928811852269122";
+ results[3][36]="6.171535776400555E+30";
+ results[3][37]="2.478005755903675E-7";
+ results[3][38]="3.020389739265025E+25";
+ results[3][39]="2.641054352841019E-12";
+ results[3][40]="5.476232636928451E+20";
+ results[3][41]="4.228282980585251E-17";
+ results[3][42]="1977671848577708";
+ results[3][43]="7.627677310280051E-22";
+ results[3][44]="51951866610.91471";
+ results[3][45]="0.000006690626880644714";
+ results[3][46]="3.642771822925908E+34";
+ results[3][47]="2.432214748217965E-11";
+ results[3][48]="3.016432756753313E+29";
+ results[3][49]="1.030058958653646E-15";
+ results[3][50]="1.016581408324629E+25";
+ results[3][51]="2.563904481179269E-21";
+ results[3][52]="1.821594877287098E+20";
+ results[3][53]="5.340626755971191E-26";
+ results[3][54]="742866950591597.5";
+ results[3][55]="2.704865701212809E-10";
+ results[3][56]="3.122350494384281E+38";
+ results[3][57]="2.713012233047182E-15";
+ results[3][58]="2.495654556647489E+33";
+ results[3][59]="5.323346161801775E-20";
+ results[3][60]="1.289044345411101E+29";
+ results[3][61]="2.460818810556097E-25";
+ results[3][62]="9.215917754885128E+23";
+ results[3][63]="2.093017669499310E-30";
+ results[3][64]="9.629637908393713E+18";
+ results[3][65]="2.270854001561525E-14";
+ results[3][66]="2.024490923702789E+42";
+ results[3][67]="7.330345910620899E-19";
+ results[3][68]="4.318958128162389E+37";
+ results[3][69]="3.255792695231470E-24";
+ results[3][70]="3.171103414978191E+32";
+ results[3][71]="1.989709807731689E-29";
+ results[3][72]="7.729045159298581E+27";
+ results[3][73]="3.770283768775571E-34";
+ results[3][74]="2.158632457669644E+22";
+ results[4][0]="2.490365448386802E+20";
+ results[4][1]="547601750051441.0";
+ results[4][2]="12286414841.35031";
+ results[4][3]="143272.9979736873";
+ results[4][4]="1";
+ results[4][5]="3119937957255229";
+ results[4][6]="1.938898586936469E+24";
+ results[4][7]="29920010422.11961";
+ results[4][8]="2.858301760108257E+18";
+ results[4][9]="278897.2527702849";
+ results[4][10]="101785311068822.8";
+ results[4][11]="3.379718622942007";
+ results[4][12]="453804243.7569410";
+ results[4][13]="0.00004252257517076709";
+ results[4][14]="3419.129239720079";
+ results[4][15]="367298685591.3171";
+ results[4][16]="4.219529460587362E+27";
+ results[4][17]="4347097.213108260";
+ results[4][18]="3.311538823369143E+22";
+ results[4][19]="28.01905561601273";
+ results[4][20]="1.120650784053732E+18";
+ results[4][21]="0.0005224163985807529";
+ results[4][22]="6438136526151.358";
+ results[4][23]="5.725725364310391E-9";
+ results[4][24]="34102025.98235386";
+ results[4][25]="34138398.32518239";
+ results[4][26]="9.143877916881798E+31";
+ results[4][27]="397.9782270365194";
+ results[4][28]="1.410191311229400E+27";
+ results[4][29]="0.006793553194777180";
+ results[4][30]="3.178179047858768E+21";
+ results[4][31]="8.289061376328140E-8";
+ results[4][32]="6.461404853344776E+16";
+ results[4][33]="3.566668317571105E-13";
+ results[4][34]="1709401471912.486";
+ results[4][35]="4196.196545754653";
+ results[4][36]="8.842144327867755E+35";
+ results[4][37]="0.03550313136443727";
+ results[4][38]="4.327402929934638E+30";
+ results[4][39]="3.783917749429893E-7";
+ results[4][40]="7.845962674940902E+25";
+ results[4][41]="6.057987789095672E-12";
+ results[4][42]="2.833469747538924E+20";
+ results[4][43]="1.092840195819694E-16";
+ results[4][44]="7443299679674857";
+ results[4][45]="0.9585861715133080";
+ results[4][46]="5.219108400046689E+39";
+ results[4][47]="0.000003484706986930048";
+ results[4][48]="4.321733642460815E+34";
+ results[4][49]="1.475796350959623E-10";
+ results[4][50]="1.456486660549828E+30";
+ results[4][51]="3.673382815367253E-16";
+ results[4][52]="2.609853591624336E+25";
+ results[4][53]="7.651676063864807E-21";
+ results[4][54]="1.064327751068292E+20";
+ results[4][55]="0.00003875342181289592";
+ results[4][56]="4.473485160550607E+43";
+ results[4][57]="3.887013961679578E-10";
+ results[4][58]="3.575599102375792E+38";
+ results[4][59]="7.626917638530619E-15";
+ results[4][60]="1.846852478880778E+34";
+ results[4][61]="3.525688884584153E-20";
+ results[4][62]="1.320392165821326E+29";
+ results[4][63]="2.998729163210665E-25";
+ results[4][64]="1.379667092536635E+24";
+ results[4][65]="3.253520607642641E-9";
+ results[4][66]="2.900548840094181E+47";
+ results[4][67]="1.050240634798815E-13";
+ results[4][68]="6.187900791446503E+42";
+ results[4][69]="4.664671802266443E-19";
+ results[4][70]="4.543334931485233E+37";
+ results[4][71]="2.850716892513680E-24";
+ results[4][72]="1.107363471446723E+33";
+ results[4][73]="5.401798587640085E-29";
+ results[4][74]="3.092737437336386E+27";
+ results[5][0]="79820.99267697315";
+ results[5][1]="0.1755168716666387";
+ results[5][2]="0.000003938031784503595";
+ results[5][3]="4.592174586052730E-11";
+ results[5][4]="3.205191941956922E-16";
+ results[5][5]="1";
+ results[5][6]="621454212.7120434";
+ results[5][7]="0.000009589937630824491";
+ results[5][8]="916.1405769180272";
+ results[5][9]="8.939192272132398E-11";
+ results[5][10]="0.03262414588473695";
+ results[5][11]="1.083264689633546E-15";
+ results[5][12]="1.454529705315602E-7";
+ results[5][13]="1.362930152886002E-20";
+ results[5][14]="1.095896548766010E-12";
+ results[5][15]="0.0001177262787348659";
+ results[5][16]="1352440182592.445";
+ results[5][17]="1.393328095835799E-9";
+ results[5][18]="10614117.55214028";
+ results[5][19]="8.980645128168683E-15";
+ results[5][20]="359.1900862796728";
+ results[5][21]="1.674444831077185E-19";
+ results[5][22]="0.002063546331483886";
+ results[5][23]="1.835204879954603E-24";
+ results[5][24]="1.093035388830462E-8";
+ results[5][25]="1.094201192231903E-8";
+ results[5][26]="2.930788381742739E+16";
+ results[5][27]="1.275596606371755E-13";
+ results[5][28]="451993382737.0138";
+ results[5][29]="2.177464195715552E-18";
+ results[5][30]="1018667.387429325";
+ results[5][31]="2.656803272979331E-23";
+ results[5][32]="20.71004276966202";
+ results[5][33]="1.143185655111196E-28";
+ results[5][34]="0.0005478959823343203";
+ results[5][35]="1.344961535532028E-12";
+ results[5][36]="2.834076974930183E+20";
+ results[5][37]="1.137943505635324E-17";
+ results[5][38]="1387015700062728";
+ results[5][39]="1.212818267950047E-22";
+ results[5][40]="25147816342.61536";
+ results[5][41]="1.941701364608288E-27";
+ results[5][42]="90818.14402590475";
+ results[5][43]="3.502762589487909E-32";
+ results[5][44]="2.385720415486439";
+ results[5][45]="3.072452672605791E-16";
+ results[5][46]="1.672824418802933E+24";
+ results[5][47]="1.116915475458918E-21";
+ results[5][48]="1.385198584609954E+19";
+ results[5][49]="4.730210572065213E-26";
+ results[5][50]="466831930796205.5";
+ results[5][51]="1.177389699953815E-31";
+ results[5][52]="8365081701.561654";
+ results[5][53]="2.452509046236414E-36";
+ results[5][54]="34113.74731325223";
+ results[5][55]="1.242121553179516E-20";
+ results[5][56]="1.433837858906067E+28";
+ results[5][57]="1.245862582824943E-25";
+ results[5][58]="1.146048143060329E+23";
+ results[5][59]="2.444573495698746E-30";
+ results[5][60]="5.919516683291835E+18";
+ results[5][61]="1.130050960271621E-35";
+ results[5][62]="42321103301135.62";
+ results[5][63]="9.611502550034045E-41";
+ results[5][64]="442209784.7581557";
+ results[5][65]="1.042815803460698E-24";
+ results[5][66]="9.296815769522365E+31";
+ results[5][67]="3.366222819772885E-29";
+ results[5][68]="1.983340975437319E+27";
+ results[5][69]="1.495116847249808E-34";
+ results[5][70]="1.456226051200787E+22";
+ results[5][71]="9.137094812685324E-40";
+ results[5][72]="3.549312475498482E+17";
+ results[5][73]="1.731380130517828E-44";
+ results[5][74]="991281711273.9084";
+ results[6][0]="0.0001284422746587108";
+ results[6][1]="2.824292893609623E-10";
+ results[6][2]="6.336801173682476E-15";
+ results[6][3]="7.389401330167758E-20";
+ results[6][4]="5.157567325787970E-25";
+ results[6][5]="1.609129006682524E-9";
+ results[6][6]="1";
+ results[6][7]="1.543144681403597E-14";
+ results[6][8]="0.000001474188376517659";
+ results[6][9]="1.438431358140050E-19";
+ results[6][10]="5.249645946137250E-11";
+ results[6][11]="1.743112634004281E-24";
+ results[6][12]="2.340525939904718E-16";
+ results[6][13]="2.193130443091112E-29";
+ results[6][14]="1.763438924942655E-21";
+ results[6][15]="1.894367699610646E-13";
+ results[6][16]="2176.250727612512";
+ results[6][17]="2.242044654835111E-18";
+ results[6][18]="0.01707948443348703";
+ results[6][19]="1.445101657445832E-23";
+ results[6][20]="5.779831867454199E-7";
+ results[6][21]="2.694397747775916E-28";
+ results[6][22]="3.320512258624031E-12";
+ results[6][23]="2.953081405540270E-33";
+ results[6][24]="1.758834949497607E-17";
+ results[6][25]="1.760710877566955E-17";
+ results[6][26]="47160165.97510373";
+ results[6][27]="2.052599500138579E-22";
+ results[6][28]="727.3156629906847";
+ results[6][29]="3.503820798338526E-27";
+ results[6][30]="0.001639167241274031";
+ results[6][31]="4.275139211600108E-32";
+ results[6][32]="3.332513055029883E-8";
+ results[6][33]="1.839533197662788E-37";
+ results[6][34]="8.816353178189703E-13";
+ results[6][35]="2.164216619696854E-21";
+ results[6][36]="456039546753.1217";
+ results[6][37]="1.831097902883797E-26";
+ results[6][38]="2231887.195695002";
+ results[6][39]="1.951581054792877E-31";
+ results[6][40]="40.46608073162718";
+ results[6][41]="3.124447988106234E-36";
+ results[6][42]="0.0001461381098851545";
+ results[6][43]="5.636396886267384E-41";
+ results[6][44]="3.838931922393911E-9";
+ results[6][45]="4.943972717149220E-25";
+ results[6][46]="2691790295382633";
+ results[6][47]="1.797261089573547E-30";
+ results[6][48]="22289632225.11453";
+ results[6][49]="7.611519039226468E-35";
+ results[6][50]="751192.8010897827";
+ results[6][51]="1.894571918364917E-40";
+ results[6][52]="13.46049560925206";
+ results[6][53]="3.946403445450303E-45";
+ results[6][54]="0.00005489342032839216";
+ results[6][55]="1.998733821046708E-29";
+ results[6][56]="2.307230089645316E+19";
+ results[6][57]="2.004753620364024E-34";
+ results[6][58]="184413931005301.8";
+ results[6][59]="3.933634120896147E-39";
+ results[6][60]="9525266000.626017";
+ results[6][61]="1.818397779202506E-44";
+ results[6][62]="68100.11491666482";
+ results[6][63]="1.546614755106283E-49";
+ results[6][64]="0.7115725916931837";
+ results[6][65]="1.678025157975551E-33";
+ results[6][66]="1.495977592452194E+23";
+ results[6][67]="5.416686782253186E-38";
+ results[6][68]="3.191451493718201E+18";
+ results[6][69]="2.405835887289389E-43";
+ results[6][70]="23432555792739.37";
+ results[6][71]="1.470276429990037E-48";
+ results[6][72]="571130165.8104760";
+ results[6][73]="2.786013989610011E-53";
+ results[6][74]="1595.100155404736";
+ results[7][0]="8323411032.456378";
+ results[7][1]="18302.19115320239";
+ results[7][2]="0.4106420642242513";
+ results[7][3]="0.000004788534360528390";
+ results[7][4]="3.342244825091065E-11";
+ results[7][5]="104275.9649224148";
+ results[7][6]="64802737685647.92";
+ results[7][7]="1";
+ results[7][8]="95531442.66270503";
+ results[7][9]="0.000009321428998035992";
+ results[7][10]="3401.914291900572";
+ results[7][11]="1.129584707779182E-10";
+ results[7][12]="0.01516724885301000";
+ results[7][13]="1.421208568140421E-15";
+ results[7][14]="1.142756700777198E-7";
+ results[7][15]="12.27602131180330";
+ results[7][16]="1.410270050396740E+17";
+ results[7][17]="0.0001452906316467887";
+ results[7][18]="1106797349549.367";
+ results[7][19]="9.364654363655727E-10";
+ results[7][20]="37454892.83737830";
+ results[7][21]="1.746043504699232E-14";
+ results[7][22]="215.1782848775914";
+ results[7][23]="1.913677596875906E-19";
+ results[7][24]="0.001139773198646432";
+ results[7][25]="0.001140988851392383";
+ results[7][26]="3.056107864896266E+21";
+ results[7][27]="1.330140669811724E-8";
+ results[7][28]="4.713204612344845E+16";
+ results[7][29]="2.270571800922490E-13";
+ results[7][30]="106222524759.1882";
+ results[7][31]="2.770407248989495E-18";
+ results[7][32]="2159559.693390987";
+ results[7][33]="1.192067872721828E-23";
+ results[7][34]="57.13238223502557";
+ results[7][35]="1.402471619011349E-7";
+ results[7][36]="2.955261112252432E+25";
+ results[7][37]="1.186601570773187E-12";
+ results[7][38]="1.446324004865796E+20";
+ results[7][39]="1.264677951660229E-17";
+ results[7][40]="2622312814817888";
+ results[7][41]="2.024727833856987E-22";
+ results[7][42]="9470149600.764056";
+ results[7][43]="3.652539489129880E-27";
+ results[7][44]="248773.2983599527";
+ results[7][45]="3.203829671144209E-11";
+ results[7][46]="1.744353804164535E+29";
+ results[7][47]="1.164674389402563E-16";
+ results[7][48]="1.444429190193662E+24";
+ results[7][49]="4.932472716883077E-21";
+ results[7][50]="4.867935004036829E+19";
+ results[7][51]="1.227734470523965E-26";
+ results[7][52]="872276966085176.7";
+ results[7][53]="2.557377472772532E-31";
+ results[7][54]="3557243918.208811";
+ results[7][55]="1.295234235087226E-15";
+ results[7][56]="1.495148262797194E+33";
+ results[7][57]="1.299135229848029E-20";
+ results[7][58]="1.195052759651575E+28";
+ results[7][59]="2.549102600877473E-25";
+ results[7][60]="6.172633140245884E+23";
+ results[7][61]="1.178371542938247E-30";
+ results[7][62]="4.413073883307109E+18";
+ results[7][63]="1.002248702759050E-35";
+ results[7][64]="46111852003790.03";
+ results[7][65]="1.087406241422075E-19";
+ results[7][66]="9.694344350728666E+36";
+ results[7][67]="3.510161326756695E-24";
+ results[7][68]="2.068147939838898E+32";
+ results[7][69]="1.559047519187323E-29";
+ results[7][70]="1.518493766341199E+27";
+ results[7][71]="9.527793781803528E-35";
+ results[7][72]="3.701079831937688E+22";
+ results[7][73]="1.805413337572430E-39";
+ results[7][74]="1.033668569530294E+17";
+ results[8][0]="87.12745040231444";
+ results[8][1]="0.0001915829034197918";
+ results[8][2]="4.298501653263149E-9";
+ results[8][3]="5.012521769858929E-14";
+ results[8][4]="3.498580919469208E-19";
+ results[8][5]="0.001091535540718088";
+ results[8][6]="678339.3601041740";
+ results[8][7]="1.046775775731475E-8";
+ results[8][8]="1";
+ results[8][9]="9.757446070344992E-14";
+ results[8][10]="0.00003561041471876213";
+ results[8][11]="1.182421908739965E-18";
+ results[8][12]="1.587670868382187E-10";
+ results[8][13]="1.487686701391408E-23";
+ results[8][14]="1.196210031928393E-15";
+ results[8][15]="1.285024173155902E-7";
+ results[8][16]="1476236525.994914";
+ results[8][17]="1.520867136485833E-12";
+ results[8][18]="11585.68654152080";
+ results[8][19]="9.802693335972867E-18";
+ results[8][20]="0.3920687450478594";
+ results[8][21]="1.827716044092442E-22";
+ results[8][22]="0.000002252434160733091";
+ results[8][23]="2.003191350969721E-27";
+ results[8][24]="1.193086974171064E-11";
+ results[8][25]="1.194359490017227E-11";
+ results[8][26]="31990596809958.51";
+ results[8][27]="1.392359031474151E-16";
+ results[8][28]="493366841.4268441";
+ results[8][29]="2.376779558264652E-21";
+ results[8][30]="1111.911657549550";
+ results[8][31]="2.899995197153080E-26";
+ results[8][32]="0.02260574773287777";
+ results[8][33]="1.247827772192961E-31";
+ results[8][34]="5.980479373345604E-7";
+ results[8][35]="1.468073316931983E-15";
+ results[8][36]="3.093495743267101E+17";
+ results[8][37]="1.242105779730290E-20";
+ results[8][38]="1513976932152.447";
+ results[8][39]="1.323834243899629E-25";
+ results[8][40]="27449735.30941583";
+ results[8][41]="2.119436048930757E-30";
+ results[8][42]="99.13123194632914";
+ results[8][43]="3.823389857123776E-35";
+ results[8][44]="0.002604098623720172";
+ results[8][45]="3.353691289323497E-19";
+ results[8][46]="1.825947306504481E+21";
+ results[8][47]="1.219152937441450E-24";
+ results[8][48]="1.511993486054156E+16";
+ results[8][49]="5.163192954489619E-29";
+ results[8][50]="509563644006.1053";
+ results[8][51]="1.285162702774995E-34";
+ results[8][52]="9130783.978265085";
+ results[8][53]="2.677000787899666E-39";
+ results[8][54]="37.23636761949100";
+ results[8][55]="1.355819821187394E-23";
+ results[8][56]="1.565084982623100E+25";
+ results[8][57]="1.359903288004258E-28";
+ results[8][58]="1.250952279524317E+20";
+ results[8][59]="2.668338852452637E-33";
+ results[8][60]="6461362843686697";
+ results[8][61]="1.233490785959079E-38";
+ results[8][62]="46194988375.59113";
+ results[8][63]="1.049129663306469E-43";
+ results[8][64]="482687.6965168229";
+ results[8][65]="1.138270511899841E-27";
+ results[8][66]="1.014780482794204E+29";
+ results[8][67]="3.674351845758363E-32";
+ results[8][68]="2.164887164052315E+24";
+ results[8][69]="1.631973176299542E-37";
+ results[8][70]="1.589522490205218E+19";
+ results[8][71]="9.973463726956913E-43";
+ results[8][72]="387420071212069.1";
+ results[8][73]="1.889862946953332E-47";
+ results[8][74]="1082019218.719317";
+ results[9][0]="892932943458573.4";
+ results[9][1]="1963453367.188511";
+ results[9][2]="44053.55276650961";
+ results[9][3]="0.5137124749367641";
+ results[9][4]="0.000003585549839831714";
+ results[9][5]="11186693042.92137";
+ results[9][6]="6.952017517839994E+18";
+ results[9][7]="107279.6885767942";
+ results[9][8]="10248583418146.87";
+ results[9][9]="1";
+ results[9][10]="364956305.8000387";
+ results[9][11]="0.00001211814956716597";
+ results[9][12]="1627.137733517652";
+ results[9][13]="1.524668125927760E-10";
+ results[9][14]="0.01225945829784226";
+ results[9][15]="1316967.743292346";
+ results[9][16]="1.512933318157422E+22";
+ results[9][17]="15.58673371619321";
+ results[9][18]="1.187368749772774E+17";
+ results[9][19]="0.0001004637203762303";
+ results[9][20]="4018149239271.144";
+ results[9][21]="1.873150034256679E-9";
+ results[9][22]="23084259.39015671";
+ results[9][23]="2.052987366292351E-14";
+ results[9][24]="122.2745137989658";
+ results[9][25]="122.4049286469690";
+ results[9][26]="3.278583000031628E+26";
+ results[9][27]="0.001426970768207302";
+ results[9][28]="5.056311230110650E+21";
+ results[9][29]="2.435862356942155E-8";
+ results[9][30]="1.139551937600652E+16";
+ results[9][31]="2.972084269024861E-13";
+ results[9][32]="231676891369.9822";
+ results[9][33]="1.278846701479992E-18";
+ results[9][34]="6129144.173823912";
+ results[9][35]="0.01504567185253299";
+ results[9][36]="3.170394917855513E+30";
+ results[9][37]="1.272982469772824E-7";
+ results[9][38]="1.551611888231443E+25";
+ results[9][39]="1.356742568040473E-12";
+ results[9][40]="2.813209021245996E+20";
+ results[9][41]="2.172121714689447E-17";
+ results[9][42]="1015954699945620";
+ results[9][43]="3.918432989082965E-22";
+ results[9][44]="26688321974.27763";
+ results[9][45]="0.000003437058493734438";
+ results[9][46]="1.871337328785176E+34";
+ results[9][47]="1.249459057884749E-11";
+ results[9][48]="1.549579136952070E+29";
+ results[9][49]="5.291541369807505E-16";
+ results[9][50]="5.222305512451464E+24";
+ results[9][51]="1.317109716528063E-21";
+ results[9][52]="9.357760127432864E+19";
+ results[9][53]="2.743546588523462E-26";
+ results[9][54]="381620019737136.4";
+ results[9][55]="1.389523253741598E-10";
+ results[9][56]="1.603990400090178E+38";
+ results[9][57]="1.393708228772385E-15";
+ results[9][58]="1.282048878882594E+33";
+ results[9][59]="2.734669331724314E-20";
+ results[9][60]="6.621981609843777E+28";
+ results[9][61]="1.264153321541716E-25";
+ results[9][62]="4.734331918675705E+23";
+ results[9][63]="1.075209287084869E-30";
+ results[9][64]="4.946865122665819E+18";
+ results[9][65]="1.166566029362225E-14";
+ results[9][66]="1.040006242902376E+42";
+ results[9][67]="3.765690139887650E-19";
+ results[9][68]="2.218702669166555E+37";
+ results[9][69]="1.672541323348396E-24";
+ results[9][70]="1.629035383588871E+32";
+ results[9][71]="1.022138749735799E-29";
+ results[9][72]="3.970506917681290E+27";
+ results[9][73]="1.936841806071609E-34";
+ results[9][74]="1.108916422308302E+22";
+ results[10][0]="2446684.518852554";
+ results[10][1]="5.379968330412397";
+ results[10][2]="0.0001207091152184304";
+ results[10][3]="1.407599942164664E-9";
+ results[10][4]="9.824600322966481E-15";
+ results[10][5]="30.65214346248511";
+ results[10][6]="19048903683.41529";
+ results[10][7]="0.0002939521440563168";
+ results[10][8]="28081.67239549524";
+ results[10][9]="2.740054039641405E-9";
+ results[10][10]="1";
+ results[10][11]="3.320438467449187E-14";
+ results[10][12]="0.000004458445319778002";
+ results[10][13]="4.177673057560849E-19";
+ results[10][14]="3.359157823281803E-11";
+ results[10][15]="0.003608562785085618";
+ results[10][16]="41455190501253.18";
+ results[10][17]="4.270849268387010E-8";
+ results[10][18]="325345453.9358852";
+ results[10][19]="2.752760228542944E-13";
+ results[10][20]="11009.94605494694";
+ results[10][21]="5.132532318219450E-18";
+ results[10][22]="0.06325211819412893";
+ results[10][23]="5.625296326342124E-23";
+ results[10][24]="3.350387754800450E-7";
+ results[10][25]="3.353961192111453E-7";
+ results[10][26]="8.983494593536299E+17";
+ results[10][27]="3.909977017876616E-12";
+ results[10][28]="13854566011748.89";
+ results[10][29]="6.674394491149785E-17";
+ results[10][30]="31224338.90003856";
+ results[10][31]="8.143671507496243E-22";
+ results[10][32]="634.8072020898827";
+ results[10][33]="3.504109070472339E-27";
+ results[10][34]="0.01679418625303079";
+ results[10][35]="4.122595393865199E-11";
+ results[10][36]="8.687053401928578E+21";
+ results[10][37]="3.488040758693718E-16";
+ results[10][38]="4.251500422304194E+16";
+ results[10][39]="3.717547954312753E-21";
+ results[10][40]="770834474302.0734";
+ results[10][41]="5.951730878927634E-26";
+ results[10][42]="2783770.779678667";
+ results[10][43]="1.073671814080092E-30";
+ results[10][44]="73.12744443686990";
+ results[10][45]="9.417726010240848E-15";
+ results[10][46]="5.127565407269577E+25";
+ results[10][47]="3.423585338923651E-20";
+ results[10][48]="4.245930573949562E+20";
+ results[10][49]="1.449910930627067E-24";
+ results[10][50]="1.430939931563421E+16";
+ results[10][51]="3.608951799423663E-30";
+ results[10][52]="256407684391.6768";
+ results[10][53]="7.517465912828107E-35";
+ results[10][54]="1045659.476688773";
+ results[10][55]="3.807368804590335E-19";
+ results[10][56]="4.395020375313125E+29";
+ results[10][57]="3.818835862329240E-24";
+ results[10][58]="3.512883209599986E+24";
+ results[10][59]="7.493141749474667E-29";
+ results[10][60]="1.814458746048353E+20";
+ results[10][61]="3.463848415416480E-34";
+ results[10][62]="1297232529877061";
+ results[10][63]="2.946131550536850E-39";
+ results[10][64]="13554677762.92165";
+ results[10][65]="3.196453961262399E-23";
+ results[10][66]="2.849673307116934E+33";
+ results[10][67]="1.031819447983696E-27";
+ results[10][68]="6.079365211412986E+28";
+ results[10][69]="4.582853609507953E-33";
+ results[10][70]="4.463644983521472E+23";
+ results[10][71]="2.800715410287590E-38";
+ results[10][72]="1.087940351921676E+19";
+ results[10][73]="5.307051214872866E-43";
+ results[10][74]="30384909225705.58";
+ results[11][0]="7.368558528753992E+19";
+ results[11][1]="162025840356721.7";
+ results[11][2]="3635336609.961668";
+ results[11][3]="42391.98997251724";
+ results[11][4]="0.2958826196985332";
+ results[11][5]="923135416089567.4";
+ results[11][6]="5.736863932325467E+23";
+ results[11][7]="8852811065.104166";
+ results[11][8]="8.457218126697593E+17";
+ results[11][9]="82520.84977639587";
+ results[11][10]="30116504485873.39";
+ results[11][11]="1";
+ results[11][12]="134272788.4731154";
+ results[11][13]="0.00001258169093785437";
+ results[11][14]="1011.660916536231";
+ results[11][15]="108677297304.5868";
+ results[11][16]="1.248485430693727E+27";
+ results[11][17]="1286230.511498665";
+ results[11][18]="9.798267822918602E+21";
+ results[11][19]="8.290351577144743";
+ results[11][20]="3.315810897530334E+17";
+ results[11][21]="0.0001545739325855462";
+ results[11][22]="1904932701334.478";
+ results[11][23]="1.694142620466497E-9";
+ results[11][24]="10090196.78468630";
+ results[11][25]="10100958.72876698";
+ results[11][26]="2.705514552250553E+31";
+ results[11][27]="117.7548403985430";
+ results[11][28]="4.172510994426643E+26";
+ results[11][29]="0.002010094316332011";
+ results[11][30]="9.403679425514422E+20";
+ results[11][31]="2.452589194869899E-8";
+ results[11][32]="1.911817394940469E+16";
+ results[11][33]="1.055315165398698E-13";
+ results[11][34]="505782185625.9951";
+ results[11][35]="1241.581626727822";
+ results[11][36]="2.616236827482037E+35";
+ results[11][37]="0.01050475951561086";
+ results[11][38]="1.280403315400169E+30";
+ results[11][39]="1.119595496425095E-7";
+ results[11][40]="2.321483990318425E+25";
+ results[11][41]="1.792453297139352E-12";
+ results[11][42]="8.383744517383584E+19";
+ results[11][43]="3.233524200509892E-17";
+ results[11][44]="2202343008423450";
+ results[11][45]="0.2836289876341450";
+ results[11][46]="1.544243465896434E+39";
+ results[11][47]="0.000001031064232174645";
+ results[11][48]="1.278725871770590E+34";
+ results[11][49]="4.366624904634691E-11";
+ results[11][50]="4.309490886794513E+29";
+ results[11][51]="1.086890130566436E-16";
+ results[11][52]="7.722103177194344E+24";
+ results[11][53]="2.263997958860880E-21";
+ results[11][54]="3.149160832039346E+19";
+ results[11][55]="0.00001146646396828192";
+ results[11][56]="1.323626508486227E+43";
+ results[11][57]="1.150099873786527E-10";
+ results[11][58]="1.057957629402673E+38";
+ results[11][59]="2.256672371113390E-15";
+ results[11][60]="5.464515496479744E+33";
+ results[11][61]="1.043190063412758E-20";
+ results[11][62]="3.906810930526339E+28";
+ results[11][63]="8.872718405771617E-26";
+ results[11][64]="4.082195136515981E+23";
+ results[11][65]="9.626602006324680E-10";
+ results[11][66]="8.582219893706080E+46";
+ results[11][67]="3.107479503381239E-14";
+ results[11][68]="1.830892296607818E+42";
+ results[11][69]="1.380195312888473E-19";
+ results[11][70]="1.344293841695707E+37";
+ results[11][71]="8.434775821758094E-25";
+ results[11][72]="3.276496048901183E+32";
+ results[11][73]="1.598298317194785E-29";
+ results[11][74]="9.150872549988179E+26";
+ results[12][0]="548775266570.8102";
+ results[12][1]="1206691.558276256";
+ results[12][2]="27.07426166761666";
+ results[12][3]="0.0003157154212300068";
+ results[12][4]="2.203593319712548E-9";
+ results[12][5]="6875074.440525237";
+ results[12][6]="4272543973773303";
+ results[12][7]="65.93153509191260";
+ results[12][8]="6298534664.297173";
+ results[12][9]="0.0006145761230907817";
+ results[12][10]="224293.4315161216";
+ results[12][11]="7.447525380023099E-9";
+ results[12][12]="1";
+ results[12][13]="9.370246258327704E-14";
+ results[12][14]="0.000007534370351881011";
+ results[12][15]="809.3769299082260";
+ results[12][16]="9.298126931680603E+18";
+ results[12][17]="0.009579234378946397";
+ results[12][18]="72972848291449.96";
+ results[12][19]="6.174260378010000E-8";
+ results[12][20]="2469458581.471433";
+ results[12][21]="1.151193286020835E-12";
+ results[12][22]="14187.03464042448";
+ results[12][23]="1.261717016330308E-17";
+ results[12][24]="0.07514699664337871";
+ results[12][25]="0.07522714649505796";
+ results[12][26]="2.014938829390782E+23";
+ results[12][27]="8.769821624887181E-7";
+ results[12][28]="3.107488152941784E+18";
+ results[12][29]="1.497022843712283E-11";
+ results[12][30]="7003414118711.969";
+ results[12][31]="1.826572027556399E-16";
+ results[12][32]="142383085.7078879";
+ results[12][33]="7.859486478230080E-22";
+ results[12][34]="3766.825664213152";
+ results[12][35]="0.000009246710676425823";
+ results[12][36]="1.948449017282359E+27";
+ results[12][37]="7.823446310355102E-11";
+ results[12][38]="9.535836188108477E+21";
+ results[12][39]="8.338215874985453E-16";
+ results[12][40]="1.728931093721377E+17";
+ results[12][41]="1.334934142295141E-20";
+ results[12][42]="624381500728.4375";
+ results[12][43]="2.408175355021632E-25";
+ results[12][44]="16402005.45075007";
+ results[12][45]="2.112334083915552E-9";
+ results[12][46]="1.150079240519853E+31";
+ results[12][47]="7.678877037554697E-15";
+ results[12][48]="9.523343384103629E+25";
+ results[12][49]="3.252054980230781E-19";
+ results[12][50]="3.209504275438039E+21";
+ results[12][51]="8.094641832690152E-25";
+ results[12][52]="5.751055939931189E+16";
+ results[12][53]="1.686118225893689E-29";
+ results[12][54]="234534552223.8769";
+ results[12][55]="8.539678142289999E-14";
+ results[12][56]="9.857742015622534E+34";
+ results[12][57]="8.565397999586525E-19";
+ results[12][58]="7.879166295965479E+29";
+ results[12][59]="1.680662475826388E-23";
+ results[12][60]="4.069711784956242E+25";
+ results[12][61]="7.769184473454425E-29";
+ results[12][62]="2.909607356004657E+20";
+ results[12][63]="6.607979551678220E-34";
+ results[12][64]="3040225188540963";
+ results[12][65]="7.169436276548434E-18";
+ results[12][66]="6.391630047531518E+38";
+ results[12][67]="2.314303246933335E-22";
+ results[12][68]="1.363561684707550E+34";
+ results[12][69]="1.027903962212583E-27";
+ results[12][70]="1.001166250423753E+29";
+ results[12][71]="6.281820700734860E-33";
+ results[12][72]="2.440178748173697E+24";
+ results[12][73]="1.190336728215637E-37";
+ results[12][74]="6.815135556539365E+18";
+ results[13][0]="5.856572510920854E+24";
+ results[13][1]="1.287790656733084E+19";
+ results[13][2]="288938635348614.2";
+ results[13][3]="3369339636.612199";
+ results[13][4]="23516.92003563011";
+ results[13][5]="7.337133145689837E+19";
+ results[13][6]="4.559692302618115E+28";
+ results[13][7]="703626492562206.3";
+ results[13][8]="6.721845393016666E+22";
+ results[13][9]="6558804391.555706";
+ results[13][10]="2.393677021207241E+18";
+ results[13][11]="79480.57259865707";
+ results[13][12]="10672078112261.57";
+ results[13][13]="1";
+ results[13][14]="80407388.92198187";
+ results[13][15]="8637733818243049";
+ results[13][16]="9.923033691261843E+31";
+ results[13][17]="102230337547.7774";
+ results[13][18]="7.787719370405676E+26";
+ results[13][19]="658921.8903956439";
+ results[13][20]="2.635425487645780E+22";
+ results[13][21]="12.28562467072543";
+ results[13][22]="1.514051418639709E+17";
+ results[13][23]="0.0001346514255384665";
+ results[13][24]="801974618079.9959";
+ results[13][25]="802829983557.8030";
+ results[13][26]="2.150358457868733E+36";
+ results[13][27]="9359222.141139671";
+ results[13][28]="3.316335630112216E+31";
+ results[13][29]="159.7634472393744";
+ results[13][30]="7.474098252740968E+25";
+ results[13][31]="0.001949331935575389";
+ results[13][32]="1.519523412539414E+21";
+ results[13][33]="8.387705361793504E-9";
+ results[13][34]="4.019985772375435E+16";
+ results[13][35]="98681618.62029944";
+ results[13][36]="2.079400011019663E+40";
+ results[13][37]="834.9243013119425";
+ results[13][38]="1.017671886652243E+35";
+ results[13][39]="0.008898609113474424";
+ results[13][40]="1.845128768291237E+30";
+ results[13][41]="1.424652144129865E-7";
+ results[13][42]="6.663448147624991E+24";
+ results[13][43]="2.570023549681410E-12";
+ results[13][44]="1.750434833681448E+20";
+ results[13][45]="22542.99434273927";
+ results[13][46]="1.227373549011834E+44";
+ results[13][47]="0.08194957555923548";
+ results[13][48]="1.016338644850434E+39";
+ results[13][49]="0.000003470618477439216";
+ results[13][50]="3.425208032911223E+34";
+ results[13][51]="8.638664992924948E-12";
+ results[13][52]="6.137571821893155E+29";
+ results[13][53]="1.799438541324536E-16";
+ results[13][54]="2.502971061357505E+24";
+ results[13][55]="0.9113611218809168";
+ results[13][56]="1.052025928012465E+48";
+ results[13][57]="0.000009141059651419642";
+ results[13][58]="8.408707817004228E+42";
+ results[13][59]="1.793616122236614E-10";
+ results[13][60]="4.343228206344449E+38";
+ results[13][61]="8.291334356927543E-16";
+ results[13][62]="3.105155697929257E+33";
+ results[13][63]="7.052087393973718E-21";
+ results[13][64]="3.244552069097433E+28";
+ results[13][65]="0.00007651278396420666";
+ results[13][66]="6.821197513193451E+51";
+ results[13][67]="2.469842502673314E-9";
+ results[13][68]="1.455203681008597E+47";
+ results[13][69]="1.096987137663585E-14";
+ results[13][70]="1.068452442788232E+42";
+ results[13][71]="6.704008120546416E-20";
+ results[13][72]="2.604177820839036E+37";
+ results[13][73]="1.270336654341115E-24";
+ results[13][74]="7.273165900503936E+31";
+ results[14][0]="7.283624788019671E+16";
+ results[14][1]="160158248389.6609";
+ results[14][2]="3593433.877438394";
+ results[14][3]="41.90335840753915";
+ results[14][4]="0.0002924721266406031";
+ results[14][5]="912494889345.1759";
+ results[14][6]="5.670737930617694E+20";
+ results[14][7]="8750769.077266332";
+ results[14][8]="835973594359440.8";
+ results[14][9]="81.56967263194704";
+ results[14][10]="29769366389.07392";
+ results[14][11]="0.0009884734930986993";
+ results[14][12]="132725.0922501232";
+ results[14][13]="1.243666799042916E-8";
+ results[14][14]="1";
+ results[14][15]="107424627.6871908";
+ results[14][16]="1.234094754760663E+24";
+ results[14][17]="1271.404766631212";
+ results[14][18]="9.685328021236938E+18";
+ results[14][19]="0.008194792782476575";
+ results[14][20]="327759118033654.3";
+ results[14][21]="1.527922350848377E-7";
+ results[14][22]="1882975481.406032";
+ results[14][23]="1.674615073859902E-12";
+ results[14][24]="9973.892061812134";
+ results[14][25]="9984.529958270096";
+ results[14][26]="2.674329420092467E+28";
+ results[14][27]="0.1163975384180276";
+ results[14][28]="4.124416517653632E+23";
+ results[14][29]="0.000001986924950322545";
+ results[14][30]="9.295287849718610E+17";
+ results[14][31]="2.424319408589176E-11";
+ results[14][32]="18897808185436.61";
+ results[14][33]="1.043151067861683E-16";
+ results[14][34]="499952283.7728221";
+ results[14][35]="1.227270527538816";
+ results[14][36]="2.586080755634628E+32";
+ results[14][37]="0.00001038367633255766";
+ results[14][38]="1.265644737748760E+27";
+ results[14][39]="1.106690471208886E-10";
+ results[14][40]="2.294725389082761E+22";
+ results[14][41]="1.771792571839617E-15";
+ results[14][42]="8.287109228345220E+16";
+ results[14][43]="3.196252961497192E-20";
+ results[14][44]="2176957686537.825";
+ results[14][45]="0.0002803597361507711";
+ results[14][46]="1.526443732929490E+36";
+ results[14][47]="1.019179663186800E-9";
+ results[14][48]="1.263986629184754E+31";
+ results[14][49]="4.316292972536028E-14";
+ results[14][50]="4.259817510346784E+26";
+ results[14][51]="1.074362083975506E-19";
+ results[14][52]="7.633094301629857E+21";
+ results[14][53]="2.237901970763539E-24";
+ results[14][54]="3.112862007975538E+16";
+ results[14][55]="1.133429569221800E-8";
+ results[14][56]="1.308369718401416E+40";
+ results[14][57]="1.136843239654142E-13";
+ results[14][58]="1.045763073486079E+35";
+ results[14][59]="2.230660821453777E-18";
+ results[14][60]="5.401528720897306E+30";
+ results[14][61]="1.031165725947463E-23";
+ results[14][62]="3.861779047373550E+25";
+ results[14][63]="8.770446955834192E-29";
+ results[14][64]="4.035141686102474E+20";
+ results[14][65]="9.515640911862703E-13";
+ results[14][66]="8.483296876872797E+43";
+ results[14][67]="3.071661119439865E-17";
+ results[14][68]="1.809788503915430E+39";
+ results[14][69]="1.364286482089321E-22";
+ results[14][70]="1.328798829452025E+34";
+ results[14][71]="8.337552320037675E-28";
+ results[14][72]="3.238729494581439E+29";
+ results[14][73]="1.579875520611302E-32";
+ results[14][74]="9.045394954387817E+23";
+ results[15][0]="678021878.6728144";
+ results[15][1]="1490.889490034119";
+ results[15][2]="0.03345074546501661";
+ results[15][3]="3.900721772064906E-7";
+ results[15][4]="2.722579849122226E-12";
+ results[15][5]="8494.280212934647";
+ results[15][6]="5278806222284.789";
+ results[15][7]="0.08145961746078984";
+ results[15][8]="7781954.774781330";
+ results[15][9]="7.593200403679254E-7";
+ results[15][10]="277.1186368526144";
+ results[15][11]="9.201553818525026E-12";
+ results[15][12]="0.001235518289498798";
+ results[15][13]="1.157711062927156E-16";
+ results[15][14]="9.308852369606484E-9";
+ results[15][15]="1";
+ results[15][16]="1.148800588217273E+16";
+ results[15][17]="0.00001183531927458393";
+ results[15][18]="90159288700.90755";
+ results[15][19]="7.628411621159118E-11";
+ results[15][20]="3051061.242567714";
+ results[15][21]="1.422320359626963E-15";
+ results[15][22]="17.52834077199745";
+ results[15][23]="1.558874449847949E-20";
+ results[15][24]="0.00009284548875379919";
+ results[15][25]="0.00009294451536144952";
+ results[15][26]="2.489493775933610E+20";
+ results[15][27]="1.083527501319018E-9";
+ results[15][28]="3839358447360413";
+ results[15][29]="1.849599103204027E-14";
+ results[15][30]="8652846232.602745";
+ results[15][31]="2.256763147132834E-19";
+ results[15][32]="175916.9065073704";
+ results[15][33]="9.710539289921761E-25";
+ results[15][34]="4.653982001488808";
+ results[15][35]="1.142448015842791E-8";
+ results[15][36]="2.407344397008314E+24";
+ results[15][37]="9.666011003355619E-14";
+ results[15][38]="1.178170001607253E+19";
+ results[15][39]="1.030201821533375E-18";
+ results[15][40]="213612598757592.2";
+ results[15][41]="1.649335548082038E-23";
+ results[15][42]="771434763.7746916";
+ results[15][43]="2.975344695449488E-28";
+ results[15][44]="20264.97771886068";
+ results[15][45]="2.609827394209354E-12";
+ results[15][46]="1.420943936035166E+28";
+ results[15][47]="9.487393022711177E-18";
+ results[15][48]="1.176626492823741E+23";
+ results[15][49]="4.017973406530782E-22";
+ results[15][50]="3.965401232528285E+18";
+ results[15][51]="1.000107803123075E-27";
+ results[15][52]="71055347977156.85";
+ results[15][53]="2.083229906348919E-32";
+ results[15][54]="289771728.7920109";
+ results[15][55]="1.055092853123241E-16";
+ results[15][56]="1.217942055346239E+32";
+ results[15][57]="1.058270588532557E-21";
+ results[15][58]="9.734854064667849E+26";
+ results[15][59]="2.076489227357834E-26";
+ results[15][60]="5.028203343302236E+22";
+ results[15][61]="9.598969511443032E-32";
+ results[15][62]="3.594873103603994E+17";
+ results[15][63]="8.164279592732510E-37";
+ results[15][64]="3756253824637.292";
+ results[15][65]="8.857969645071753E-21";
+ results[15][66]="7.896975823435262E+35";
+ results[15][67]="2.859363989032589E-25";
+ results[15][68]="1.684705400315972E+31";
+ results[15][69]="1.269994145161927E-30";
+ results[15][70]="1.236959213227480E+26";
+ results[15][71]="7.761304367110075E-36";
+ results[15][72]="3.014885473014884E+21";
+ results[15][73]="1.470682798372580E-40";
+ results[15][74]="8420224625517956";
+ results[16][0]="5.901998011029744E-8";
+ results[16][1]="1.297779184068582E-13";
+ results[16][2]="2.911797383123386E-18";
+ results[16][3]="3.395473341564099E-23";
+ results[16][4]="2.369932499205253E-28";
+ results[16][5]="7.394042360403217E-13";
+ results[16][6]="0.0004595058773843880";
+ results[16][7]="7.090840507594115E-18";
+ results[16][8]="6.773982233816134E-10";
+ results[16][9]="6.609676632793603E-23";
+ results[16][10]="2.412243166437193E-14";
+ results[16][11]="8.009705002679486E-28";
+ results[16][12]="1.075485425556837E-19";
+ results[16][13]="1.007756328470993E-32";
+ results[16][14]="8.103105504195564E-25";
+ results[16][15]="8.704730918982346E-17";
+ results[16][16]="1";
+ results[16][17]="1.030232696254985E-21";
+ results[16][18]="0.000007848123479882456";
+ results[16][19]="6.640327050142802E-27";
+ results[16][20]="2.655866713388787E-10";
+ results[16][21]="1.238091601114291E-31";
+ results[16][22]="1.525794898764651E-15";
+ results[16][23]="1.356958262240303E-36";
+ results[16][24]="8.081949966432234E-21";
+ results[16][25]="8.090569966166392E-21";
+ results[16][26]="21670.37344398340";
+ results[16][27]="9.431815342299341E-26";
+ results[16][28]="0.3342058218579424";
+ results[16][29]="1.610026250138211E-30";
+ results[16][30]="7.532069813813702E-7";
+ results[16][31]="1.964451594366708E-35";
+ results[16][32]="1.531309335246434E-11";
+ results[16][33]="8.452763159697483E-41";
+ results[16][34]="4.051166102474697E-16";
+ results[16][35]="9.944702566836774E-25";
+ results[16][36]="209552852.0527718";
+ results[16][37]="8.414002484413322E-30";
+ results[16][38]="1025.565284080813";
+ results[16][39]="8.967629648693503E-35";
+ results[16][40]="0.01859440193089382";
+ results[16][41]="1.435702214116641E-39";
+ results[16][42]="6.715132040207400E-8";
+ results[16][43]="2.589957496510927E-44";
+ results[16][44]="1.764011781218549E-12";
+ results[16][45]="2.271784521158129E-28";
+ results[16][46]="1236893461414.578";
+ results[16][47]="8.258520338533136E-34";
+ results[16][48]="10242217.01217658";
+ results[16][49]="3.497537734347732E-38";
+ results[16][50]="345.1775071495967";
+ results[16][51]="8.705669316160942E-44";
+ results[16][52]="0.006185176844958069";
+ results[16][53]="1.813395577714413E-48";
+ results[16][54]="2.522384927062784E-8";
+ results[16][55]="9.184299380979178E-33";
+ results[16][56]="1.060185786670131E+16";
+ results[16][57]="9.211960712648993E-38";
+ results[16][58]="84739285168.49519";
+ results[16][59]="1.807527998031550E-42";
+ results[16][60]="4376915.710937338";
+ results[16][61]="8.355644669662702E-48";
+ results[16][62]="31.29240305475972";
+ results[16][63]="7.106785700207527E-53";
+ results[16][64]="0.0003269717880686592";
+ results[16][65]="7.710624224886317E-37";
+ results[16][66]="6.874104961671300E+19";
+ results[16][67]="2.488999412395668E-41";
+ results[16][68]="1466490718750697";
+ results[16][69]="1.105495730231758E-46";
+ results[16][70]="10767397108.90133";
+ results[16][71]="6.756006609601578E-52";
+ results[16][72]="262437.6679414338";
+ results[16][73]="1.280189802700927E-56";
+ results[16][74]="0.7329578964252270";
+ results[17][0]="57288009131181.63";
+ results[17][1]="125969520.1662847";
+ results[17][2]="2826.349225478968";
+ results[17][3]="0.03295831469829135";
+ results[17][4]="2.300385638914618E-7";
+ results[17][5]="717706047.1174538";
+ results[17][6]="4.460214464700500E+17";
+ results[17][7]="6882.756229121966";
+ results[17][8]="657519632063.7410";
+ results[17][9]="0.06415712350055034";
+ results[17][10]="23414546.78351770";
+ results[17][11]="7.774656183788081E-7";
+ results[17][12]="104.3924765216976";
+ results[17][13]="9.781832125249994E-12";
+ results[17][14]="0.0007865315800645127";
+ results[17][15]="84492.86215264814";
+ results[17][16]="9.706544974112313E+20";
+ results[17][17]="1";
+ results[17][18]="7617816351986589";
+ results[17][19]="0.000006445463315502565";
+ results[17][20]="257792896987.5612";
+ results[17][21]="1.201759180828659E-10";
+ results[17][22]="1481019.680613023";
+ results[17][23]="1.317137640042879E-15";
+ results[17][24]="7.844781082769998";
+ results[17][25]="7.853148124279642";
+ results[17][26]="2.103444544398340E+25";
+ results[17][27]="0.00009155033980755107";
+ results[17][28]="3.243983840474286E+20";
+ results[17][29]="1.562779220646795E-9";
+ results[17][30]="731103743959364.5";
+ results[17][31]="1.906803775018709E-14";
+ results[17][32]="14863722931.84754";
+ results[17][33]="8.204712576512332E-20";
+ results[17][34]="393228.2597126994";
+ results[17][35]="0.0009652870271917130";
+ results[17][36]="2.034034182903733E+29";
+ results[17][37]="8.167089352725064E-9";
+ results[17][38]="9.954695553818683E+23";
+ results[17][39]="8.704470049622648E-14";
+ results[17][40]="1.804873986089417E+19";
+ results[17][41]="1.393570811075580E-18";
+ results[17][42]="65180731155375.70";
+ results[17][43]="2.513953892092264E-23";
+ results[17][44]="1712245968.926182";
+ results[17][45]="2.205117862611359E-7";
+ results[17][46]="1.200596201140605E+33";
+ results[17][47]="8.016169908559313E-13";
+ results[17][48]="9.941654006331020E+27";
+ results[17][49]="3.394900731710114E-17";
+ results[17][50]="3.350480997199534E+23";
+ results[17][51]="8.450197074706576E-23";
+ results[17][52]="6.003669721842360E+18";
+ results[17][53]="1.760180573094133E-27";
+ results[17][54]="24483642736557.92";
+ results[17][55]="8.914781499718627E-12";
+ results[17][56]="1.029074101922827E+37";
+ results[17][57]="8.941631095708316E-17";
+ results[17][58]="8.225256825621270E+31";
+ results[17][59]="1.754485180486043E-21";
+ results[17][60]="4.248472919611204E+27";
+ results[17][61]="8.110444077378283E-27";
+ results[17][62]="3.037411175990747E+22";
+ results[17][63]="6.898233502044262E-32";
+ results[17][64]="3.173766366154361E+17";
+ results[17][65]="7.484352081733892E-16";
+ results[17][66]="6.672380896723107E+40";
+ results[17][67]="2.415958473695767E-20";
+ results[17][68]="1.423455811567193E+36";
+ results[17][69]="1.073054402418369E-25";
+ results[17][70]="1.045142242916776E+31";
+ results[17][71]="6.557748200149776E-31";
+ results[17][72]="2.547363026774680E+26";
+ results[17][73]="1.242621989531652E-35";
+ results[17][74]="7.114488785782220E+20";
+ results[18][0]="0.007520266502124582";
+ results[18][1]="1.653617183005917E-8";
+ results[18][2]="3.710182938109170E-13";
+ results[18][3]="4.326477979440449E-18";
+ results[18][4]="3.019744153210938E-23";
+ results[18][5]="9.421414404802356E-8";
+ results[18][6]="58.54977671570353";
+ results[18][7]="9.035077653620603E-13";
+ results[18][8]="0.00008631340028199442";
+ results[18][9]="8.421983483996608E-18";
+ results[18][10]="3.073655979828342E-9";
+ results[18][11]="1.020588555112725E-22";
+ results[18][12]="1.370372711787334E-14";
+ results[18][13]="1.284072977513965E-27";
+ results[18][14]="1.032489553071727E-19";
+ results[18][15]="1.109148058296442E-11";
+ results[18][16]="127418.9941790999";
+ results[18][17]="1.312712139272323E-16";
+ results[18][18]="1";
+ results[18][19]="8.461037937494653E-22";
+ results[18][20]="0.00003384078652937511";
+ results[18][21]="1.577563865155743E-26";
+ results[18][22]="1.944152513241934E-10";
+ results[18][23]="1.729022569176787E-31";
+ results[18][24]="1.029793935728606E-15";
+ results[18][25]="1.030892287424556E-15";
+ results[18][26]="2761217187.717842";
+ results[18][27]="1.201792424198785E-20";
+ results[18][28]="42584.16966993846";
+ results[18][29]="2.051479253945588E-25";
+ results[18][30]="0.09597287597629022";
+ results[18][31]="2.503084462677351E-30";
+ results[18][32]="0.000001951178952741667";
+ results[18][33]="1.077042579842804E-35";
+ results[18][34]="5.161955100297903E-11";
+ results[18][35]="1.267143998476655E-19";
+ results[18][36]="26701013635925.91";
+ results[18][37]="1.072103733584393E-24";
+ results[18][38]="130676496.9625801";
+ results[18][39]="1.142646350007201E-29";
+ results[18][40]="2369.279991396404";
+ results[18][41]="1.829357320634491E-34";
+ results[18][42]="0.008556353703430740";
+ results[18][43]="3.300097791720419E-39";
+ results[18][44]="2.247686068829500E-7";
+ results[18][45]="2.894684986776169E-23";
+ results[18][46]="1.576037207601508E+17";
+ results[18][47]="1.052292354943532E-28";
+ results[18][48]="1305052989855.606";
+ results[18][49]="4.456527402140359E-33";
+ results[18][50]="43982170.77425067";
+ results[18][51]="1.109267627921080E-38";
+ results[18][52]="788.1090124044157";
+ results[18][53]="2.310610405611983E-43";
+ results[18][54]="0.003213997503388622";
+ results[18][55]="1.170254189364097E-27";
+ results[18][56]="1.350878065804859E+21";
+ results[18][57]="1.173778768423119E-32";
+ results[18][58]="1.079739448362558E+16";
+ results[18][59]="2.303133994597421E-37";
+ results[18][60]="557702197494.3356";
+ results[18][61]="1.064667839526379E-42";
+ results[18][62]="3987246.522684476";
+ results[18][63]="9.055394857668533E-48";
+ results[18][64]="41.66241636065038";
+ results[18][65]="9.824799832280163E-32";
+ results[18][66]="8.758915400977171E+24";
+ results[18][67]="3.171458016398266E-36";
+ results[18][68]="1.868587723561991E+20";
+ results[18][69]="1.408611540154202E-41";
+ results[18][70]="1371970909543155";
+ results[18][71]="8.608435668627840E-47";
+ results[18][72]="33439543683.80610";
+ results[18][73]="1.631204970184925E-51";
+ results[18][74]="93392.75793813131";
+ results[19][0]="8.888113441495055E+18";
+ results[19][1]="19543904603925.69";
+ results[19][2]="438502104.0583787";
+ results[19][3]="5113.412812236528";
+ results[19][4]="0.03568999661175253";
+ results[19][5]="111350575123317.2";
+ results[19][6]="6.919928399829436E+22";
+ results[19][7]="1067845070.589050";
+ results[19][8]="1.020127801336300E+17";
+ results[19][9]="9953.842006398556";
+ results[19][10]="3632717407172.463";
+ results[19][11]="0.1206221462014772";
+ results[19][12]="16196271.92208414";
+ results[19][13]="0.000001517630563767670";
+ results[19][14]="122.0287109807536";
+ results[19][15]="13108888844.25527";
+ results[19][16]="1.505949921515530E+26";
+ results[19][17]="155147.8848067927";
+ results[19][18]="1.181888093857317E+21";
+ results[19][19]="1";
+ results[19][20]="3.999602268583552E+16";
+ results[19][21]="0.00001864503949527103";
+ results[19][22]="229777070804.3422";
+ results[19][23]="2.043511188520634E-10";
+ results[19][24]="1217101.191764106";
+ results[19][25]="1218399.320556418";
+ results[19][26]="3.263449718717902E+30";
+ results[19][27]="14.20384157448466";
+ results[19][28]="5.032972311970014E+25";
+ results[19][29]="0.0002424618905033581";
+ results[19][30]="1.134291994496223E+20";
+ results[19][31]="2.958365724357601E-9";
+ results[19][32]="2306075173230364";
+ results[19][33]="1.272943801693578E-14";
+ results[19][34]="61008532740.68144";
+ results[19][35]="149.7622405002312";
+ results[19][36]="3.155761011022271E+34";
+ results[19][37]="0.001267106638103371";
+ results[19][38]="1.544449959070552E+29";
+ results[19][39]="1.350480116563032E-8";
+ results[19][40]="2.800223812845777E+24";
+ results[19][41]="2.162095636668628E-13";
+ results[19][42]="1.011265256891675E+19";
+ results[19][43]="3.900346288599187E-18";
+ results[19][44]="265651340347854.4";
+ results[19][45]="0.03421193721338280";
+ results[19][46]="1.862699611140355E+38";
+ results[19][47]="1.243691805564838E-7";
+ results[19][48]="1.542426590563234E+33";
+ results[19][49]="5.267116676538570E-12";
+ results[19][50]="5.198200398008612E+28";
+ results[19][51]="1.311030202341272E-17";
+ results[19][52]="9.314566584224275E+23";
+ results[19][53]="2.730882927935629E-22";
+ results[19][54]="3.798585382942154E+18";
+ results[19][55]="0.000001383109493196072";
+ results[19][56]="1.596586702227764E+42";
+ results[19][57]="1.387275151221789E-11";
+ results[19][58]="1.276131198487774E+37";
+ results[19][59]="2.722046646772734E-16";
+ results[19][60]="6.591415871366172E+32";
+ results[19][61]="1.258318243449020E-21";
+ results[19][62]="4.712479192434771E+27";
+ results[19][63]="1.070246336745521E-26";
+ results[19][64]="4.924031385797897E+22";
+ results[19][65]="1.161181394630329E-10";
+ results[19][66]="1.035205782751841E+46";
+ results[19][67]="3.748308469749455E-15";
+ results[19][68]="2.208461582805865E+41";
+ results[19][69]="1.664821208178269E-20";
+ results[19][70]="1.621516083107649E+36";
+ results[19][71]="1.017420762348790E-25";
+ results[19][72]="3.952179854391208E+31";
+ results[19][73]="1.927901732902443E-30";
+ results[19][74]="1.103797886595758E+26";
+ results[20][0]="222.2249324966694";
+ results[20][1]="0.0004886462025847162";
+ results[20][2]="1.096364274774934E-8";
+ results[20][3]="1.278480326006873E-13";
+ results[20][4]="8.923386430719285E-19";
+ results[20][5]="0.002784041203245736";
+ results[20][6]="1730154.134120969";
+ results[20][7]="2.669878150077217E-8";
+ results[20][8]="2.550573114105107";
+ results[20][9]="2.488707960935246E-13";
+ results[20][10]="0.00009082696636380747";
+ results[20][11]="3.015853529960997E-18";
+ results[20][12]="4.049470630943514E-10";
+ results[20][13]="3.794453702780639E-23";
+ results[20][14]="3.051021146259370E-15";
+ results[20][15]="3.277548107026588E-7";
+ results[20][16]="3765249193.262553";
+ results[20][17]="3.879082828446787E-12";
+ results[20][18]="29550.14060125232";
+ results[20][19]="2.500248606854969E-17";
+ results[20][20]="1";
+ results[20][21]="4.661723402280728E-22";
+ results[20][22]="0.000005744998011657722";
+ results[20][23]="5.109286002191258E-27";
+ results[20][24]="3.043055559109729E-11";
+ results[20][25]="3.046301203814225E-11";
+ results[20][26]="81594356127656.76";
+ results[20][27]="3.551313510859396E-16";
+ results[20][28]="1258368201.134266";
+ results[20][29]="6.062150039464433E-21";
+ results[20][30]="2836.011979005927";
+ results[20][31]="7.396649780892585E-26";
+ results[20][32]="0.05765761239172050";
+ results[20][33]="3.182675966789038E-31";
+ results[20][34]="0.000001525364989911545";
+ results[20][35]="3.744428331701820E-15";
+ results[20][36]="7.890187071375662E+17";
+ results[20][37]="3.168081606654638E-20";
+ results[20][38]="3861508858523.363";
+ results[20][39]="3.376536030022057E-25";
+ results[20][40]="70012556.86949763";
+ results[20][41]="5.405776603467944E-30";
+ results[20][42]="252.8414549704244";
+ results[20][43]="9.751835374322068E-35";
+ results[20][44]="0.006641943936138782";
+ results[20][45]="8.553834835557002E-19";
+ results[20][46]="4.657212107742966E+21";
+ results[20][47]="3.109538704220428E-24";
+ results[20][48]="3.856449934231786E+16";
+ results[20][49]="1.316910113265814E-28";
+ results[20][50]="1299679330327.398";
+ results[20][51]="3.277901436948555E-34";
+ results[20][52]="23288732.12566459";
+ results[20][53]="6.827886236055077E-39";
+ results[20][54]="94.97407811720772";
+ results[20][55]="3.458117583491362E-23";
+ results[20][56]="3.991863677968137E+25";
+ results[20][57]="3.468532764166796E-28";
+ results[20][58]="3.190645251183220E+20";
+ results[20][59]="6.805793336387770E-33";
+ results[20][60]="1.648017834958501E+16";
+ results[20][61]="3.146108435163604E-38";
+ results[20][62]="117823695357.1807";
+ results[20][63]="2.675881912439624E-43";
+ results[20][64]="1231130.261245134";
+ results[20][65]="2.903242164230390E-27";
+ results[20][66]="2.588271816133498E+29";
+ results[20][67]="9.371703029553756E-32";
+ results[20][68]="5.521702995703085E+24";
+ results[20][69]="4.162466906410325E-37";
+ results[20][70]="4.054193327782826E+19";
+ results[20][71]="2.543804843647882E-42";
+ results[20][72]="988143217498189.4";
+ results[20][73]="4.820233621842614E-47";
+ results[20][74]="2759769128.210504";
+ results[21][0]="4.767012396916274E+23";
+ results[21][1]="1.048209343234839E+18";
+ results[21][2]="23518432565916.35";
+ results[21][3]="274250575.5235032";
+ results[21][4]="1914.181872385126";
+ results[21][5]="5.972128680744241E+18";
+ results[21][6]="3.711404527506926E+27";
+ results[21][7]="57272341571595.42";
+ results[21][8]="5.471309415005725E+21";
+ results[21][9]="533860065.5108917";
+ results[21][10]="1.948355973230217E+17";
+ results[21][11]="6469.396121798011";
+ results[21][12]="868663857010.9776";
+ results[21][13]="0.08139594255901624";
+ results[21][14]="6544835.210014115";
+ results[21][15]="703076485709783.2";
+ results[21][16]="8.076946803451319E+30";
+ results[21][17]="8321134682.827734";
+ results[21][18]="6.338887585392785E+25";
+ results[21][19]="53633.56834152223";
+ results[21][20]="2.145129416109833E+21";
+ results[21][21]="1";
+ results[21][22]="1.232376423029948E+16";
+ results[21][23]="0.00001096007969861868";
+ results[21][24]="65277479947.02833";
+ results[21][25]="65347103226.32689";
+ results[21][26]="1.750304535179781E+35";
+ results[21][27]="761802.7077972777";
+ results[21][28]="2.699362644550329E+30";
+ results[21][29]="13.00409637452654";
+ results[21][30]="6.083612720605475E+24";
+ results[21][31]="0.0001586677102565503";
+ results[21][32]="1.236830404041385E+20";
+ results[21][33]="6.827251838304966E-10";
+ results[21][34]="3272105310163334";
+ results[21][35]="8032283.360848641";
+ results[21][36]="1.692547238541742E+39";
+ results[21][37]="67.95945047071364";
+ results[21][38]="8.283436242987168E+33";
+ results[21][39]="0.0007243106762555027";
+ results[21][40]="1.501859952378219E+29";
+ results[21][41]="1.159609040901739E-8";
+ results[21][42]="5.423776426690670E+23";
+ results[21][43]="2.091894892251871E-13";
+ results[21][44]="1.424782931756363E+19";
+ results[21][45]="1834.908272629834";
+ results[21][46]="9.990322689382312E+42";
+ results[21][47]="0.006670362944955292";
+ results[21][48]="8.272584195675434E+37";
+ results[21][49]="2.824942622339028E-7";
+ results[21][50]="2.787980362995230E+33";
+ results[21][51]="7.031522795507035E-13";
+ results[21][52]="4.995734434666519E+28";
+ results[21][53]="1.464669961481319E-17";
+ results[21][54]="2.037316887371354E+23";
+ results[21][55]="0.07418109752713971";
+ results[21][56]="8.563064200709839E+46";
+ results[21][57]="7.440451663154942E-7";
+ results[21][58]="6.844346984684270E+41";
+ results[21][59]="1.459930748584969E-11";
+ results[21][60]="3.535211536043119E+37";
+ results[21][61]="6.748809750540721E-17";
+ results[21][62]="2.527470748254518E+32";
+ results[21][63]="5.740113004410473E-22";
+ results[21][64]="2.640933738459919E+27";
+ results[21][65]="0.000006227830168580984";
+ results[21][66]="5.552178009675986E+50";
+ results[21][67]="2.010351584774140E-10";
+ results[21][68]="1.184476752310447E+46";
+ results[21][69]="8.929030204524482E-16";
+ results[21][70]="8.696769366023154E+40";
+ results[21][71]="5.456790598951745E-21";
+ results[21][72]="2.119695083184782E+36";
+ results[21][73]="1.034002493473623E-25";
+ results[21][74]="5.920061938596140E+30";
+ results[22][0]="38681463.77870482";
+ results[22][1]="85.05593937424482";
+ results[22][2]="0.001908380599175486";
+ results[22][3]="2.225379927743381E-8";
+ results[22][4]="1.553244476779973E-13";
+ results[22][5]="484.6026400002877";
+ results[22][6]="301158352119.5565";
+ results[22][7]="0.004647309093335652";
+ results[22][8]="443964.1421858626";
+ results[22][9]="4.331956174545530E-8";
+ results[22][10]="15.80974722349805";
+ results[22][11]="5.249529284155089E-13";
+ results[22][12]="0.00007048689351547812";
+ results[22][13]="6.604795502245522E-18";
+ results[22][14]="5.310743606992122E-10";
+ results[22][15]="0.05705046547232572";
+ results[22][16]="655396082926770.0";
+ results[22][17]="6.752104736286019E-7";
+ results[22][18]="5143629387.040573";
+ results[22][19]="4.352044338016266E-12";
+ results[22][20]="174064.4640730606";
+ results[22][21]="8.114403856748394E-17";
+ results[22][22]="1";
+ results[22][23]="8.893451297674116E-22";
+ results[22][24]="0.000005296878350409827";
+ results[22][25]="0.000005302527864470423";
+ results[22][26]="1.420267787074702E+19";
+ results[22][27]="6.181574830231600E-11";
+ results[22][28]="219037186537017.3";
+ results[22][29]="1.055204897749860E-15";
+ results[22][30]="493648905.2304466";
+ results[22][31]="1.287493880047189E-20";
+ results[22][32]="10036.14140069709";
+ results[22][33]="5.539907864773438E-26";
+ results[22][34]="0.2655118394847626";
+ results[22][35]="6.517719108176616E-10";
+ results[22][36]="1.373401184015196E+23";
+ results[22][37]="5.514504270020602E-15";
+ results[22][38]="6.721514699722450E+17";
+ results[22][39]="5.877349344891688E-20";
+ results[22][40]="12186698189873.78";
+ results[22][41]="9.409536073813374E-25";
+ results[22][42]="44010712.35487979";
+ results[22][43]="1.697447998160085E-29";
+ results[22][44]="1156.126411647312";
+ results[22][45]="1.488918676420706E-13";
+ results[22][46]="8.106551296088482E+26";
+ results[22][47]="5.412601880645680E-19";
+ results[22][48]="6.712708910266456E+21";
+ results[22][49]="2.292272530980073E-23";
+ results[22][50]="2.262279861002728E+17";
+ results[22][51]="5.705661569067654E-29";
+ results[22][52]="4053740676394.876";
+ results[22][53]="1.188492358430754E-33";
+ results[22][54]="16531612.00830475";
+ results[22][55]="6.019353838720512E-18";
+ results[22][56]="6.948416117582402E+30";
+ results[22][57]="6.037482967145447E-23";
+ results[22][58]="5.553779556944628E+25";
+ results[22][59]="1.184646769690344E-27";
+ results[22][60]="2.868613412248970E+21";
+ results[22][61]="5.476256786824880E-33";
+ results[22][62]="2.050891838745521E+16";
+ results[22][63]="4.657759510115996E-38";
+ results[22][64]="214296029127.7612";
+ results[22][65]="5.053512913910754E-22";
+ results[22][66]="4.505261465506844E+34";
+ results[22][67]="1.631280465291153E-26";
+ results[22][68]="9.611322727176706E+29";
+ results[22][69]="7.245375712861636E-32";
+ results[22][70]="7.056909888490957E+24";
+ results[22][71]="4.427860268160242E-37";
+ results[22][72]="1.720006195812521E+20";
+ results[22][73]="8.390313820929822E-42";
+ results[22][74]="480377734267339.0";
+ results[23][0]="4.349432237720928E+28";
+ results[23][1]="9.563884315247705E+22";
+ results[23][2]="2.145826783438484E+18";
+ results[23][3]="25022680771022.83";
+ results[23][4]="174650360.6745100";
+ results[23][5]="5.448982895167197E+23";
+ results[23][6]="3.386293375197521E+32";
+ results[23][7]="5.225540611608288E+18";
+ results[23][8]="4.992034333194938E+26";
+ results[23][9]="48709505787460.23";
+ results[23][10]="1.777684128953709E+22";
+ results[23][11]="590269076.4751797";
+ results[23][12]="7.925707484777299E+16";
+ results[23][13]="7426.583090383436";
+ results[23][14]="597152154909.8750";
+ results[23][15]="6.414884791379698E+19";
+ results[23][16]="7.369423421683034E+35";
+ results[23][17]="759222096156514.8";
+ results[23][18]="5.783614498890633E+30";
+ results[23][19]="4893538169.095777";
+ results[23][20]="1.957220636251567E+26";
+ results[23][21]="91240.21243440706";
+ results[23][22]="1.124422866364071E+21";
+ results[23][23]="1";
+ results[23][24]="5955931137549612";
+ results[23][25]="5962283580343192";
+ results[23][26]="1.596981576147093E+40";
+ results[23][27]="69507040892.53014";
+ results[23][28]="2.462904211262749E+35";
+ results[23][29]="1186496.515729304";
+ results[23][30]="5.550701169967046E+29";
+ results[23][31]="14.47687559028860";
+ results[23][32]="1.128486688100694E+25";
+ results[23][33]="0.00006229199080701412";
+ results[23][34]="2.985475836070540E+20";
+ results[23][35]="732867240177.1831";
+ results[23][36]="1.544283695998176E+44";
+ results[23][37]="6200634.697873477";
+ results[23][38]="7.557824824970159E+38";
+ results[23][39]="66.08625997006110";
+ results[23][40]="1.370300211017172E+34";
+ results[23][41]="0.001058029752327336";
+ results[23][42]="4.948665133679859E+28";
+ results[23][43]="1.908649343595118E-8";
+ results[23][44]="1.299974973663679E+24";
+ results[23][45]="167417420.5923969";
+ results[23][46]="9.115191644675190E+47";
+ results[23][47]="608.6053321123179";
+ results[23][48]="7.547923393949451E+42";
+ results[23][49]="0.02577483649772239";
+ results[23][50]="2.543759205826400E+38";
+ results[23][51]="6.415576335994377E-8";
+ results[23][52]="4.558118710848557E+33";
+ results[23][53]="1.336367984318503E-12";
+ results[23][54]="1.858852255999673E+28";
+ results[23][55]="6768.299096993695";
+ results[23][56]="7.812957967622318E+51";
+ results[23][57]="0.06788683903541942";
+ results[23][58]="6.244796728573862E+46";
+ results[23][59]="0.000001332043916404155";
+ results[23][60]="3.225534515491407E+42";
+ results[23][61]="6.157628353187331E-12";
+ results[23][62]="2.306069679924920E+37";
+ results[23][63]="5.237291299199141E-17";
+ results[23][64]="2.409593553222759E+32";
+ results[23][65]="0.5682285475867381";
+ results[23][66]="5.065819010764803E+55";
+ results[23][67]="0.00001834249056626394";
+ results[23][68]="1.080719105044218E+51";
+ results[23][69]="8.146866126940509E-11";
+ results[23][70]="7.934950844489962E+45";
+ results[23][71]="4.978787334584325E-16";
+ results[23][72]="1.934014296859477E+41";
+ results[23][73]="9.434260716223996E-21";
+ results[23][74]="5.401477089023595E+35";
+ results[24][0]="7302690607518.291";
+ results[24][1]="16057748.30899485";
+ results[24][2]="360.2840150232697";
+ results[24][3]="0.004201304580784266";
+ results[24][4]="2.932377098408908E-8";
+ results[24][5]="91488346.14311905";
+ results[24][6]="5.685581812469896E+16";
+ results[24][7]="877.3675334597941";
+ results[24][8]="83816186216.83326";
+ results[24][9]="0.008178319168327438";
+ results[24][10]="2984729.151326427";
+ results[24][11]="9.910609488981233E-8";
+ results[24][12]="13.30725171553627";
+ results[24][13]="1.246922255961287E-12";
+ results[24][14]="0.0001002617627905542";
+ results[24][15]="10770.58253903672";
+ results[24][16]="1.237325155628808E+20";
+ results[24][17]="0.1274732831227585";
+ results[24][18]="971068060613965.9";
+ results[24][19]="8.216243700744122E-7";
+ results[24][20]="32861706944.73151";
+ results[24][21]="1.531921883031460E-11";
+ results[24][22]="188790.4410571613";
+ results[24][23]="1.678998593008280E-16";
+ results[24][24]="1";
+ results[24][25]="1.001066574251259";
+ results[24][26]="2.681329819411114E+24";
+ results[24][27]="0.00001167022238627271";
+ results[24][28]="4.135212705424321E+19";
+ results[24][29]="1.992125980518727E-10";
+ results[24][30]="93196194545840.82";
+ results[24][31]="2.430665374725046E-15";
+ results[24][32]="1894727561.549639";
+ results[24][33]="1.045881649206614E-20";
+ results[24][34]="50126.09728222654";
+ results[24][35]="0.0001230483065119351";
+ results[24][36]="2.592850152786563E+28";
+ results[24][37]="1.041085693348789E-9";
+ results[24][38]="1.268957724732794E+23";
+ results[24][39]="1.109587375069120E-14";
+ results[24][40]="2.300732126296780E+18";
+ results[24][41]="1.776430465518496E-19";
+ results[24][42]="8308801796717.613";
+ results[24][43]="3.204619562442379E-24";
+ results[24][44]="218265615.1727291";
+ results[24][45]="2.810936136197098E-8";
+ results[24][46]="1.530439394641047E+32";
+ results[24][47]="1.021847496313918E-13";
+ results[24][48]="1.267295275857541E+27";
+ results[24][49]="4.327591421469434E-18";
+ results[24][50]="4.270968127534385E+22";
+ results[24][51]="1.077174364147177E-23";
+ results[24][52]="7.653074902279439E+17";
+ results[24][53]="2.243759965412078E-28";
+ results[24][54]="3121010322433.718";
+ results[24][55]="1.136396466091162E-12";
+ results[24][56]="1.311794543487070E+36";
+ results[24][57]="1.139819072242488E-17";
+ results[24][58]="1.048500492089822E+31";
+ results[24][59]="2.236499861467814E-22";
+ results[24][60]="5.415667913209714E+26";
+ results[24][61]="1.033864934126942E-27";
+ results[24][62]="3.871887747972994E+21";
+ results[24][63]="8.793404722529862E-33";
+ results[24][64]="4.045704185582832E+16";
+ results[24][65]="9.540549319052715E-17";
+ results[24][66]="8.505502991508699E+39";
+ results[24][67]="3.079701585302480E-21";
+ results[24][68]="1.814525856806408E+35";
+ results[24][69]="1.367857676455993E-26";
+ results[24][70]="1.332277130348850E+30";
+ results[24][71]="8.359376929654525E-32";
+ results[24][72]="3.247207283284959E+25";
+ results[24][73]="1.584011046861337E-36";
+ results[24][74]="9.069072432637074E+19";
+ results[25][0]="7294910044299.792";
+ results[25][1]="16040639.77563644";
+ results[25][2]="359.9001547851519";
+ results[25][3]="0.004196828351727361";
+ results[25][4]="2.929252832762058E-8";
+ results[25][5]="91390870.99331748";
+ results[25][6]="5.679524178222003E+16";
+ results[25][7]="876.4327528526417";
+ results[25][8]="83726885276.85887";
+ results[25][9]="0.008169605677269126";
+ results[25][10]="2981549.107819164";
+ results[25][11]="9.900050350191554E-8";
+ results[25][12]="13.29307366544463";
+ results[25][13]="1.245593737753071E-12";
+ results[25][14]="0.0001001549401102962";
+ results[25][15]="10759.10715238146";
+ results[25][16]="1.236006862534849E+20";
+ results[25][17]="0.1273374682578942";
+ results[25][18]="970033447915559.5";
+ results[25][19]="8.207489803452292E-7";
+ results[25][20]="32826694837.26416";
+ results[25][21]="1.530289715424023E-11";
+ results[25][22]="188589.2965693774";
+ results[25][23]="1.677209724302378E-16";
+ results[25][24]="0.9989345621173533";
+ results[25][25]="1";
+ results[25][26]="2.678473029045643E+24";
+ results[25][27]="0.00001165778848924346";
+ results[25][28]="4.130806893155160E+19";
+ results[25][29]="1.990003494032078E-10";
+ results[25][30]="93096899789653.17";
+ results[25][31]="2.428075651754777E-15";
+ results[25][32]="1892708847.028269";
+ results[25][33]="1.044767327276784E-20";
+ results[25][34]="50072.69103927282";
+ results[25][35]="0.0001229172061847818";
+ results[25][36]="2.590087632009758E+28";
+ results[25][37]="1.039976481212013E-9";
+ results[25][38]="1.267605729101387E+23";
+ results[25][39]="1.108405178645614E-14";
+ results[25][40]="2.298280839131601E+18";
+ results[25][41]="1.774537789204645E-19";
+ results[25][42]="8299949284523.987";
+ results[25][43]="3.201205239361082E-24";
+ results[25][44]="218033066.7178449";
+ results[25][45]="2.807941258351893E-8";
+ results[25][46]="1.528808806532901E+32";
+ results[25][47]="1.020758781281058E-13";
+ results[25][48]="1.265945051462143E+27";
+ results[25][49]="4.322980641628383E-18";
+ results[25][50]="4.266417676295733E+22";
+ results[25][51]="1.076026701773399E-23";
+ results[25][52]="7.644921026359818E+17";
+ results[25][53]="2.241369378545362E-28";
+ results[25][54]="3117685079804.065";
+ results[25][55]="1.135185706246483E-12";
+ results[25][56]="1.310396907886189E+36";
+ results[25][57]="1.138604665823557E-17";
+ results[25][58]="1.047383379945576E+31";
+ results[25][59]="2.234117009790872E-22";
+ results[25][60]="5.409897855455146E+26";
+ results[25][61]="1.032763415260583E-27";
+ results[25][62]="3.867762492088947E+21";
+ results[25][63]="8.784035896021034E-33";
+ results[25][64]="4.041393739081530E+16";
+ results[25][65]="9.530384456386937E-17";
+ results[25][66]="8.496440906410580E+39";
+ results[25][67]="3.076420354566251E-21";
+ results[25][68]="1.812592592219525E+35";
+ results[25][69]="1.366400309069427E-26";
+ results[25][70]="1.330857671823993E+30";
+ results[25][71]="8.350470532798348E-32";
+ results[25][72]="3.243747585632540E+25";
+ results[25][73]="1.582323381485480E-36";
+ results[25][74]="9.059409899306875E+19";
+ results[26][0]="2.723533134436308E-12";
+ results[26][1]="5.988725516997952E-18";
+ results[26][2]="1.343676605597132E-22";
+ results[26][3]="1.566873478364917E-27";
+ results[26][4]="1.093627899552070E-32";
+ results[26][5]="3.412051194925813E-17";
+ results[26][6]="2.120433589075808E-8";
+ results[26][7]="3.272135815251872E-22";
+ results[26][8]="3.125918550193178E-14";
+ results[26][9]="3.050098167380094E-27";
+ results[26][10]="1.113152559494507E-18";
+ results[26][11]="3.696154578685082E-32";
+ results[26][12]="4.962929819077190E-24";
+ results[26][13]="4.650387456755103E-37";
+ results[26][14]="3.739255128732137E-29";
+ results[26][15]="4.016880900314683E-21";
+ results[26][16]="0.00004614595141080237";
+ results[26][17]="4.754106794320244E-26";
+ results[26][18]="3.621591247686330E-10";
+ results[26][19]="3.064242094077263E-31";
+ results[26][20]="1.225574963096063E-14";
+ results[26][21]="5.713291486714258E-36";
+ results[26][22]="7.040925726124371E-20";
+ results[26][23]="6.261813003582785E-41";
+ results[26][24]="3.729492704555177E-25";
+ results[26][25]="3.733470485444113E-25";
+ results[26][26]="1";
+ results[26][27]="4.352400925014057E-30";
+ results[26][28]="0.00001542224561666388";
+ results[26][29]="7.429619310899423E-35";
+ results[26][30]="3.475745276510183E-11";
+ results[26][31]="9.065148782251936E-40";
+ results[26][32]="7.066372617918999E-16";
+ results[26][33]="3.900607980544203E-45";
+ results[26][34]="1.869449141218870E-20";
+ results[26][35]="4.589077614441313E-29";
+ results[26][36]="9670.015728822264";
+ results[26][37]="3.882721498161075E-34";
+ results[26][38]="0.04732568576779893";
+ results[26][39]="4.138198020386811E-39";
+ results[26][40]="8.580563680159561E-7";
+ results[26][41]="6.625184461300789E-44";
+ results[26][42]="3.098761568445328E-12";
+ results[26][43]="1.195160527900366E-48";
+ results[26][44]="8.140200194419411E-17";
+ results[26][45]="1.048336581291759E-32";
+ results[26][46]="57077625.57077626";
+ results[26][47]="3.810972782670732E-38";
+ results[26][48]="472.6368485827938";
+ results[26][49]="1.613972063466582E-42";
+ results[26][50]="0.01592854447302717";
+ results[26][51]="4.017313932620759E-48";
+ results[26][52]="2.854208701546549E-7";
+ results[26][53]="8.368086421777320E-53";
+ results[26][54]="1.163978522835795E-12";
+ results[26][55]="4.238182329769274E-37";
+ results[26][56]="489232817981.0316";
+ results[26][57]="4.250946914441208E-42";
+ results[26][58]="3910374.935971505";
+ results[26][59]="8.341009917082876E-47";
+ results[26][60]="201.9769397260919";
+ results[26][61]="3.855791729321848E-52";
+ results[26][62]="0.001444017710892185";
+ results[26][63]="3.279493876087616E-57";
+ results[26][64]="1.508842424491952E-8";
+ results[26][65]="3.558140908285596E-41";
+ results[26][66]="3172121135540393";
+ results[26][67]="1.148572459459261E-45";
+ results[26][68]="67672609451.86232";
+ results[26][69]="5.101415225212420E-51";
+ results[26][70]="496871.7838081744";
+ results[26][71]="3.117623527377340E-56";
+ results[26][72]="12.11043587318969";
+ results[26][73]="5.907557643204166E-61";
+ results[26][74]="0.00003382303947460244";
+ results[27][0]="6.257541943766386E+17";
+ results[27][1]="1375959067231.062";
+ results[27][2]="30872077.93461244";
+ results[27][3]="360.0021012218345";
+ results[27][4]="0.002512700273696726";
+ results[27][5]="7839468959112.017";
+ results[27][6]="4.871871010065461E+21";
+ results[27][7]="75180018.37666884";
+ results[27][8]="7182055614931850";
+ results[27][9]="700.7852033691596";
+ results[27][10]="255755978980.9374";
+ results[27][11]="0.008492219908884301";
+ results[27][12]="1140274.047492801";
+ results[27][13]="1.068464862698761E-7";
+ results[27][14]="8.591246976449121";
+ results[27][15]="922911507.8137501";
+ results[27][16]="1.060241283048926E+25";
+ results[27][17]="10922.95235716340";
+ results[27][18]="8.320904507836979E+19";
+ results[27][19]="0.07040348871507895";
+ results[27][20]="2815859531810263";
+ results[27][21]="0.000001312675827697515";
+ results[27][22]="16177107411.35740";
+ results[27][23]="1.438703169001500E-11";
+ results[27][24]="85688.17001947338";
+ results[27][25]="85779.56281525363";
+ results[27][26]="2.297582454439834E+29";
+ results[27][27]="1";
+ results[27][28]="3.543388093690857E+24";
+ results[27][29]="0.00001707016297188988";
+ results[27][30]="7.985811363411926E+18";
+ results[27][31]="2.082792678898868E-10";
+ results[27][32]="162355737434647.7";
+ results[27][33]="8.961968457746355E-16";
+ results[27][34]="4295213546.332090";
+ results[27][35]="10.54378420900297";
+ results[27][36]="2.221765847269926E+33";
+ results[27][37]="0.00008920872789651233";
+ results[27][38]="1.087346652644278E+28";
+ results[27][39]="9.507851164638391E-10";
+ results[27][40]="1.971455256073830E+23";
+ results[27][41]="1.522190757571212E-14";
+ results[27][42]="7.119660210152448E+17";
+ results[27][43]="2.745979859142930E-19";
+ results[27][44]="18702781142325.76";
+ results[27][45]="0.002408639735523385";
+ results[27][46]="1.311405510525019E+37";
+ results[27][47]="8.756024199812025E-9";
+ results[27][48]="1.085922130625564E+32";
+ results[27][49]="3.708233894976874E-13";
+ results[27][50]="3.659714430599182E+27";
+ results[27][51]="9.230110005566145E-19";
+ results[27][52]="6.557779833982852E+22";
+ results[27][53]="1.922636853991178E-23";
+ results[27][54]="2.674336631412318E+17";
+ results[27][55]="9.737573359594823E-8";
+ results[27][56]="1.124052738729375E+41";
+ results[27][57]="9.766901045375269E-13";
+ results[27][58]="8.984408843169418E+35";
+ results[27][59]="1.916415803779827E-17";
+ results[27][60]="4.640586729161206E+31";
+ results[27][61]="8.858999425264104E-23";
+ results[27][62]="3.317749756446258E+26";
+ results[27][63]="7.534907589141790E-28";
+ results[27][64]="3.466689881027168E+21";
+ results[27][65]="8.175122121301600E-12";
+ results[27][66]="7.288209864375369E+44";
+ results[27][67]="2.638939930506406E-16";
+ results[27][68]="1.554834001227581E+40";
+ results[27][69]="1.172092211426029E-21";
+ results[27][70]="1.141603892583884E+35";
+ results[27][71]="7.162997116051003E-27";
+ results[27][72]="2.782472497785938E+30";
+ results[27][73]="1.357310078961783E-31";
+ results[27][74]="7.771122205267246E+24";
+ results[28][0]="1.765977019256848E-7";
+ results[28][1]="3.883173479306462E-13";
+ results[28][2]="8.712587252178613E-18";
+ results[28][3]="1.015982702721253E-22";
+ results[28][4]="7.091236430383361E-28";
+ results[28][5]="2.212421770302413E-12";
+ results[28][6]="0.001374918829450271";
+ results[28][7]="2.121698679027844E-17";
+ results[28][8]="2.026889357030855E-9";
+ results[28][9]="1.977726359178481E-22";
+ results[28][10]="7.217837059291388E-14";
+ results[28][11]="2.396638382345144E-27";
+ results[28][12]="3.218033185591791E-19";
+ results[28][13]="3.015376341646586E-32";
+ results[28][14]="2.424585382489199E-24";
+ results[28][15]="2.604601820097072E-16";
+ results[28][16]="2.992168102999295";
+ results[28][17]="3.082629412401127E-21";
+ results[28][18]="0.00002348290474490412";
+ results[28][19]="1.986897479292069E-26";
+ results[28][20]="7.946799665619501E-10";
+ results[28][21]="3.704578197445509E-31";
+ results[28][22]="4.565434827802628E-15";
+ results[28][23]="4.060247229376789E-36";
+ results[28][24]="2.418255289959476E-20";
+ results[28][25]="2.420834538784717E-20";
+ results[28][26]="64841.40019917012";
+ results[28][27]="2.822157702060747E-25";
+ results[28][28]="1";
+ results[28][29]="4.817469190655120E-30";
+ results[28][30]="0.000002253721904645720";
+ results[28][31]="5.877969400550175E-35";
+ results[28][32]="4.581934948749433E-11";
+ results[28][33]="2.529208830865435E-40";
+ results[28][34]="1.212176999177676E-15";
+ results[28][35]="2.975622181430421E-24";
+ results[28][36]="627017359.8048342";
+ results[28][37]="2.517610985241837E-29";
+ results[28][38]="3068.663730570020";
+ results[28][39]="2.683265539433148E-34";
+ results[28][40]="0.05563757635196901";
+ results[28][41]="4.295862370485278E-39";
+ results[28][42]="2.009280389813716E-7";
+ results[28][43]="7.749588209183903E-44";
+ results[28][44]="5.278219785077115E-12";
+ results[28][45]="6.797561181096882E-28";
+ results[28][46]="3700993162053.089";
+ results[28][47]="2.471088113492979E-33";
+ results[28][48]="30646435.04783151";
+ results[28][49]="1.046522084775171E-37";
+ results[28][50]="1032.829126765834";
+ results[28][51]="2.604882604307646E-43";
+ results[28][52]="0.01850708886689335";
+ results[28][53]="5.425984405757048E-48";
+ results[28][54]="7.547399722243467E-8";
+ results[28][55]="2.748096765616207E-32";
+ results[28][56]="3.172254094127582E+16";
+ results[28][57]="2.756373501047097E-37";
+ results[28][58]="253554186152.1326";
+ results[28][59]="5.408427620988176E-42";
+ results[28][60]="13096467.57978319";
+ results[28][61]="2.500149346056082E-47";
+ results[28][62]="93.63213028664973";
+ results[28][63]="2.126469748701247E-52";
+ results[28][64]="0.0009783545548396877";
+ results[28][65]="2.307148385991850E-36";
+ results[28][66]="2.056847760298206E+20";
+ results[28][67]="7.447504650154305E-41";
+ results[28][68]="4387986751990347";
+ results[28][69]="3.307829062001381E-46";
+ results[28][70]="32217862181.58138";
+ results[28][71]="2.021510748090225E-51";
+ results[28][72]="785257.6190398789";
+ results[28][73]="3.830543093426676E-56";
+ results[28][74]="2.193133238525025";
+ results[29][0]="3.665777505505325E+22";
+ results[29][1]="8.060608850055552E+16";
+ results[29][2]="1808540315956.603";
+ results[29][3]="21089552.67824123";
+ results[29][4]="147.1983763619884";
+ results[29][5]="4.592498016581085E+17";
+ results[29][6]="2.854027239276019E+26";
+ results[29][7]="4404176954869.778";
+ results[29][8]="4.207373782405491E+20";
+ results[29][9]="41053222.77960500";
+ results[29][10]="1.498263252683064E+16";
+ results[29][11]="497.4890938574387";
+ results[29][12]="66799247867.20172";
+ results[29][13]="0.006259254023867518";
+ results[29][14]="503290.2726585955";
+ results[29][15]="54065770158934.34";
+ results[29][16]="6.211078856100365E+29";
+ results[29][17]="639885651.6572606";
+ results[29][18]="4.874531380596274E+24";
+ results[29][19]="4124.359493873326";
+ results[29][20]="1.649579758814986E+20";
+ results[29][21]="0.07689884565596421";
+ results[29][22]="947683243446292.2";
+ results[29][23]="8.428174771211442E-7";
+ results[29][24]="5019762855.256830";
+ results[29][25]="5025116805.065672";
+ results[29][26]="1.345963983017241E+34";
+ results[29][27]="58581.74884719846";
+ results[29][28]="2.075778713727511E+29";
+ results[29][29]="1";
+ results[29][30]="4.678227956325009E+23";
+ results[29][31]="0.00001220136376160371";
+ results[29][32]="9.511083034298228E+18";
+ results[29][33]="5.250077853682115E-11";
+ results[29][34]="251621121216311.1";
+ results[29][35]="617673.3184308691";
+ results[29][36]="1.301549288620499E+38";
+ results[29][37]="5.226003292611552";
+ results[29][38]="6.369866851504902E+32";
+ results[29][39]="0.00005569865490033896";
+ results[29][40]="1.154912966748064E+28";
+ results[29][41]="8.917259665756348E-10";
+ results[29][42]="4.170821463085429E+22";
+ results[29][43]="1.608643024477765E-14";
+ results[29][44]="1.095641627623847E+18";
+ results[29][45]="141.1023280498135";
+ results[29][46]="7.682442825440876E+41";
+ results[29][47]="0.0005129432105733799";
+ results[29][48]="6.361521752392140E+36";
+ results[29][49]="2.172348267022037E-8";
+ results[29][50]="2.143924716258292E+32";
+ results[29][51]="5.407159861780895E-14";
+ results[29][52]="3.841662112296063E+27";
+ results[29][53]="1.126314293048790E-18";
+ results[29][54]="1.566673168742592E+22";
+ results[29][55]="0.005704440769329544";
+ results[29][56]="6.584897523124984E+45";
+ results[29][57]="5.721621440556141E-8";
+ results[29][58]="5.263223823910997E+40";
+ results[29][59]="1.122669893038318E-12";
+ results[29][60]="2.718536862713640E+36";
+ results[29][61]="5.189756793682972E-18";
+ results[29][62]="1.943595829699885E+31";
+ results[29][63]="4.414080639739539E-23";
+ results[29][64]="2.030847559414579E+26";
+ results[29][65]="4.789129509052666E-7";
+ results[29][66]="4.269560798205122E+49";
+ results[29][67]="1.545937162317696E-11";
+ results[29][68]="9.108489495899883E+44";
+ results[29][69]="6.866321155551707E-17";
+ results[29][70]="6.687715251833322E+39";
+ results[29][71]="4.196208980457067E-22";
+ results[29][72]="1.630021050395328E+35";
+ results[29][73]="7.951359815351027E-27";
+ results[29][74]="4.552459292898528E+29";
+ results[30][0]="0.07835824888672127";
+ results[30][1]="1.723004720015306E-7";
+ results[30][2]="3.865866163087327E-12";
+ results[30][3]="4.508021600300163E-17";
+ results[30][4]="3.146455831913338E-22";
+ results[30][5]="9.816746980813501E-7";
+ results[30][6]="610.0658766354783";
+ results[30][7]="9.414199128358610E-12";
+ results[30][8]="0.0008993520242460782";
+ results[30][9]="8.775378874836710E-17";
+ results[30][10]="3.202629856156106E-8";
+ results[30][11]="1.063413537138199E-21";
+ results[30][12]="1.427875009316049E-13";
+ results[30][13]="1.337954046340334E-26";
+ results[30][14]="1.075813913638266E-18";
+ results[30][15]="1.155689091332903E-10";
+ results[30][16]="1327656.307919525";
+ results[30][17]="1.367794937807870E-15";
+ results[30][18]="10.41961064339727";
+ results[30][19]="8.816072094770739E-21";
+ results[30][20]="0.0003526078195024119";
+ results[30][21]="1.643760124001572E-25";
+ results[30][22]="2.025731221936322E-9";
+ results[30][23]="1.801574196446855E-30";
+ results[30][24]="1.073005185322375E-14";
+ results[30][25]="1.074149625024506E-14";
+ results[30][26]="28770807997.87632";
+ results[30][27]="1.252220913433587E-19";
+ results[30][28]="443710.4675331262";
+ results[30][29]="2.137561506912014E-24";
+ results[30][30]="1";
+ results[30][31]="2.608116550863527E-29";
+ results[30][32]="0.00002033052498315981";
+ results[30][33]="1.122236432832213E-34";
+ results[30][34]="5.378556230380286E-10";
+ results[30][35]="1.320314709324433E-18";
+ results[30][36]="278214165870389.4";
+ results[30][37]="1.117090347328190E-23";
+ results[30][38]="1361598218.593171";
+ results[30][39]="1.190593007017408E-28";
+ results[30][40]="24686.97501554217";
+ results[30][41]="1.906119100865986E-33";
+ results[30][42]="0.08915387411693861";
+ results[30][43]="3.438573407486192E-38";
+ results[30][44]="0.000002342001368579163";
+ results[30][45]="3.016149049749527E-22";
+ results[30][46]="1.642169406271479E+18";
+ results[30][47]="1.096447662153521E-27";
+ results[30][48]="13598144023296.90";
+ results[30][49]="4.643528035193328E-32";
+ results[30][50]="458277094.7190988";
+ results[30][51]="1.155813678226253E-37";
+ results[30][52]="8211.789053806363";
+ results[30][53]="2.407566077505911E-42";
+ results[30][54]="0.03348860259416035";
+ results[30][55]="1.219359300697839E-26";
+ results[30][56]="1.407562347239223E+22";
+ results[30][57]="1.223031774845527E-31";
+ results[30][58]="1.125046464825440E+17";
+ results[30][59]="2.399775948327737E-36";
+ results[30][60]="5811039752858.027";
+ results[30][61]="1.109342435241184E-41";
+ results[30][62]="41545556.30561193";
+ results[30][63]="9.435368863912798E-47";
+ results[30][64]="434.1061569410814";
+ results[30][65]="1.023705889016741E-30";
+ results[30][66]="9.126448813663803E+25";
+ results[30][67]="3.304535770275098E-35";
+ results[30][68]="1.946995653254801E+21";
+ results[30][69]="1.467718379620295E-40";
+ results[30][70]="1.429540269150730E+16";
+ results[30][71]="8.969654791583536E-46";
+ results[30][72]="348427025278.1341";
+ results[30][73]="1.699652066890138E-50";
+ results[30][74]="973116.1746283781";
+ results[31][0]="3.004399817208225E+27";
+ results[31][1]="6.606317955556214E+21";
+ results[31][2]="1.482244404226248E+17";
+ results[31][3]="1728458645303.865";
+ results[31][4]="12064092.11609646";
+ results[31][5]="3.763921891283291E+22";
+ results[31][6]="2.339105115657083E+31";
+ results[31][7]="3.609577618470172E+17";
+ results[31][8]="3.448281572954666E+25";
+ results[31][9]="3364642148346.955";
+ results[31][10]="1.227947368799811E+21";
+ results[31][11]="40773236.79365905";
+ results[31][12]="5474736199359228";
+ results[31][13]="512.9962638737704";
+ results[31][14]="41248690104.82190";
+ results[31][15]="4.431125177094802E+18";
+ results[31][16]="5.090479209910875E+34";
+ results[31][17]="52443781216564.26";
+ results[31][18]="3.995070941115503E+29";
+ results[31][19]="338024467.9576074";
+ results[31][20]="1.351963428879995E+25";
+ results[31][21]="6302.479555437567";
+ results[31][22]="7.767027210749525E+19";
+ results[31][23]="0.06907567822651053";
+ results[31][24]="411409982796631.8";
+ results[31][25]="411848782090993.5";
+ results[31][26]="1.103125854876022E+39";
+ results[31][27]="4801245991.169322";
+ results[31][28]="1.701267787999033E+34";
+ results[31][29]="81958.05153739330";
+ results[31][30]="3.834184479481592E+28";
+ results[31][31]="1";
+ results[31][32]="7.795098335014412E+23";
+ results[31][33]="0.000004302861513074059";
+ results[31][34]="2.062237682054311E+19";
+ results[31][35]="50623301665.22991";
+ results[31][36]="1.066724436752164E+43";
+ results[31][37]="428313.0471904447";
+ results[31][38]="5.220618757019720E+37";
+ results[31][39]="4.564953228885464";
+ results[31][40]="9.465441644994164E+32";
+ results[31][41]="0.00007308412272583773";
+ results[31][42]="3.418324004248217E+27";
+ results[31][43]="1.318412479054169E-9";
+ results[31][44]="8.979665298330876E+22";
+ results[31][45]="11564471.87435279";
+ results[31][46]="6.296380450205607E+46";
+ results[31][47]="42.03982608792905";
+ results[31][48]="5.213779276388035E+41";
+ results[31][49]="0.001780414312257591";
+ results[31][50]="1.757118923873884E+37";
+ results[31][51]="4.431602866227630E-9";
+ results[31][52]="3.148551413888119E+32";
+ results[31][53]="9.231052487699542E-14";
+ results[31][54]="1.284014803060566E+27";
+ results[31][55]="467.5248505647183";
+ results[31][56]="5.396853705687309E+50";
+ results[31][57]="0.004689329449025547";
+ results[31][58]="4.313635694129337E+45";
+ results[31][59]="9.201183695311428E-8";
+ results[31][60]="2.228059843005880E+41";
+ results[31][61]="4.253423547632060E-13";
+ results[31][62]="1.592933271784059E+36";
+ results[31][63]="3.617694485619832E-18";
+ results[31][64]="1.664443089390894E+31";
+ results[31][65]="0.03925077231221895";
+ results[31][66]="3.499248839413294E+54";
+ results[31][67]="0.000001267019976228053";
+ results[31][68]="7.465140515327681E+49";
+ results[31][69]="5.627503031390007E-12";
+ results[31][70]="5.481121112771666E+44";
+ results[31][71]="3.439131118819729E-17";
+ results[31][72]="1.335933492553362E+40";
+ results[31][73]="6.516779575388975E-22";
+ results[31][74]="3.731106933492626E+34";
+ results[32][0]="3854.216698861785";
+ results[32][1]="0.008474964229612891";
+ results[32][2]="1.901508281900985E-7";
+ results[32][3]="2.217366056230347E-12";
+ results[32][4]="1.547651049109460E-17";
+ results[32][5]="0.04828575252702482";
+ results[32][6]="30007384.32189076";
+ results[32][7]="4.630573551915940E-7";
+ results[32][8]="44.23653717702960";
+ results[32][9]="4.316356258436777E-12";
+ results[32][10]="0.001575281434595963";
+ results[32][11]="5.230625072490977E-17";
+ results[32][12]="7.023306139407549E-9";
+ results[32][13]="6.581010807387358E-22";
+ results[32][14]="5.291618954893612E-14";
+ results[32][15]="0.000005684501960919277";
+ results[32][16]="65303591964.26306";
+ results[32][17]="6.727789562447809E-11";
+ results[32][18]="512510.6534153962";
+ results[32][19]="4.336372081917841E-16";
+ results[32][20]="17.34376361626097";
+ results[32][21]="8.085182873354881E-21";
+ results[32][22]="0.00009963988749008084";
+ results[32][23]="8.861424866987624E-26";
+ results[32][24]="5.277803628834801E-10";
+ results[32][25]="5.283432798288516E-10";
+ results[32][26]="1415153225099094";
+ results[32][27]="6.159314205957922E-15";
+ results[32][28]="21824840622.69226";
+ results[32][29]="1.051404972907783E-19";
+ results[32][30]="49187.12137676328";
+ results[32][31]="1.282857453520695E-24";
+ results[32][32]="1";
+ results[32][33]="5.519957963514394E-30";
+ results[32][34]="0.00002645556981354615";
+ results[32][35]="6.494247986306681E-14";
+ results[32][36]="1.368455394540179E+19";
+ results[32][37]="5.494645850284232E-19";
+ results[32][38]="66973096844326.95";
+ results[32][39]="5.856184274649082E-24";
+ results[32][40]="1214281236.514595";
+ results[32][41]="9.375651157286216E-29";
+ results[32][42]="4385.222427398534";
+ results[32][43]="1.691335275569338E-33";
+ results[32][44]="0.1151963055808490";
+ results[32][45]="1.483556894004392E-17";
+ results[32][46]="8.077358590748254E+22";
+ results[32][47]="5.393110424161355E-23";
+ results[32][48]="6.688535605726128E+17";
+ results[32][49]="2.284017770834574E-27";
+ results[32][50]="22541331082138.75";
+ results[32][51]="5.685114767983791E-33";
+ results[32][52]="403914264.9099497";
+ results[32][53]="1.184212448768611E-37";
+ results[32][54]="1647.207960537155";
+ results[32][55]="5.997677392530980E-22";
+ results[32][56]="6.923394001901749E+26";
+ results[32][57]="6.015741235696518E-27";
+ results[32][58]="5.533779701986738E+21";
+ results[32][59]="1.180380708474336E-31";
+ results[32][60]="2.858283176490243E+17";
+ results[32][61]="5.456536101060227E-37";
+ results[32][62]="2043506320669.287";
+ results[32][63]="4.640986335438119E-42";
+ results[32][64]="21352432.23186122";
+ results[32][65]="5.035314581717381E-26";
+ results[32][66]="4.489037455364987E+30";
+ results[32][67]="1.625406020263772E-30";
+ results[32][68]="9.576711151667440E+25";
+ results[32][69]="7.219284208528977E-36";
+ results[32][70]="7.031497073168779E+20";
+ results[32][71]="4.411914989412857E-41";
+ results[32][72]="1.713812238330015E+16";
+ results[32][73]="8.360099251239178E-46";
+ results[32][74]="47864783395.13761";
+ results[33][0]="6.982329800946383E+32";
+ results[33][1]="1.535331298830604E+27";
+ results[33][2]="3.444787613364996E+22";
+ results[33][3]="4.016998083837972E+17";
+ results[33][4]="2803737019990.124";
+ results[33][5]="8.747485550828852E+27";
+ results[33][6]="5.436161746200319E+36";
+ results[33][7]="8.388784085898711E+22";
+ results[33][8]="8.013926459118452E+30";
+ results[33][9]="7.819545523655909E+17";
+ results[33][10]="2.853792447348690E+26";
+ results[33][11]="9475842220292.549";
+ results[33][12]="1.272347758049958E+21";
+ results[33][13]="119222118.1915926";
+ results[33][14]="9586339225533875";
+ results[33][15]="1.029808922186089E+24";
+ results[33][16]="1.183045095558775E+40";
+ results[33][17]="1.218811738588753E+19";
+ results[33][18]="9.284683992214605E+34";
+ results[33][19]="78558063495777.08";
+ results[33][20]="3.142010089732407E+30";
+ results[33][21]="1464718196.550773";
+ results[33][22]="1.805084171812118E+25";
+ results[33][23]="16053.42817021349";
+ results[33][24]="9.561311270339060E+19";
+ results[33][25]="9.571509118748273E+19";
+ results[33][26]="2.563702902183168E+44";
+ results[33][27]="1115826288292324";
+ results[33][28]="3.953805584562284E+39";
+ results[33][29]="19047336589.46896";
+ results[33][30]="8.910778252638594E+33";
+ results[33][31]="232403.4824178150";
+ results[33][32]="1.811607998846661E+29";
+ results[33][33]="1";
+ results[33][34]="4.792712188826647E+24";
+ results[33][35]="1.176503159848700E+16";
+ results[33][36]="2.479104738813852E+48";
+ results[33][37]="99541443732.04527";
+ results[33][38]="1.213289979507148E+43";
+ results[33][39]="1060911.027467431";
+ results[33][40]="2.199801600919255E+38";
+ results[33][41]="16.98500463093566";
+ results[33][42]="7.944304026196954E+32";
+ results[33][43]="0.0003064036513952934";
+ results[33][44]="2.086905486278503E+28";
+ results[33][45]="2687623535922.464";
+ results[33][46]="1.463300743255233E+52";
+ results[33][47]="9770201.983074019";
+ results[33][48]="1.211700460390415E+47";
+ results[33][49]="413.7744863151833";
+ results[33][50]="4.083605569305342E+42";
+ results[33][51]="0.001029919938804072";
+ results[33][52]="7.317343131591340E+37";
+ results[33][53]="2.145328744523008E-8";
+ results[33][54]="2.984095117073005E+32";
+ results[33][55]="108654403.3881091";
+ results[33][56]="1.254247595301220E+56";
+ results[33][57]="1089.816494157951";
+ results[33][58]="1.002503957197447E+51";
+ results[33][59]="0.02138387133156396";
+ results[33][60]="5.178088665498566E+46";
+ results[33][61]="9.885104446676278E-8";
+ results[33][62]="3.702032396218190E+41";
+ results[33][63]="8.407647967817748E-13";
+ results[33][64]="3.868223702607104E+36";
+ results[33][65]="9122.016172948436";
+ results[33][66]="8.132376161261471E+59";
+ results[33][67]="0.2944598547683367";
+ results[33][68]="1.734924652500475E+55";
+ results[33][69]="0.000001307851301811848";
+ results[33][70]="1.273831634161944E+50";
+ results[33][71]="7.992660485051813E-12";
+ results[33][72]="3.104755959479955E+45";
+ results[33][73]="1.514522267469688E-16";
+ results[33][74]="8.671222446169412E+39";
+ results[34][0]="145686398.9710135";
+ results[34][1]="320.3470682862941";
+ results[34][2]="0.007187553680765358";
+ results[34][3]="8.381471545908569E-8";
+ results[34][4]="5.850000812747606E-13";
+ results[34][5]="1825.163958566520";
+ results[34][6]="1134255830941.353";
+ results[34][7]="0.01750320852868166";
+ results[34][8]="1672106.761971122";
+ results[34][9]="1.631549155379241E-7";
+ results[34][10]="59.54441524783812";
+ results[34][11]="1.977135669106896E-12";
+ results[34][12]="0.0002654755194806417";
+ results[34][13]="2.487570993091087E-17";
+ results[34][14]="2.000190883125157E-9";
+ results[34][15]="0.2148697609230333";
+ results[34][16]="2468425077384854";
+ results[34][17]="0.000002543052222977617";
+ results[34][18]="19372504808.15474";
+ results[34][19]="1.639114981260948E-11";
+ results[34][20]="655580.7997520574";
+ results[34][21]="3.056136356290082E-16";
+ results[34][22]="3.766310391056549";
+ results[34][23]="3.349549803478537E-21";
+ results[34][24]="0.00001994968797131100";
+ results[34][25]="0.00001997096579482185";
+ results[34][26]="5.349169324542341E+19";
+ results[34][27]="2.328172951619490E-10";
+ results[34][28]="824962031682160.1";
+ results[34][29]="3.974229171089060E-15";
+ results[34][30]="1859235001.303121";
+ results[34][31]="4.849101578843441E-20";
+ results[34][32]="37799.22364355827";
+ results[34][33]="2.086501255659210E-25";
+ results[34][34]="1";
+ results[34][35]="2.454775320311342E-9";
+ results[34][36]="5.172655150445800E+23";
+ results[34][37]="2.076933473370431E-14";
+ results[34][38]="2.531531065720401E+18";
+ results[34][39]="2.213592190953497E-19";
+ results[34][40]="45898888025191.66";
+ results[34][41]="3.543923348982476E-24";
+ results[34][42]="165758003.2599846";
+ results[34][43]="6.393116033748466E-29";
+ results[34][44]="4354.330917562191";
+ results[34][45]="5.607729882441468E-13";
+ results[34][46]="3.053178838209099E+27";
+ results[34][47]="2.038553870572805E-18";
+ results[34][48]="2.528214532087444E+22";
+ results[34][49]="8.633409852563746E-23";
+ results[34][50]="8.520448147972540E+17";
+ results[34][51]="2.148929245543152E-28";
+ results[34][52]="15267645632154.63";
+ results[34][53]="4.476231119249052E-33";
+ results[34][54]="62263182.08779341";
+ results[34][55]="2.267075491021919E-17";
+ results[34][56]="2.616989182503541E+31";
+ results[34][57]="2.273903483498682E-22";
+ results[34][58]="2.091725765495799E+26";
+ results[34][59]="4.461747438416318E-27";
+ results[34][60]="1.080408850247748E+22";
+ results[34][61]="2.062528284031250E-32";
+ results[34][62]="7.724295243200328E+16";
+ results[34][63]="1.754256804199234E-37";
+ results[34][64]="807105361266.0442";
+ results[34][65]="1.903309819900053E-21";
+ results[34][66]="1.696821307196509E+35";
+ results[34][67]="6.143908567153631E-26";
+ results[34][68]="3.619922465916360E+30";
+ results[34][69]="2.728833383445953E-31";
+ results[34][70]="2.657851304177320E+25";
+ results[34][71]="1.667669613811836E-36";
+ results[34][72]="6.478077207970342E+20";
+ results[34][73]="3.160052612799337E-41";
+ results[34][74]="1809251652203281";
+ results[35][0]="5.934816020251334E+16";
+ results[35][1]="130499547406.9147";
+ results[35][2]="2927988.407449751";
+ results[35][3]="34.14353841900911";
+ results[35][4]="0.0002383110488501100";
+ results[35][5]="743515686940.7634";
+ results[35][6]="4.620609558668262E+20";
+ results[35][7]="7130269.065301548";
+ results[35][8]="681164890381514.3";
+ results[35][9]="66.46429682910084";
+ results[35][10]="24256564238.34587";
+ results[35][11]="0.0008054242898515592";
+ results[35][12]="108146.5653023476";
+ results[35][13]="1.013359948875315E-8";
+ results[35][14]="0.8148162752717714";
+ results[35][15]="87531335.00453358";
+ results[35][16]="1.005560491406513E+24";
+ results[35][17]="1035.961296309220";
+ results[35][18]="7.891762903049598E+18";
+ results[35][19]="0.006677250531641558";
+ results[35][20]="267063463742543.0";
+ results[35][21]="1.244975998822763E-7";
+ results[35][22]="1534279068.187334";
+ results[35][23]="1.364503616996488E-12";
+ results[35][24]="8126.889579768451";
+ results[35][25]="8135.557510937055";
+ results[35][26]="2.179087136929461E+28";
+ results[35][27]="0.09484260870458016";
+ results[35][28]="3.360641704583902E+23";
+ results[35][29]="0.000001618978787266365";
+ results[35][30]="7.573951823286671E+17";
+ results[35][31]="1.975374910575696E-11";
+ results[35][32]="15398241676457.85";
+ results[35][33]="8.499764676608273E-17";
+ results[35][34]="407369257.6773865";
+ results[35][35]="1";
+ results[35][36]="2.107180688858216E+32";
+ results[35][37]="0.000008460788472922284";
+ results[35][38]="1.031267931029763E+27";
+ results[35][39]="9.017494076291857E-11";
+ results[35][40]="1.869779594303981E+22";
+ results[35][41]="1.443685423940549E-15";
+ results[35][42]="6.752471474210576E+16";
+ results[35][43]="2.604358932913510E-20";
+ results[35][44]="1773820553569.003";
+ results[35][45]="0.0002284416759465479";
+ results[35][46]="1.243771196877546E+36";
+ results[35][47]="8.304441769906065E-10";
+ results[35][48]="1.029916877185643E+31";
+ results[35][49]="3.516985762863528E-14";
+ results[35][50]="3.470968637118237E+26";
+ results[35][51]="8.754077115581401E-20";
+ results[35][52]="6.219569467652223E+21";
+ results[35][53]="1.823478948240904E-24";
+ results[35][54]="2.536410626773635E+16";
+ results[35][55]="9.235368598761958E-9";
+ results[35][56]="1.066080940626218E+40";
+ results[35][57]="9.263183741028816E-14";
+ results[35][58]="8.521047723546869E+34";
+ results[35][59]="1.817578741931636E-18";
+ results[35][60]="4.401253513135038E+30";
+ results[35][61]="8.402106160044240E-24";
+ results[35][62]="3.146640419303486E+25";
+ results[35][63]="7.146302921021462E-29";
+ results[35][64]="3.287899118863873E+20";
+ results[35][65]="7.753499084627650E-13";
+ results[35][66]="6.912328363238143E+43";
+ results[35][67]="2.502839472239110E-17";
+ results[35][68]="1.474645127790042E+39";
+ results[35][69]="1.111642829739649E-22";
+ results[35][70]="1.082726912799589E+34";
+ results[35][71]="6.793573326296614E-28";
+ results[35][72]="2.638969503387675E+29";
+ results[35][73]="1.287308287097552E-32";
+ results[35][74]="7.370335025096355E+23";
+ results[36][0]="2.816472290028026E-16";
+ results[36][1]="6.193087669080073E-22";
+ results[36][2]="1.389528872835434E-26";
+ results[36][3]="1.620342223120407E-31";
+ results[36][4]="1.130947384389897E-36";
+ results[36][5]="3.528485672216559E-21";
+ results[36][6]="2.192792285493067E-12";
+ results[36][7]="3.383795752781463E-26";
+ results[36][8]="3.232588899391471E-18";
+ results[36][9]="3.154181185340816E-31";
+ results[36][10]="1.151138313225971E-22";
+ results[36][11]="3.822283936590086E-36";
+ results[36][12]="5.132287225019476E-28";
+ results[36][13]="4.809079516690182E-41";
+ results[36][14]="3.866855270552440E-33";
+ results[36][15]="4.153954877593472E-25";
+ results[36][16]="4.772065806807389E-9";
+ results[36][17]="4.916338222853396E-30";
+ results[36][18]="3.745176170594929E-14";
+ results[36][19]="3.168807766200464E-35";
+ results[36][20]="1.267397073040055E-18";
+ results[36][21]="5.908254595372923E-40";
+ results[36][22]="7.281193664595935E-24";
+ results[36][23]="6.475494124501726E-45";
+ results[36][24]="3.856759708713939E-29";
+ results[36][25]="3.860873229312546E-29";
+ results[36][26]="0.0001034124481327801";
+ results[36][27]="4.500924349110802E-34";
+ results[36][28]="1.594852174924249E-9";
+ results[36][29]="7.683151216346878E-39";
+ results[36][30]="3.594353281298647E-15";
+ results[36][31]="9.374492282605629E-44";
+ results[36][32]="7.307508918374459E-20";
+ results[36][33]="4.033714204743355E-49";
+ results[36][34]="1.933243123531666E-24";
+ results[36][35]="4.745677507807144E-33";
+ results[36][36]="1";
+ results[36][37]="4.015217355426124E-38";
+ results[36][38]="0.000004894065024810755";
+ results[36][39]="4.279411881464243E-43";
+ results[36][40]="8.873370965245172E-11";
+ results[36][41]="6.851265444743684E-48";
+ results[36][42]="3.204505199727048E-16";
+ results[36][43]="1.235944761018426E-52";
+ results[36][44]="8.417980303958437E-21";
+ results[36][45]="1.084110523385301E-36";
+ results[36][46]="5902.536993880142";
+ results[36][47]="3.941020252233737E-42";
+ results[36][48]="0.04887653358970880";
+ results[36][49]="1.669048023009940E-46";
+ results[36][50]="0.000001647209779147603";
+ results[36][51]="4.154402686902390E-52";
+ results[36][52]="2.951607093088121E-11";
+ results[36][53]="8.653643030626684E-57";
+ results[36][54]="1.203698686204266E-16";
+ results[36][55]="4.382808103545301E-41";
+ results[36][56]="50592763.41431727";
+ results[36][57]="4.396008273048529E-46";
+ results[36][58]="404.3814452458765";
+ results[36][59]="8.625642554253372E-51";
+ results[36][60]="0.02088692980344213";
+ results[36][61]="3.987368622192980E-56";
+ results[36][62]="1.493294066304539E-7";
+ results[36][63]="3.391404903626805E-61";
+ results[36][64]="1.560330889633121E-12";
+ results[36][65]="3.679560621272072E-45";
+ results[36][66]="328036812399.9663";
+ results[36][67]="1.187766898905705E-49";
+ results[36][68]="6998190.214950595";
+ results[36][69]="5.275498373810540E-55";
+ results[36][70]="51.38272757170476";
+ results[36][71]="3.224010813224441E-60";
+ results[36][72]="0.001252369821601588";
+ results[36][73]="6.109149983692593E-65";
+ results[36][74]="3.497723315360298E-9";
+ results[37][0]="7.014495208389838E+21";
+ results[37][1]="1.542404089460013E+16";
+ results[37][2]="346065667144.4297";
+ results[37][3]="4035503.136413506";
+ results[37][4]="28.16652958678678";
+ results[37][5]="8.787782478196851E+16";
+ results[37][6]="5.461204441472514E+25";
+ results[37][7]="842742858791.6008";
+ results[37][8]="8.050844109405394E+19";
+ results[37][9]="7855567.721827779";
+ results[37][10]="2866938975720293";
+ results[37][11]="95.19494458811030";
+ results[37][12]="12782090658.38928";
+ results[37][13]="0.001197713371653776";
+ results[37][14]="96305.00489162340";
+ results[37][15]="10345529294895.73";
+ results[37][16]="1.188495013939524E+29";
+ results[37][17]="122442642.2696522";
+ results[37][18]="9.327455624622005E+23";
+ results[37][19]="789.1995590022467";
+ results[37][20]="3.156484346550524E+19";
+ results[37][21]="0.01471465694724737";
+ results[37][22]="181339962947614.9";
+ results[37][23]="1.612738128796641E-7";
+ results[37][24]="960535723.8013413";
+ results[37][25]="961560206.4717620";
+ results[37][26]="2.575513078838174E+33";
+ results[37][27]="11209.66550672107";
+ results[37][28]="3.972019529077253E+28";
+ results[37][29]="0.1913508170601013";
+ results[37][30]="8.951827418361983E+22";
+ results[37][31]="0.000002334740925030381";
+ results[37][32]="1.819953509739433E+18";
+ results[37][33]="1.004606686931215E-11";
+ results[37][34]="48147907134319.92";
+ results[37][35]="118192.2941579709";
+ results[37][36]="2.490525198215260E+37";
+ results[37][37]="1";
+ results[37][38]="1.218879226599518E+32";
+ results[37][39]="0.00001065798312432847";
+ results[37][40]="2.209935398205477E+27";
+ results[37][41]="1.706324922979563E-10";
+ results[37][42]="7.980900947732038E+21";
+ results[37][43]="3.078151570918528E-15";
+ results[37][44]="2.096519206508824E+17";
+ results[37][45]="27.00004576141425";
+ results[37][46]="1.470041711665625E+41";
+ results[37][47]="0.00009815210244864781";
+ results[37][48]="1.217282385065843E+36";
+ results[37][49]="4.156806158337618E-9";
+ results[37][50]="4.102417461713700E+31";
+ results[37][51]="1.034664457526358E-14";
+ results[37][52]="7.351051840566861E+26";
+ results[37][53]="2.155211602413563E-19";
+ results[37][54]="2.997841909050329E+21";
+ results[37][55]="0.001091549402082161";
+ results[37][56]="1.260025521307003E+45";
+ results[37][57]="1.094836937559011E-8";
+ results[37][58]="1.007122179075560E+40";
+ results[37][59]="2.148238013216586E-13";
+ results[37][60]="5.201942498882593E+35";
+ results[37][61]="9.930642028144481E-19";
+ results[37][62]="3.719086500476785E+30";
+ results[37][63]="8.446379369833354E-24";
+ results[37][64]="3.886043398184922E+25";
+ results[37][65]="9.164038445638694E-8";
+ results[37][66]="8.169839472243282E+48";
+ results[37][67]="2.958163391330656E-12";
+ results[37][68]="1.742916907223793E+44";
+ results[37][69]="1.313876163311878E-17";
+ results[37][70]="1.279699777703607E+39";
+ results[37][71]="8.029480169653943E-23";
+ results[37][72]="3.119058598183105E+34";
+ results[37][73]="1.521499197406275E-27";
+ results[37][74]="8.711168053289843E+28";
+ }
+
+ private static void initResults2() {
+ results[38][0]="5.754873046740801E-11";
+ results[38][1]="1.265428153832008E-16";
+ results[38][2]="2.839212118742058E-21";
+ results[38][3]="3.310831006343367E-26";
+ results[38][4]="2.310854838782263E-31";
+ results[38][5]="7.209723725223695E-16";
+ results[38][6]="4.480513181530232E-7";
+ results[38][7]="6.914080086037084E-21";
+ results[38][8]="6.605120453046024E-13";
+ results[38][9]="6.444910660872926E-26";
+ results[38][10]="2.352110786003469E-17";
+ results[38][11]="7.810039133548062E-31";
+ results[38][12]="1.048675732545652E-22";
+ results[38][13]="9.826349859084964E-36";
+ results[38][14]="7.901111348029064E-28";
+ results[38][15]="8.487739448770601E-20";
+ results[38][16]="0.0009750720071382617";
+ results[38][17]="1.004551062956811E-24";
+ results[38][18]="7.652485513797906E-9";
+ results[38][19]="6.474797024837234E-30";
+ results[38][20]="2.589661286915703E-13";
+ results[38][21]="1.207228462519536E-34";
+ results[38][22]="1.487759894419769E-18";
+ results[38][23]="1.323132016365500E-39";
+ results[38][24]="7.880483175360085E-24";
+ results[38][25]="7.888888295802402E-24";
+ results[38][26]="21.13017452946058";
+ results[38][27]="9.196699116773269E-29";
+ results[38][28]="0.0003258747415163162";
+ results[38][29]="1.569891527267555E-33";
+ results[38][30]="7.344310431260839E-10";
+ results[38][31]="1.915481759045105E-38";
+ results[38][32]="1.493136867068297E-14";
+ results[38][33]="8.242052739990580E-44";
+ results[38][34]="3.950178662790491E-19";
+ results[38][35]="9.696801092238556E-28";
+ results[38][36]="204329.1200526434";
+ results[38][37]="8.204258290543218E-33";
+ results[38][38]="1";
+ results[38][39]="8.744084640824158E-38";
+ results[38][40]="0.00001813088081229221";
+ results[38][41]="1.399913039571560E-42";
+ results[38][42]="6.547737276643480E-11";
+ results[38][43]="2.525395054525697E-47";
+ results[38][44]="1.720038508128311E-15";
+ results[38][45]="2.215153492831292E-31";
+ results[38][46]="1206060190.037704";
+ results[38][47]="8.052652002485662E-37";
+ results[38][48]="9986.899099608667";
+ results[38][49]="3.410351138672251E-41";
+ results[38][50]="0.3365729247153389";
+ results[38][51]="8.488654453591028E-47";
+ results[38][52]="0.000006030992800718365";
+ results[38][53]="1.768191265697641E-51";
+ results[38][54]="2.459506933606407E-11";
+ results[38][55]="8.955353231570062E-36";
+ results[38][56]="10337574829479.02";
+ results[38][57]="8.982325021761465E-41";
+ results[38][58]="82626904.87270614";
+ results[38][59]="1.762469952999227E-45";
+ results[38][60]="4267.807987338662";
+ results[38][61]="8.147355218982128E-51";
+ results[38][62]="0.03051234625478403";
+ results[38][63]="6.929627797002850E-56";
+ results[38][64]="3.188210376696939E-7";
+ results[38][65]="7.518413839248804E-40";
+ results[38][66]="6.702747322255918E+16";
+ results[38][67]="2.426953652810597E-44";
+ results[38][68]="1429934048581.875";
+ results[38][69]="1.077937940559859E-49";
+ results[38][70]="10498987.51063113";
+ results[38][71]="6.587592925063573E-55";
+ results[38][72]="255.8956236283385";
+ results[38][73]="1.248277240437528E-59";
+ results[38][74]="0.0007146867272151842";
+ results[39][0]="6.581447096100371E+26";
+ results[39][1]="1.447181958788470E+21";
+ results[39][2]="3.247008961334176E+16";
+ results[39][3]="378636660364.1785";
+ results[39][4]="2642763.575267104";
+ results[39][5]="8.245258390527376E+21";
+ results[39][6]="5.124050561692560E+30";
+ results[39][7]="7.907151371518986E+16";
+ results[39][8]="7.553815778735954E+24";
+ results[39][9]="737059500863.3713";
+ results[39][10]="2.689945125899165E+20";
+ results[39][11]="8931797.271363033";
+ results[39][12]="1199297325702478";
+ results[39][13]="112.3771127878607";
+ results[39][14]="9035950213.862933";
+ results[39][15]="9.706835875242173E+17";
+ results[39][16]="1.115121876320673E+34";
+ results[39][17]="11488350172947.65";
+ results[39][18]="8.751614180482857E+28";
+ results[39][19]="74047739.59538163";
+ results[39][20]="2.961615072691725E+24";
+ results[39][21]="1380.623029291435";
+ results[39][22]="1.701447270390950E+19";
+ results[39][23]="0.01513173843478247";
+ results[39][24]="90123592108977.16";
+ results[39][25]="90219715611751.54";
+ results[39][26]="2.416510749542446E+38";
+ results[39][27]="1051762362.161496";
+ results[39][28]="3.726802231475215E+33";
+ results[39][29]="17953.75492979660";
+ results[39][30]="8.399175823358240E+27";
+ results[39][31]="0.2190602947851342";
+ results[39][32]="1.707596539147366E+23";
+ results[39][33]="9.425861114736121E-7";
+ results[39][34]="4.517543945478293E+18";
+ results[39][35]="11089555385.78204";
+ results[39][36]="2.336769695694354E+42";
+ results[39][37]="93826.38237785791";
+ results[39][38]="1.143630283873541E+37";
+ results[39][39]="1";
+ results[39][40]="2.073502437023907E+32";
+ results[39][41]="0.00001600982946843494";
+ results[39][42]="7.488190640417148E+26";
+ results[39][43]="2.888118263100058E-10";
+ results[39][44]="1.967088127324202E+22";
+ results[39][45]="2533316.617830116";
+ results[39][46]="1.379286957501396E+46";
+ results[39][47]="9.209256695537514";
+ results[39][48]="1.142132025230187E+41";
+ results[39][49]="0.0003900180840828200";
+ results[39][50]="3.849149894363509E+36";
+ results[39][51]="9.707882302464703E-10";
+ results[39][52]="6.897226008724825E+31";
+ results[39][53]="2.022157079132508E-14";
+ results[39][54]="2.812766612669237E+26";
+ results[39][55]="102.4161315840830";
+ results[39][56]="1.182236363680106E+50";
+ results[39][57]="0.001027245891448147";
+ results[39][58]="9.449463067516497E+44";
+ results[39][59]="2.015614012667092E-8";
+ results[39][60]="4.880794460077878E+40";
+ results[39][61]="9.317562161903105E-14";
+ results[39][62]="3.489484320900643E+35";
+ results[39][63]="7.924932204624348E-19";
+ results[39][64]="3.646133938150488E+30";
+ results[39][65]="0.008598285753258867";
+ results[39][66]="7.665464822884150E+53";
+ results[39][67]="2.775537694911710E-7";
+ results[39][68]="1.635315881900131E+49";
+ results[39][69]="1.232762472960531E-12";
+ results[39][70]="1.200696006716784E+44";
+ results[39][71]="7.533770766933783E-18";
+ results[39][72]="2.926499846920735E+39";
+ results[39][73]="1.427567654834451E-22";
+ results[39][74]="8.173373847257529E+33";
+ results[40][0]="0.000003174072515461667";
+ results[40][1]="6.979408043839129E-12";
+ results[40][2]="1.565953771433517E-16";
+ results[40][3]="1.826072897737389E-21";
+ results[40][4]="1.274540858056698E-26";
+ results[40][5]="3.976488401123740E-11";
+ results[40][6]="0.02471205468678926";
+ results[40][7]="3.813427575647367E-16";
+ results[40][8]="3.643022377913347E-8";
+ results[40][9]="3.554659438554945E-21";
+ results[40][10]="1.297295377072253E-12";
+ results[40][11]="4.307589473674706E-26";
+ results[40][12]="5.783920502277423E-18";
+ results[40][13]="5.419675944492992E-31";
+ results[40][14]="4.357819914999574E-23";
+ results[40][15]="4.681371818966545E-15";
+ results[40][16]="53.77962699292531";
+ results[40][17]="5.540553012050880E-20";
+ results[40][18]="0.0004220691533424975";
+ results[40][19]="3.571143118677119E-25";
+ results[40][20]="1.428315211889754E-8";
+ results[40][21]="6.658410449100025E-30";
+ results[40][22]="8.205668052327118E-14";
+ results[40][23]="7.297670918825164E-35";
+ results[40][24]="4.346442545702108E-19";
+ results[40][25]="4.351078349405929E-19";
+ results[40][26]="1165424.600614822";
+ results[40][27]="5.072395109750087E-24";
+ results[40][28]="17.97346443838419";
+ results[40][29]="8.658661118125126E-29";
+ results[40][30]="0.00004050719050715733";
+ results[40][31]="1.056474739906990E-33";
+ results[40][32]="8.235324486033761E-10";
+ results[40][33]="4.545864497880714E-39";
+ results[40][34]="2.178702018774722E-14";
+ results[40][35]="5.348223946000686E-23";
+ results[40][36]="11269674218.70173";
+ results[40][37]="4.525019151292953E-28";
+ results[40][38]="55154.51843475961";
+ results[40][39]="4.822757775174344E-33";
+ results[40][40]="1";
+ results[40][41]="7.721152954810994E-38";
+ results[40][42]="0.000003611372963305955";
+ results[40][43]="1.392869480898883E-42";
+ results[40][44]="9.486789560505935E-11";
+ results[40][45]="1.221757241561856E-26";
+ results[40][46]="66519668984864.25";
+ results[40][47]="4.441401433197993E-32";
+ results[40][48]="550822610.4954504";
+ results[40][49]="1.880962747469021E-36";
+ results[40][50]="18563.51758085312";
+ results[40][51]="4.681876485468906E-42";
+ results[40][52]="0.3326365036071236";
+ results[40][53]="9.752373776010145E-47";
+ results[40][54]="0.000001356529205100136";
+ results[40][55]="4.939281949004150E-31";
+ results[40][56]="5.701639615032074E+17";
+ results[40][57]="4.954158109997452E-36";
+ results[40][58]="4557247148008.799";
+ results[40][59]="9.720818151340577E-41";
+ results[40][60]="235388894.3136845";
+ results[40][61]="4.493634536198847E-46";
+ results[40][62]="1682.893763997254";
+ results[40][63]="3.822002840758163E-51";
+ results[40][64]="0.01758442079954232";
+ results[40][65]="4.146744946969999E-35";
+ results[40][66]="3.696868007488996E+21";
+ results[40][67]="1.338574599842493E-39";
+ results[40][68]="7.886732384299944E+16";
+ results[40][69]="5.945314801413554E-45";
+ results[40][70]="579066600201.4157";
+ results[40][71]="3.633355154261108E-50";
+ results[40][72]="14113799.89078350";
+ results[40][73]="6.884813006940251E-55";
+ results[40][74]="39.41820227126789";
+ results[41][0]="4.110878950382567E+31";
+ results[41][1]="9.039334001912643E+25";
+ results[41][2]="2.028134632999056E+21";
+ results[41][3]="2.365026192881695E+16";
+ results[41][4]="165071313250.2498";
+ results[41][5]="5.150122558634225E+26";
+ results[41][6]="3.200565360046566E+35";
+ results[41][7]="4.938935412840446E+21";
+ results[41][8]="4.718236252065705E+29";
+ results[41][9]="4.603793577667779E+16";
+ results[41][10]="1.680183496771577E+25";
+ results[41][11]="557894591505.3629";
+ results[41][12]="7.491006247549473E+19";
+ results[41][13]="7019257.326220990";
+ results[41][14]="564400153772921.7";
+ results[41][15]="6.063047638564933E+22";
+ results[41][16]="6.965232693572741E+38";
+ results[41][17]="7.175810457942816E+17";
+ results[41][18]="5.466400624527316E+33";
+ results[41][19]="4625142306567.008";
+ results[41][20]="1.849872966186717E+29";
+ results[41][21]="86235960.97719082";
+ results[41][22]="1.062751651256206E+24";
+ results[41][23]="945.1530051969814";
+ results[41][24]="5.629266213401292E+18";
+ results[41][25]="5.635270243797986E+18";
+ results[41][26]="1.509391935939637E+43";
+ results[41][27]="65694788581924.34";
+ results[41][28]="2.327821316787288E+38";
+ results[41][29]="1121420747.497299";
+ results[41][30]="5.246261891744755E+32";
+ results[41][31]="13682.86247002409";
+ results[41][32]="1.066592584583160E+28";
+ results[41][33]="0.05887546231095213";
+ results[41][34]="2.821731458405042E+23";
+ results[41][35]="692671674463882.5";
+ results[41][36]="1.459584376149378E+47";
+ results[41][37]="5860548518.823794";
+ results[41][38]="7.143300846072895E+41";
+ results[41][39]="62461.62721293222";
+ results[41][40]="1.295143362464938E+37";
+ results[41][41]="1";
+ results[41][42]="4.677245722811041E+31";
+ results[41][43]="0.00001803965662966171";
+ results[41][44]="1.228675253039092E+27";
+ results[41][45]="158235078195.2310";
+ results[41][46]="8.615250775911171E+50";
+ results[41][47]="575225.1586248642";
+ results[41][48]="7.133942478787923E+45";
+ results[41][49]="24.36116417428315";
+ results[41][50]="2.404241657884309E+41";
+ results[41][51]="0.00006063701254035724";
+ results[41][52]="4.308119597603104E+36";
+ results[41][53]="1.263072216427666E-9";
+ results[41][54]="1.756899795975280E+31";
+ results[41][55]="6397078.231595606";
+ results[41][56]="7.384440702575934E+54";
+ results[41][57]="64.16344992765041";
+ results[41][58]="5.902288394855864E+49";
+ results[41][59]="0.001258985310643743";
+ results[41][60]="3.048623640683292E+45";
+ results[41][61]="5.819900942901146E-9";
+ results[41][62]="2.179588688174679E+40";
+ results[41][63]="4.950041610530071E-14";
+ results[41][64]="2.277434588131763E+35";
+ results[41][65]="537.0629193903215";
+ results[41][66]="4.787974061808353E+58";
+ results[41][67]="0.01733646008150164";
+ results[41][68]="1.021444909906334E+54";
+ results[41][69]="7.700035002815314E-8";
+ results[41][70]="7.499742636760013E+48";
+ results[41][71]="4.705715811519044E-13";
+ results[41][72]="1.827939424770661E+44";
+ results[41][73]="8.916819867750936E-18";
+ results[41][74]="5.105222303193294E+38";
+ results[42][0]="0.8789101950179163";
+ results[42][1]="0.000001932619010762593";
+ results[42][2]="4.336172938504800E-11";
+ results[42][3]="5.056450597297903E-16";
+ results[42][4]="3.529241845156713E-21";
+ results[42][5]="0.00001101101559303791";
+ results[42][6]="6842.842026531408";
+ results[42][7]="1.055949527892695E-10";
+ results[42][8]="0.01008763817785915";
+ results[42][9]="9.842958549761383E-16";
+ results[42][10]="3.592249790463821E-7";
+ results[42][11]="1.192784438894235E-20";
+ results[42][12]="1.601584926576693E-12";
+ results[42][13]="1.500724516564931E-25";
+ results[42][14]="1.206693398681896E-17";
+ results[42][15]="1.296285890859935E-9";
+ results[42][16]="14891739.93917645";
+ results[42][17]="1.534195738946580E-14";
+ results[42][18]="116.8722138729541";
+ results[42][19]="9.888602354180532E-20";
+ results[42][20]="0.003955047640890110";
+ results[42][21]="1.843733814467261E-24";
+ results[42][22]="2.272174083292525E-8";
+ results[42][23]="2.020746954959940E-29";
+ results[42][24]="1.203542971015447E-13";
+ results[42][25]="1.204826638958615E-13";
+ results[42][26]="322709565712.6364";
+ results[42][27]="1.404561412318563E-18";
+ results[42][28]="4976906.185267212";
+ results[42][29]="2.397609221230570E-23";
+ results[42][30]="11.21656248710349";
+ results[42][31]="2.925410226640957E-28";
+ results[42][32]="0.0002280386038692306";
+ results[42][33]="1.258763507416664E-33";
+ results[42][34]="6.032891204846025E-9";
+ results[42][35]="1.480939243977938E-17";
+ results[42][36]="3120606576282596";
+ results[42][37]="1.252991368454678E-22";
+ results[42][38]="15272451501.17909";
+ results[42][39]="1.335436085991919E-27";
+ results[42][40]="276902.9978793913";
+ results[42][41]="2.138010400272485E-32";
+ results[42][42]="1";
+ results[42][43]="3.856897349156122E-37";
+ results[42][44]="0.00002626920469555007";
+ results[42][45]="3.383082428693337E-21";
+ results[42][46]="1.841949575985368E+19";
+ results[42][47]="1.229837371638349E-26";
+ results[42][48]="152524432145942.5";
+ results[42][49]="5.208442236736284E-31";
+ results[42][50]="5140293669.325014";
+ results[42][51]="1.296425634527369E-36";
+ results[42][52]="92108.04505293148";
+ results[42][53]="2.700461535017569E-41";
+ results[42][54]="0.3756270036031754";
+ results[42][55]="1.367701979050812E-25";
+ results[42][56]="1.578801102230280E+23";
+ results[42][57]="1.371821232626794E-30";
+ results[42][58]="1.261915397360943E+18";
+ results[42][59]="2.691723687946608E-35";
+ results[42][60]="65179890502974.45";
+ results[42][61]="1.244300874447829E-40";
+ results[42][62]="465998328.3633725";
+ results[42][63]="1.058324044509485E-45";
+ results[42][64]="4869.178835365991";
+ results[42][65]="1.148246107257210E-29";
+ results[42][66]="1.023673834038115E+27";
+ results[42][67]="3.706553195815928E-34";
+ results[42][68]="2.183859840685134E+22";
+ results[42][69]="1.646275491848131E-39";
+ results[42][70]="1.603452775675989E+17";
+ results[42][71]="1.006086934575439E-44";
+ results[42][72]="3908153501227.777";
+ results[42][73]="1.906425361460782E-49";
+ results[42][74]="10915018.37993031";
+ results[43][0]="2.278801107346606E+36";
+ results[43][1]="5.010812670929508E+30";
+ results[43][2]="1.124264543740979E+26";
+ results[43][3]="1.311015082733337E+21";
+ results[43][4]="9150468694555485";
+ results[43][5]="2.854889460681936E+31";
+ results[43][6]="1.774183082168003E+40";
+ results[43][7]="2.737821187083793E+26";
+ results[43][8]="2.615480077546344E+34";
+ results[43][9]="2.552040580472019E+21";
+ results[43][10]="9.313833025008547E+29";
+ results[43][11]="3.092600945563700E+16";
+ results[43][12]="4.152521525954315E+24";
+ results[43][13]="389101492911.9866";
+ results[43][14]="3.128663507069788E+19";
+ results[43][15]="3.360955124054725E+27";
+ results[43][16]="3.861067223485925E+43";
+ results[43][17]="3.977797696073652E+22";
+ results[43][18]="3.030213233404445E+38";
+ results[43][19]="2.563874912653335E+17";
+ results[43][20]="1.025447991701273E+34";
+ results[43][21]="4780354900735.599";
+ results[43][22]="5.891196673382220E+28";
+ results[43][23]="52393070.69974453";
+ results[43][24]="3.120495211724467E+23";
+ results[43][25]="3.123823451568468E+23";
+ results[43][26]="8.367076862526411E+47";
+ results[43][27]="3.641687307612366E+18";
+ results[43][28]="1.290391144673877E+43";
+ results[43][29]="62164195833605.98";
+ results[43][30]="2.908182788312382E+37";
+ results[43][31]="758487966.3133965";
+ results[43][32]="5.912488283338024E+32";
+ results[43][33]="3263.668678379727";
+ results[43][34]="1.564182465516227E+28";
+ results[43][35]="3.839716512812981E+19";
+ results[43][36]="8.090976486489524E+51";
+ results[43][37]="324870292108974.2";
+ results[43][38]="3.959776503909459E+46";
+ results[43][39]="3462462090.893108";
+ results[43][40]="7.179423583569754E+41";
+ results[43][41]="55433.42761611934";
+ results[43][42]="2.592757622182496E+36";
+ results[43][43]="1";
+ results[43][44]="6.810968070305965E+31";
+ results[43][45]="8771512753466319";
+ results[43][46]="4.775728802811879E+55";
+ results[43][47]="31886702193.60218";
+ results[43][48]="3.954588840154493E+50";
+ results[43][49]="1350422.830899525";
+ results[43][50]="1.332753559139886E+46";
+ results[43][51]="3.361317445513614";
+ results[43][52]="2.388138358753168E+41";
+ results[43][53]="0.00007001642228327445";
+ results[43][54]="9.739097766897050E+35";
+ results[43][55]="354611973105.8077";
+ results[43][56]="4.093448591717685E+59";
+ results[43][57]="3556799.957164907";
+ results[43][58]="3.271840765057037E+54";
+ results[43][59]="69.78987108732747";
+ results[43][60]="1.689956579146075E+50";
+ results[43][61]="0.0003226170576512954";
+ results[43][62]="1.208220717788436E+45";
+ results[43][63]="2.743977733140975E-9";
+ results[43][64]="1.262460053916486E+40";
+ results[43][65]="29771238.46732512";
+ results[43][66]="2.654138135831102E+63";
+ results[43][67]="961.0194050476638";
+ results[43][68]="5.662219247714633E+58";
+ results[43][69]="0.004268393329701480";
+ results[43][70]="4.157364405943601E+53";
+ results[43][71]="2.608539568198692E-8";
+ results[43][72]="1.013289477896753E+49";
+ results[43][73]="4.942898887049463E-13";
+ results[43][74]="2.829999710082635E+43";
+ results[44][0]="33457.81515672613";
+ results[44][1]="0.07356975717997179";
+ results[44][2]="0.000001650667764311622";
+ results[44][3]="1.924858653278701E-11";
+ results[44][4]="1.343490176447769E-16";
+ results[44][5]="0.4191605996698921";
+ results[44][6]="260489120.4677608";
+ results[44][7]="0.000004019724008133258";
+ results[44][8]="384.0100336028812";
+ results[44][9]="3.746957193351482E-11";
+ results[44][10]="0.01367475655276438";
+ results[44][11]="4.540618769080169E-16";
+ results[44][12]="6.096815435177592E-8";
+ results[44][13]="5.712866201918743E-21";
+ results[44][14]="4.593566545569257E-13";
+ results[44][15]="0.00004934621759141124";
+ results[44][16]="566889637953.1077";
+ results[44][17]="5.840282401874423E-10";
+ results[44][18]="4449019.878121849";
+ results[44][19]="3.764332597345680E-15";
+ results[44][20]="150.5583319604680";
+ results[44][21]="7.018612995084639E-20";
+ results[44][22]="0.0008649573177513917";
+ results[44][23]="7.692455779988837E-25";
+ results[44][24]="4.581573690425900E-9";
+ results[44][25]="4.586460278954353E-9";
+ results[44][26]="1.228471015596839E+16";
+ results[44][27]="5.346798384636640E-14";
+ results[44][28]="189457817354.8698";
+ results[44][29]="9.127071980358501E-19";
+ results[44][30]="426985.2329790381";
+ results[44][31]="1.113627253106948E-23";
+ results[44][32]="8.680833946520647";
+ results[44][33]="4.791783847304273E-29";
+ results[44][34]="0.0002296564085119783";
+ results[44][35]="5.637548837665439E-13";
+ results[44][36]="1.187933404322369E+20";
+ results[44][37]="4.769810822125617E-18";
+ results[44][38]="581382332589848.2";
+ results[44][39]="5.083656324845414E-23";
+ results[44][40]="10540973778.55897";
+ results[44][41]="8.138847083690577E-28";
+ results[44][42]="38067.38771080486";
+ results[44][43]="1.468220067511016E-32";
+ results[44][44]="1";
+ results[44][45]="1.287851104706806E-16";
+ results[44][46]="7.011820865278762E+23";
+ results[44][47]="4.681669604739426E-22";
+ results[44][48]="5.806206693869941E+18";
+ results[44][49]="1.982717899951718E-26";
+ results[44][50]="195677552057591.1";
+ results[44][51]="4.935153726777955E-32";
+ results[44][52]="3506312662.314225";
+ results[44][53]="1.027995162516290E-36";
+ results[44][54]="14299.13878080998";
+ results[44][55]="5.206484150936237E-21";
+ results[44][56]="6.010083367684613E+27";
+ results[44][57]="5.222165073231839E-26";
+ results[44][58]="4.803782268957339E+22";
+ results[44][59]="1.024668892394211E-30";
+ results[44][60]="2.481228162724536E+18";
+ results[44][61]="4.736728381649903E-36";
+ results[44][62]="17739339038395.46";
+ results[44][63]="4.028763172600968E-41";
+ results[44][64]="185356918.5591225";
+ results[44][65]="4.371072975238266E-25";
+ results[44][66]="3.896858872973504E+31";
+ results[44][67]="1.410987975758478E-29";
+ results[44][68]="8.313383926141755E+26";
+ results[44][69]="6.266940742697879E-35";
+ results[44][70]="6.103925848762411E+21";
+ results[44][71]="3.829910140925841E-40";
+ results[44][72]="1.487731945645773E+17";
+ results[44][73]="7.257263337643890E-45";
+ results[44][74]="415506236539.3683";
+ results[45][0]="2.597956785100805E+20";
+ results[45][1]="571259805664574.7";
+ results[45][2]="12817225207.78065";
+ results[45][3]="149462.8258067859";
+ results[45][4]="1.043203031420026";
+ results[45][5]="3254728734851059";
+ results[45][6]="2.022664883508130E+24";
+ results[45][7]="31212645572.47396";
+ results[45][8]="2.981789060858130E+18";
+ results[45][9]="290946.4595446784";
+ results[45][10]="106182745061026.3";
+ results[45][11]="3.525732712799818";
+ results[45][12]="473409962.7585133";
+ results[45][13]="0.00004435967932193017";
+ results[45][14]="3566.845987692836";
+ results[45][15]="383167102245.4531";
+ results[45][16]="4.401825924450844E+27";
+ results[45][17]="4534904.990592084";
+ results[45][18]="3.454607339203797E+22";
+ results[45][19]="29.22956375615078";
+ results[45][20]="1.169066295088082E+18";
+ results[45][21]="0.0005449863706629740";
+ results[45][22]="6716283540777.093";
+ results[45][23]="5.973094057127134E-9";
+ results[45][24]="35575336.88235604";
+ results[45][25]="35613280.62065461";
+ results[45][26]="9.538921161825726E+31";
+ results[45][27]="415.1720928836645";
+ results[45][28]="1.471115850756691E+27";
+ results[45][29]="0.007087055286904757";
+ results[45][30]="3.315486017121880E+21";
+ results[45][31]="8.647173955412170E-8";
+ results[45][32]="6.740557130241340E+16";
+ results[45][33]="3.720759200959941E-13";
+ results[45][34]="1783252797412.961";
+ results[45][35]="4377.484956965496";
+ results[45][36]="9.224151767085032E+35";
+ results[45][37]="0.03703697426428437";
+ results[45][38]="4.514359854683718E+30";
+ results[45][39]="3.947394466849308E-7";
+ results[45][40]="8.184932046906727E+25";
+ results[45][41]="6.319711225890107E-12";
+ results[45][42]="2.955884230069542E+20";
+ results[45][43]="1.140054205136760E-16";
+ results[45][44]="7764872789604521";
+ results[45][45]="1";
+ results[45][46]="5.444589704238428E+39";
+ results[45][47]="0.000003635256892375972";
+ results[45][48]="4.508445636805033E+34";
+ results[45][49]="1.539555227079692E-10";
+ results[45][50]="1.519411299508411E+30";
+ results[45][51]="3.832084088557348E-16";
+ results[45][52]="2.722607178344951E+25";
+ results[45][53]="7.982251665267820E-21";
+ results[45][54]="1.110309936338901E+20";
+ results[45][55]="0.00004042768711311199";
+ results[45][56]="4.666753280498896E+43";
+ results[45][57]="4.054944747996101E-10";
+ results[45][58]="3.730075822741150E+38";
+ results[45][59]="7.956423600906009E-15";
+ results[45][60]="1.926642104554017E+34";
+ results[45][61]="3.678009332242079E-20";
+ results[45][62]="1.377437110048061E+29";
+ results[45][63]="3.128283353469004E-25";
+ results[45][64]="1.439272893284671E+24";
+ results[45][65]="3.394082560680328E-9";
+ results[45][66]="3.025861342768090E+47";
+ results[45][67]="1.095614213942617E-13";
+ results[45][68]="6.455236863763371E+42";
+ results[45][69]="4.866199764703870E-19";
+ results[45][70]="4.739620773281892E+37";
+ results[45][71]="2.973876503990548E-24";
+ results[45][72]="1.155204930297025E+33";
+ results[45][73]="5.635172661746553E-29";
+ results[45][74]="3.226353070015521E+27";
+ results[46][0]="4.771630051532411E-20";
+ results[46][1]="1.049224710578041E-25";
+ results[46][2]="2.354121413006176E-30";
+ results[46][3]="2.745162334095334E-35";
+ results[46][4]="1.916036080015227E-40";
+ results[46][5]="5.977913693510024E-25";
+ results[46][6]="3.714999648060815E-16";
+ results[46][7]="5.732781948321280E-30";
+ results[46][8]="5.476609299938448E-22";
+ results[46][9]="5.343771989249925E-35";
+ results[46][10]="1.950243284234377E-26";
+ results[46][11]="6.475662821856263E-40";
+ results[46][12]="8.695053043023237E-32";
+ results[46][13]="8.147478824234940E-45";
+ results[46][14]="6.551174985538704E-37";
+ results[46][15]="7.037575337351325E-29";
+ results[46][16]="8.084770687172574E-13";
+ results[46][17]="8.329195103649068E-34";
+ results[46][18]="6.345027865946450E-18";
+ results[46][19]="5.368552148823365E-39";
+ results[46][20]="2.147207335344303E-22";
+ results[46][21]="1.000968668472338E-43";
+ results[46][22]="1.233570187216990E-27";
+ results[46][23]="1.097069638227704E-48";
+ results[46][24]="6.534071218380670E-33";
+ results[46][25]="6.541040290498085E-33";
+ results[46][26]="1.752E-8";
+ results[46][27]="7.625406420624627E-38";
+ results[46][28]="2.701977432039512E-13";
+ results[46][29]="1.301669303269579E-42";
+ results[46][30]="6.089505724445841E-19";
+ results[46][31]="1.588214066650539E-47";
+ results[46][32]="1.238028482659409E-23";
+ results[46][33]="6.833865181913444E-53";
+ results[46][34]="3.275274895415460E-28";
+ results[46][35]="8.040063980501181E-37";
+ results[46][36]="0.0001694186755689661";
+ results[46][37]="6.802528064778204E-42";
+ results[46][38]="8.291460146518372E-10";
+ results[46][39]="7.250122931717692E-47";
+ results[46][40]="1.503314756763955E-14";
+ results[46][41]="1.160732317619898E-51";
+ results[46][42]="5.429030267916215E-20";
+ results[46][43]="2.093921244881440E-56";
+ results[46][44]="1.426163074062281E-24";
+ results[46][45]="1.836685690423163E-40";
+ results[46][46]="1";
+ results[46][47]="6.676824315239122E-46";
+ results[46][48]="0.000008280597587170547";
+ results[46][49]="2.827679055193452E-50";
+ results[46][50]="2.790680991674361E-10";
+ results[46][51]="7.038334009951569E-56";
+ results[46][52]="5.000573645109554E-15";
+ results[46][53]="1.466088741095387E-60";
+ results[46][54]="2.039290372008313E-20";
+ results[46][55]="7.425295441755768E-45";
+ results[46][56]="8571.358971027673";
+ results[46][57]="7.447658994100996E-50";
+ results[46][58]="0.06850976887822076";
+ results[46][59]="1.461344937472920E-54";
+ results[46][60]="0.000003538635984001130";
+ results[46][61]="6.755347109771878E-60";
+ results[46][62]="2.529919029483109E-11";
+ results[46][63]="5.745673270905503E-65";
+ results[46][64]="2.643491927709899E-16";
+ results[46][65]="6.233862871316364E-49";
+ results[46][66]="55575562.29466768";
+ results[46][67]="2.012298948972625E-53";
+ results[46][68]="1185.624117596628";
+ results[46][69]="8.937679474572159E-59";
+ results[46][70]="0.008705193652319216";
+ results[46][71]="5.462076419965100E-64";
+ results[46][72]="2.121748364982833E-7";
+ results[46][73]="1.035004099089370E-68";
+ results[46][74]="5.925796515950347E-13";
+ results[47][0]="7.146556246270681E+25";
+ results[47][1]="1.571442741399231E+20";
+ results[47][2]="3525810028628656";
+ results[47][3]="41114790572.36538";
+ results[47][4]="286968.1737232600";
+ results[47][5]="8.953228977234115E+20";
+ results[47][6]="5.564021865277680E+29";
+ results[47][7]="8586090748616571";
+ results[47][8]="8.202416360482460E+23";
+ results[47][9]="80034635283.92306";
+ results[47][10]="2.920914482927399E+19";
+ results[47][11]="969871.6809241588";
+ results[47][12]="130227375058794.5";
+ results[47][13]="12.20262573876507";
+ results[47][14]="981181273.6462696";
+ results[47][15]="1.054030330150941E+17";
+ results[47][16]="1.210870663276248E+33";
+ results[47][17]="1247478548243.150";
+ results[47][18]="9.503062483559163E+27";
+ results[47][19]="8040577.219577623";
+ results[47][20]="3.215911088814389E+23";
+ results[47][21]="149.9168798238013";
+ results[47][22]="1.847540281090668E+18";
+ results[47][23]="0.001643100951037101";
+ results[47][24]="9786196116419.247";
+ results[47][25]="9796633821214.788";
+ results[47][26]="2.624001946556017E+37";
+ results[47][27]="114207084.9942909";
+ results[47][28]="4.046800251839102E+32";
+ results[47][29]="1949.533553397026";
+ results[47][30]="9.120362371295601E+26";
+ results[47][31]="0.02378696805044898";
+ results[47][32]="1.854217550450959E+22";
+ results[47][33]="1.023520293369992E-7";
+ results[47][34]="4.905438185545787E+17";
+ results[47][35]="1204174859.319065";
+ results[47][36]="2.537414009565692E+41";
+ results[47][37]="10188.26876910955";
+ results[47][38]="1.241826915768028E+36";
+ results[47][39]="0.1085863966072925";
+ results[47][40]="2.251541579928655E+31";
+ results[47][41]="0.000001738449692274594";
+ results[47][42]="8.131156387513517E+25";
+ results[47][43]="3.136103551657476E-11";
+ results[47][44]="2.135990115551220E+21";
+ results[47][45]="275083.7229955457";
+ results[47][46]="1.497718006025124E+45";
+ results[47][47]="1";
+ results[47][48]="1.240200010695352E+40";
+ results[47][49]="0.00004235065836223342";
+ results[47][50]="4.179653170302738E+35";
+ results[47][51]="1.054143957912348E-10";
+ results[47][52]="7.489449188735266E+30";
+ results[47][53]="2.195787505969266E-15";
+ results[47][54]="3.054281909670523E+25";
+ results[47][55]="11.12099868317389";
+ results[47][56]="1.283747866701312E+49";
+ results[47][57]="0.0001115449297820002";
+ results[47][58]="1.026083144375309E+44";
+ results[47][59]="2.188682625866851E-9";
+ results[47][60]="5.299878830006924E+39";
+ results[47][61]="1.011760500325512E-14";
+ results[47][62]="3.789105284242457E+34";
+ results[47][63]="8.605398314572440E-20";
+ results[47][64]="3.959205458913181E+29";
+ results[47][65]="0.0009336568669461997";
+ results[47][66]="8.323652034369472E+52";
+ results[47][67]="3.013856369381733E-8";
+ results[47][68]="1.775730589302118E+48";
+ results[47][69]="1.338612348114789E-13";
+ results[47][70]="1.303792527901410E+43";
+ results[47][71]="8.180650204466976E-19";
+ results[47][72]="3.177780730489156E+38";
+ results[47][73]="1.550144275515960E-23";
+ results[47][74]="8.875172141979778E+32";
+ results[48][0]="5.762422338848205E-15";
+ results[48][1]="1.267088153400481E-20";
+ results[48][2]="2.842936621692024E-25";
+ results[48][3]="3.315174183018531E-30";
+ results[48][4]="2.313886238094478E-35";
+ results[48][5]="7.219181503001472E-20";
+ results[48][6]="4.486390757373126E-11";
+ results[48][7]="6.923150035938593E-25";
+ results[48][8]="6.613785107035720E-17";
+ results[48][9]="6.453365150275192E-30";
+ results[48][10]="2.355196305223146E-21";
+ results[48][11]="7.820284410257130E-35";
+ results[48][12]="1.050051394418058E-26";
+ results[48][13]="9.839240149597593E-40";
+ results[48][14]="7.911476094054727E-32";
+ results[48][15]="8.498873738599392E-24";
+ results[48][16]="9.763511150087314E-8";
+ results[48][17]="1.005868841707006E-28";
+ results[48][18]="7.662524110309441E-13";
+ results[48][19]="6.483290719429564E-34";
+ results[48][20]="2.593058426931717E-17";
+ results[48][21]="1.208812115230884E-38";
+ results[48][22]="1.489711550683502E-22";
+ results[48][23]="1.324867712358631E-43";
+ results[48][24]="7.890820861170891E-28";
+ results[48][25]="7.899237007522711E-28";
+ results[48][26]="0.002115789327468880";
+ results[48][27]="9.208763426010420E-33";
+ results[48][28]="3.263022268134115E-8";
+ results[48][29]="1.571950924515769E-37";
+ results[48][30]="7.353944761040615E-14";
+ results[48][31]="1.917994504540616E-42";
+ results[48][32]="1.495095576891135E-18";
+ results[48][33]="8.252864735875365E-48";
+ results[48][34]="3.955360541236747E-23";
+ results[48][35]="9.709521439561277E-32";
+ results[48][36]="20.45971607549835";
+ results[48][37]="8.215020707343183E-37";
+ results[48][38]="0.0001001311808626548";
+ results[48][39]="8.755555206487259E-42";
+ results[48][40]="1.815466505814869E-9";
+ results[48][41]="1.401749457573287E-46";
+ results[48][42]="6.556326654887352E-15";
+ results[48][43]="2.528707889543666E-51";
+ results[48][44]="1.722294869481269E-19";
+ results[48][45]="2.218059350292316E-35";
+ results[48][46]="120764.2310199132";
+ results[48][47]="8.063215540849113E-41";
+ results[48][48]="1";
+ results[48][49]="3.414824866715520E-45";
+ results[48][50]="0.00003370144439814430";
+ results[48][51]="8.499789943731035E-51";
+ results[48][52]="6.038904309100998E-10";
+ results[48][53]="1.770510794253370E-55";
+ results[48][54]="2.462733336018967E-15";
+ results[48][55]="8.967100941193022E-40";
+ results[48][56]="1035113574.931792";
+ results[48][57]="8.994108113211472E-45";
+ results[48][58]="8273.529555930313";
+ results[48][59]="1.764781976287603E-49";
+ results[48][60]="0.4273406534672904";
+ results[48][61]="8.158042989841942E-55";
+ results[48][62]="0.000003055237261381728";
+ results[48][63]="6.938718142525727E-60";
+ results[48][64]="3.192392698572340E-11";
+ results[48][65]="7.528276559381090E-44";
+ results[48][66]="6711540044014.826";
+ results[48][67]="2.430137351548587E-48";
+ results[48][68]="143180984.8402199";
+ results[48][69]="1.079351988849169E-53";
+ results[48][70]="1051.276017301760";
+ results[48][71]="6.596234586290859E-59";
+ results[48][72]="0.02562313097149101";
+ results[48][73]="1.249914741289858E-63";
+ results[48][74]="7.156242594292246E-8";
+ results[49][0]="1.687472290311238E+30";
+ results[49][1]="3.710550915072856E+24";
+ results[49][2]="8.325277964917845E+19";
+ results[49][3]="970818215402995.0";
+ results[49][4]="6776002660.189255";
+ results[49][5]="2.114070789798686E+25";
+ results[49][6]="1.313798198291870E+34";
+ results[49][7]="2.027380702131727E+20";
+ results[49][8]="1.936786033011718E+28";
+ results[49][9]="1889808526690925";
+ results[49][10]="6.896975385705340E+23";
+ results[49][11]="22900982379.74620";
+ results[49][12]="3.074978762902205E+18";
+ results[49][13]="288133.0824752154";
+ results[49][14]="23168028823874.12";
+ results[49][15]="2.488816870650781E+21";
+ results[49][16]="2.859154284968690E+37";
+ results[49][17]="2.945594228012286E+16";
+ results[49][18]="2.243899587646931E+32";
+ results[49][19]="189857195390.0929";
+ results[49][20]="7.593532693891262E+27";
+ results[49][21]="3539894.906509671";
+ results[49][22]="4.362483022786321E+22";
+ results[49][23]="38.79753030008030";
+ results[49][24]="2.310754187742728E+17";
+ results[49][25]="2.313218778660363E+17";
+ results[49][26]="6.195894108923685E+41";
+ results[49][27]="2696701525096.859";
+ results[49][28]="9.555460076266186E+36";
+ results[49][29]="46033134.51994738";
+ results[49][30]="2.153534968284877E+31";
+ results[49][31]="561.6670193647148";
+ results[49][32]="4.378249647482396E+26";
+ results[49][33]="0.002416775400787454";
+ results[49][34]="1.158290892101044E+22";
+ results[49][35]="28433438956710.49";
+ results[49][36]="5.991439348740924E+45";
+ results[49][37]="240569312.5704755";
+ results[49][38]="2.932249376494788E+40";
+ results[49][39]="2563.983673607429";
+ results[49][40]="5.316426395714516E+35";
+ results[49][41]="0.04104894137430629";
+ results[49][42]="1.919959854688953E+30";
+ results[49][43]="7.405088074035996E-7";
+ results[49][44]="5.043581843006266E+25";
+ results[49][45]="6495382448.194808";
+ results[49][46]="3.536469240253245E+49";
+ results[49][47]="23612.38381341809";
+ results[49][48]="2.928407865794388E+44";
+ results[49][49]="1";
+ results[49][50]="9.869157486415798E+39";
+ results[49][51]="0.000002489085172882200";
+ results[49][52]="1.768437487955098E+35";
+ results[49][53]="5.184777736365438E-11";
+ results[49][54]="7.211887672551995E+29";
+ results[49][55]="262593.2892956190";
+ results[49][56]="3.031234734820807E+53";
+ results[49][57]="2.633841694453359";
+ results[49][58]="2.422826902946868E+48";
+ results[49][59]="0.00005168001420772782";
+ results[49][60]="1.251427730987327E+44";
+ results[49][61]="2.389007726094191E-10";
+ results[49][62]="8.946980828098355E+38";
+ results[49][63]="2.031939678710256E-15";
+ results[49][64]="9.348627889203813E+33";
+ results[49][65]="22.04586429236709";
+ results[49][66]="1.965412665648703E+57";
+ results[49][67]="0.0007116433335235624";
+ results[49][68]="4.192923222382870E+52";
+ results[49][69]="3.160782854106722E-9";
+ results[49][70]="3.078564958187471E+47";
+ results[49][71]="1.931646524711914E-14";
+ results[49][72]="7.503497828319405E+42";
+ results[49][73]="3.660260159965578E-19";
+ results[49][74]="2.095639710265825E+37";
+ results[50][0]="1.709844323220016E-10";
+ results[50][1]="3.759744355260485E-16";
+ results[50][2]="8.435652158126978E-21";
+ results[50][3]="9.836890501942623E-26";
+ results[50][4]="6.865836997247178E-31";
+ results[50][5]="2.142098545603874E-15";
+ results[50][6]="0.000001331216165209868";
+ results[50][7]="2.054259145142100E-20";
+ results[50][8]="1.962463397384800E-12";
+ results[50][9]="1.914863076500820E-25";
+ results[50][10]="6.988413545126361E-17";
+ results[50][11]="2.320459716168051E-30";
+ results[50][12]="3.115745966294182E-22";
+ results[50][13]="2.919530698256769E-35";
+ results[50][14]="2.347518403243974E-27";
+ results[50][15]="2.521812904573124E-19";
+ results[50][16]="0.002897060148147514";
+ results[50][17]="2.984646087638879E-24";
+ results[50][18]="2.273648577130825E-8";
+ results[50][19]="1.923742686763465E-29";
+ results[50][20]="7.694205614150171E-13";
+ results[50][21]="3.586825837344361E-34";
+ results[50][22]="4.420319595457841E-18";
+ results[50][23]="3.931189704235886E-39";
+ results[50][24]="2.341389516707296E-23";
+ results[50][25]="2.343886782477983E-23";
+ results[50][26]="62.78037530003851";
+ results[50][27]="2.732453635286172E-28";
+ results[50][28]="0.0009682143677835323";
+ results[50][29]="4.664342886746792E-33";
+ results[50][30]="2.182085929066454E-9";
+ results[50][31]="5.691134427004636E-38";
+ results[50][32]="4.436295249628704E-14";
+ results[50][33]="2.448816329168904E-43";
+ results[50][34]="1.173647186900553E-18";
+ results[50][35]="2.881040149156310E-27";
+ results[50][36]="607087.2166127371";
+ results[50][37]="2.437587128400801E-32";
+ results[50][38]="2.971124313834108";
+ results[50][39]="2.597976247857604E-37";
+ results[50][40]="0.00005386910081262968";
+ results[50][41]="4.159315669124470E-42";
+ results[50][42]="1.945414142323337E-10";
+ results[50][43]="7.503262648537709E-47";
+ results[50][44]="5.110448232230970E-15";
+ results[50][45]="6.581496401425599E-31";
+ results[50][46]="3583354754.568408";
+ results[50][47]="2.392543015543006E-36";
+ results[50][48]="29672.31873465527";
+ results[50][49]="1.013257718682096E-40";
+ results[50][50]="1";
+ results[50][51]="2.522084763880048E-46";
+ results[50][52]="0.00001791882934677280";
+ results[50][53]="5.253516061023365E-51";
+ results[50][54]="7.307500850481565E-11";
+ results[50][55]="2.660746772529066E-35";
+ results[50][56]="30714219921944.59";
+ results[50][57]="2.668760426691597E-40";
+ results[50][58]="245494806.0441551";
+ results[50][59]="5.236517329758060E-45";
+ results[50][60]="12680.18807795731";
+ results[50][61]="2.420680518456101E-50";
+ results[50][62]="0.09065597382971390";
+ results[50][63]="2.058878563349585E-55";
+ results[50][64]="9.472569367822474E-7";
+ results[50][65]="2.233814215925896E-39";
+ results[50][66]="1.991469553864102E+17";
+ results[50][67]="7.210781006414067E-44";
+ results[50][68]="4248511818920.849";
+ results[50][69]="3.202687624001662E-49";
+ results[50][70]="31193797.06347679";
+ results[50][71]="1.957255750929793E-54";
+ results[50][72]="760.2977091658982";
+ results[50][73]="3.708786859469685E-59";
+ results[50][74]="0.002123423112003558";
+ results[51][0]="6.779487936755711E+35";
+ results[51][1]="1.490728784815458E+30";
+ results[51][2]="3.344713975889266E+25";
+ results[51][3]="3.900301307403033E+20";
+ results[51][4]="2722286378148756";
+ results[51][5]="8.493364601705167E+30";
+ results[51][6]="5.278237211829022E+39";
+ results[51][7]="8.145083680620504E+25";
+ results[51][8]="7.781115946181321E+33";
+ results[51][9]="7.592381921196569E+20";
+ results[51][10]="2.770887658182901E+29";
+ results[51][11]="9200561969210697";
+ results[51][12]="1.235385111125618E+24";
+ results[51][13]="115758627151.1858";
+ results[51][14]="9.307848954420085E+18";
+ results[51][15]="9.998922084971854E+26";
+ results[51][16]="1.148676757275435E+43";
+ results[51][17]="1.183404352773304E+22";
+ results[51][18]="9.014957029568579E+37";
+ results[51][19]="7.627589343206385E+16";
+ results[51][20]="3.050732364091198E+33";
+ results[51][21]="1422167045577.915";
+ results[51][22]="1.752645136580379E+28";
+ results[51][23]="15587064.16428300";
+ results[51][24]="9.283548079903686E+22";
+ results[51][25]="9.293449673246033E+22";
+ results[51][26]="2.489225429658254E+47";
+ results[51][27]="1.083410706261310E+18";
+ results[51][28]="3.838944597143528E+42";
+ results[51][29]="18493997321370.88";
+ results[51][30]="8.651913529303709E+36";
+ results[51][31]="225651988.7241708";
+ results[51][32]="1.758979441596474E+32";
+ results[51][33]="970.9492576298560";
+ results[51][34]="4.653480341774795E+27";
+ results[51][35]="1.142324869654275E+19";
+ results[51][36]="2.407084905737968E+51";
+ results[51][37]="96649690895033.44";
+ results[51][38]="1.178043004892208E+46";
+ results[51][39]="1030090774.530830";
+ results[51][40]="2.135895731345520E+41";
+ results[51][41]="16491.57763724665";
+ results[51][42]="7.713516096621809E+35";
+ results[51][43]="0.2975023978573374";
+ results[51][44]="2.026279332645786E+31";
+ results[51][45]="2609546076992446";
+ results[51][46]="1.420790770352885E+55";
+ results[51][47]="9486370362.359466";
+ results[51][48]="1.176499662485828E+50";
+ results[51][49]="401754.0303139023";
+ results[51][50]="3.964973795970168E+45";
+ results[51][51]="1";
+ results[51][52]="7.104768881441538E+40";
+ results[51][53]="0.00002083005351866606";
+ results[51][54]="2.897404938618912E+35";
+ results[51][55]="105497912307.8994";
+ results[51][56]="1.217810771541752E+59";
+ results[51][57]="1058156.515955435";
+ results[51][58]="9.733804730118538E+53";
+ results[51][59]="20.76265399463438";
+ results[51][60]="5.027661345707404E+49";
+ results[51][61]="0.00009597934824093921";
+ results[51][62]="3.594485606829729E+44";
+ results[51][63]="8.163399552765810E-10";
+ results[51][64]="3.755848932392581E+39";
+ results[51][65]="8857014.831211825";
+ results[51][66]="7.896124596543564E+62";
+ results[51][67]="285.9055773891117";
+ results[51][68]="1.684523803389072E+58";
+ results[51][69]="0.001269857250584455";
+ results[51][70]="1.236825879534966E+53";
+ results[51][71]="7.760467764448543E-9";
+ results[51][72]="3.014560493978934E+48";
+ results[51][73]="1.470524271263579E-13";
+ results[51][74]="8.419316996851535E+42";
+ results[52][0]="0.000009542165339768479";
+ results[52][1]="2.098208695724657E-11";
+ results[52][2]="4.707702715884311E-16";
+ results[52][3]="5.489694840870986E-21";
+ results[52][4]="3.831632560574457E-26";
+ results[52][5]="1.195445586399130E-10";
+ results[52][6]="0.07429146957357580";
+ results[52][7]="1.146424861461206E-15";
+ results[52][8]="1.095196209197808E-7";
+ results[52][9]="1.068631794769388E-20";
+ results[52][10]="3.900039120795011E-12";
+ results[52][11]="1.294983992124446E-25";
+ results[52][12]="1.738811116505963E-17";
+ results[52][13]="1.629308835837862E-30";
+ results[52][14]="1.310084692372364E-22";
+ results[52][15]="1.407353603167891E-14";
+ results[52][16]="161.6768647148971";
+ results[52][17]="1.665647922572809E-19";
+ results[52][18]="0.001268859998122764";
+ results[52][19]="1.073587258148610E-24";
+ results[52][20]="4.293922033213574E-8";
+ results[52][21]="2.001707682980056E-29";
+ results[52][22]="2.466857354302527E-13";
+ results[52][23]="2.193887573879874E-34";
+ results[52][24]="1.306664331355432E-18";
+ results[52][25]="1.308057985886294E-18";
+ results[52][26]="3503598.035624204";
+ results[52][27]="1.524906333112822E-23";
+ results[52][28]="54.03334944745757";
+ results[52][29]="2.603039962310287E-28";
+ results[52][30]="0.0001217761432311118";
+ results[52][31]="3.176063746613903E-33";
+ results[52][32]="2.475772922312967E-9";
+ results[52][33]="1.366616245837476E-38";
+ results[52][34]="6.549798338873787E-14";
+ results[52][35]="1.607828331528359E-22";
+ results[52][36]="33879848111.95684";
+ results[52][37]="1.360349541383301E-27";
+ results[52][38]="165810.1796906287";
+ results[52][39]="1.449858245525120E-32";
+ results[52][40]="3.006284605435543";
+ results[52][41]="2.321198326426144E-37";
+ results[52][42]="0.00001085681494407283";
+ results[52][43]="4.187362077807307E-42";
+ results[52][44]="2.851998941075561E-10";
+ results[52][45]="3.672949986886802E-26";
+ results[52][46]="199977056827865.5";
+ results[52][47]="1.335211675518248E-31";
+ results[52][48]="1655929534.258291";
+ results[52][49]="5.654709351113861E-36";
+ results[52][50]="55807.21712605078";
+ results[52][51]="1.407505320281584E-41";
+ results[52][52]="1";
+ results[52][53]="2.931841114927259E-46";
+ results[52][54]="0.000004078112866116254";
+ results[52][55]="1.484888728519684E-30";
+ results[52][56]="1.714075140041236E+18";
+ results[52][57]="1.489360925897899E-35";
+ results[52][58]="13700381944223.89";
+ results[52][59]="2.922354596061357E-40";
+ results[52][60]="707646009.2657238";
+ results[52][61]="1.350914432862808E-45";
+ results[52][62]="5059.257615288420";
+ results[52][63]="1.149002830210218E-50";
+ results[52][64]="0.05286377354516463";
+ results[52][65]="1.246629549674354E-34";
+ results[52][66]="1.111383737924134E+22";
+ results[52][67]="4.024136212733528E-39";
+ results[52][68]="2.370976215411088E+17";
+ results[52][69]="1.787330836195764E-44";
+ results[52][70]="1740839005707.414";
+ results[52][71]="1.092289966633505E-49";
+ results[52][72]="42430099.33586029";
+ results[52][73]="2.069770735406687E-54";
+ results[52][74]="118.5023346620570";
+ results[53][0]="3.254666595398102E+40";
+ results[53][1]="7.156624842464271E+34";
+ results[53][2]="1.605715497990454E+30";
+ results[53][3]="1.872439407756647E+25";
+ results[53][4]="1.306903208726412E+20";
+ results[53][5]="4.077456927364187E+35";
+ results[53][6]="2.533952784662378E+44";
+ results[53][7]="3.910255762579582E+30";
+ results[53][8]="3.735523741793833E+38";
+ results[53][9]="3.644917145504665E+25";
+ results[53][10]="1.330235496370605E+34";
+ results[53][11]="4.416965112915320E+20";
+ results[53][12]="5.930782222996091E+28";
+ results[53][13]="5557288993398558";
+ results[53][14]="4.468470974440470E+23";
+ results[53][15]="4.800238307602860E+31";
+ results[53][16]="5.514516591357251E+47";
+ results[53][17]="5.681235296456829E+26";
+ results[53][18]="4.327860714083221E+42";
+ results[53][19]="3.661819369005083E+21";
+ results[53][20]="1.464582105541592E+38";
+ results[53][21]="6.827476675964822E+16";
+ results[53][22]="8.414021284245927E+32";
+ results[53][23]="748296885090.3456";
+ results[53][24]="4.456804718040974E+27";
+ results[53][25]="4.461558231196124E+27";
+ results[53][26]="1.195016338977540E+52";
+ results[53][27]="5.201190219172758E+22";
+ results[53][28]="1.842983549563809E+47";
+ results[53][29]="8.878516468907865E+17";
+ results[53][30]="4.153572395553678E+41";
+ results[53][31]="10833000910053.42";
+ results[53][32]="8.444430735716701E+36";
+ results[53][33]="46612902.68696511";
+ results[53][34]="2.234022268644081E+32";
+ results[53][35]="5.484022730093443E+23";
+ results[53][36]="1.155582679411242E+56";
+ results[53][37]="4.639915630001839E+18";
+ results[53][38]="5.655496774583657E+50";
+ results[53][39]="49452142482867.52";
+ results[53][40]="1.025391379542793E+46";
+ results[53][41]="791720367.9994558";
+ results[53][42]="3.703070704887838E+40";
+ results[53][43]="14282.36358541959";
+ results[53][44]="9.727672234879347E+35";
+ results[53][45]="1.252779343391509E+20";
+ results[53][46]="6.820869514711989E+59";
+ results[53][47]="455417474269022.8";
+ results[53][48]="5.648087564592924E+54";
+ results[53][49]="19287229864.95862";
+ results[53][50]="1.903487090139787E+50";
+ results[53][51]="48007.55788283925";
+ results[53][52]="3.410826033199997E+45";
+ results[53][53]="1";
+ results[53][54]="1.390973353007717E+40";
+ results[53][55]="5064697131640181";
+ results[53][56]="5.846412110513578E+63";
+ results[53][57]="50799510188.83404";
+ results[53][58]="4.672961940014202E+58";
+ results[53][59]="996764.3134487737";
+ results[53][60]="2.413657430693617E+54";
+ results[53][61]="4.607734116234075";
+ results[53][62]="1.725624758289108E+49";
+ results[53][63]="0.00003919048765501487";
+ results[53][64]="1.803091350210368E+44";
+ results[53][65]="425203652178.5674";
+ results[53][66]="3.790736586186758E+67";
+ results[53][67]="13725628.55553436";
+ results[53][68]="8.086987399622141E+62";
+ results[53][69]="60.96274546037631";
+ results[53][70]="5.937699000276846E+57";
+ results[53][71]="0.0003725611053996715";
+ results[53][72]="1.447216874060142E+53";
+ results[53][73]="7.059627907080629E-9";
+ results[53][74]="4.041908480603224E+47";
+ results[54][0]="2.339848271255880";
+ results[54][1]="0.000005145048125465107";
+ results[54][2]="1.154382644727447E-10";
+ results[54][3]="1.346136073496915E-15";
+ results[54][4]="9.395602050179328E-21";
+ results[54][5]="0.00002931369546761954";
+ results[54][6]="18217.11953851009";
+ results[54][7]="2.811165112634539E-10";
+ results[54][8]="0.02685546587730432";
+ results[54][9]="2.620407599917871E-15";
+ results[54][10]="9.563342773563720E-7";
+ results[54][11]="3.175449122274317E-20";
+ results[54][12]="4.263764083022794E-12";
+ results[54][13]="3.995251944533639E-25";
+ results[54][14]="3.212477769454207E-17";
+ results[54][15]="3.450992283369952E-9";
+ results[54][16]="39645019.65068670";
+ results[54][17]="4.084359548780881E-14";
+ results[54][18]="311.1390095809556";
+ results[54][19]="2.632558963898978E-19";
+ results[54][20]="0.01052918880419032";
+ results[54][21]="4.908416585552623E-24";
+ results[54][22]="6.049016874444212E-8";
+ results[54][23]="5.379663697167850E-29";
+ results[54][24]="3.204090652350726E-13";
+ results[54][25]="3.207508052939222E-13";
+ results[54][26]="859122381024.4411";
+ results[54][27]="3.739245045871056E-18";
+ results[54][28]="13249596.37493202";
+ results[54][29]="6.382952232485079E-23";
+ results[54][30]="29.86090557789883";
+ results[54][31]="7.788072206149096E-28";
+ results[54][32]="0.0006070878868712484";
+ results[54][33]="3.351099615688073E-33";
+ results[54][34]="1.606085597408052E-8";
+ results[54][35]="3.942579286824783E-17";
+ results[54][36]="8307726937489580";
+ results[54][37]="3.335732938354928E-22";
+ results[54][38]="40658555840.44592";
+ results[54][39]="3.555218536425345E-27";
+ results[54][40]="737175.4299430523";
+ results[54][41]="5.691844249118863E-32";
+ results[54][42]="2.662215416909782";
+ results[54][43]="1.026789158436190E-36";
+ results[54][44]="0.00006993428173045223";
+ results[54][45]="9.006494198343990E-21";
+ results[54][46]="4.903666558358682E+19";
+ results[54][47]="3.274092011067419E-26";
+ results[54][48]="406052894714338.1";
+ results[54][49]="1.386599522072340E-30";
+ results[54][50]="13684569053.92081";
+ results[54][51]="3.451364311115807E-36";
+ results[54][52]="245211.4575613350";
+ results[54][53]="7.189210331295627E-41";
+ results[54][54]="1";
+ results[54][55]="3.641117294367092E-25";
+ results[54][56]="4.203108634591608E+23";
+ results[54][57]="3.652083634743231E-30";
+ results[54][58]="3.359490625690135E+18";
+ results[54][59]="7.165948300112717E-35";
+ results[54][60]="173522909369510.1";
+ results[54][61]="3.312596971229334E-40";
+ results[54][62]="1240587934.023157";
+ results[54][63]="2.817486587379466E-45";
+ results[54][64]="12962.80296320216";
+ results[54][65]="3.056878489146789E-29";
+ results[54][66]="2.725240262863416E+27";
+ results[54][67]="9.867643061497388E-34";
+ results[54][68]="5.813905336242105E+22";
+ results[54][69]="4.382739994878830E-39";
+ results[54][70]="4.268736699691402E+17";
+ results[54][71]="2.678420147978238E-44";
+ results[54][72]="10404346502618.53";
+ results[54][73]="5.075314988468698E-49";
+ results[54][74]="29058130.20690411";
+ results[55][0]="6.426182081186150E+24";
+ results[55][1]="1.413041028209840E+19";
+ results[55][2]="317040773861723.4";
+ results[55][3]="3697041222.976872";
+ results[55][4]="25804.17297930660";
+ results[55][5]="8.050741873371843E+19";
+ results[55][6]="5.003167452664180E+28";
+ results[55][7]="772061124475030.9";
+ results[55][8]="7.375611304488999E+22";
+ results[55][9]="7196712953.937829";
+ results[55][10]="2.626485773572434E+18";
+ results[55][11]="87210.84396777946";
+ results[55][12]="11710043204647.52";
+ results[55][13]="1.097259885232042";
+ results[55][14]="88227802.34034201";
+ results[55][15]="9477838818070297";
+ results[55][16]="1.088814680922766E+32";
+ results[55][17]="112173248444.9072";
+ results[55][18]="8.545152062590683E+26";
+ results[55][19]="723008.5578324046";
+ results[55][20]="2.891746668111807E+22";
+ results[55][21]="13.48052311620413";
+ results[55][22]="1.661307885852018E+17";
+ results[55][23]="0.0001477476077326687";
+ results[55][24]="879974577393.4671";
+ results[55][25]="880913135619.4773";
+ results[55][26]="2.359502074688797E+36";
+ results[55][27]="10269499.01244810";
+ results[55][28]="3.638882052887863E+31";
+ results[55][29]="175.3020217821514";
+ results[55][30]="8.201028191015562E+25";
+ results[55][31]="0.002138923735908606";
+ results[55][32]="1.667312085250398E+21";
+ results[55][33]="9.203492622641725E-9";
+ results[55][34]="4.410969127231112E+16";
+ results[55][35]="108279381.5218219";
+ results[55][36]="2.281642217442943E+40";
+ results[55][37]="916.1289430349850";
+ results[55][38]="1.116650537551916E+35";
+ results[55][39]="0.009764086814575751";
+ results[55][40]="2.024585780533582E+30";
+ results[55][41]="1.563213648163519E-7";
+ results[55][42]="7.311534349712662E+24";
+ results[55][43]="2.819983745167070E-12";
+ results[55][44]="1.920681924711475E+20";
+ results[55][45]="24735.52338530067";
+ results[55][46]="1.346747759525569E+44";
+ results[55][47]="0.08991998187294129";
+ results[55][48]="1.115187624805477E+39";
+ results[55][49]="0.000003808170432239159";
+ results[55][50]="3.758343373088038E+34";
+ results[55][51]="9.478860558694889E-12";
+ results[55][52]="6.734511352893900E+29";
+ results[55][53]="1.974451727335874E-16";
+ results[55][54]="2.746409739524259E+24";
+ results[55][55]="1";
+ results[55][56]="1.154345849032090E+48";
+ results[55][57]="0.00001003011806401597";
+ results[55][58]="9.226537774235836E+42";
+ results[55][59]="1.968063020435687E-10";
+ results[55][60]="4.765650083230079E+38";
+ results[55][61]="9.097748584902804E-16";
+ results[55][62]="3.407162784737478E+33";
+ results[55][63]="7.737972604557934E-21";
+ results[55][64]="3.560116830967234E+28";
+ results[55][65]="0.00008395440855134944";
+ results[55][66]="7.484626400471738E+51";
+ results[55][67]="2.710059101024540E-9";
+ results[55][68]="1.596736624012738E+47";
+ results[55][69]="1.203679980773772E-14";
+ results[55][70]="1.172370004749711E+42";
+ results[55][71]="7.356039180945439E-20";
+ results[55][72]="2.857459856817670E+37";
+ results[55][73]="1.393889451548389E-24";
+ results[55][74]="7.980553181260552E+31";
+ results[56][0]="5.566946930657264E-24";
+ results[56][1]="1.224105435467771E-29";
+ results[56][2]="2.746497283526938E-34";
+ results[56][3]="3.202715395976701E-39";
+ results[56][4]="2.235393578184839E-44";
+ results[56][5]="6.974289273983464E-29";
+ results[56][6]="4.334201449989442E-20";
+ results[56][7]="6.688299915682963E-34";
+ results[56][8]="6.389429399060419E-26";
+ results[56][9]="6.234451278160885E-39";
+ results[56][10]="2.275302307167926E-30";
+ results[56][11]="7.555001305796269E-44";
+ results[56][12]="1.014431092247293E-35";
+ results[56][13]="9.505469146461484E-49";
+ results[56][14]="7.643099545454276E-41";
+ results[56][15]="8.210571230465625E-33";
+ results[56][16]="9.432309059158727E-17";
+ results[56][17]="9.717473193927414E-38";
+ results[56][18]="7.402592619669160E-22";
+ results[56][19]="6.263361699083869E-43";
+ results[56][20]="2.505095566061517E-26";
+ results[56][21]="1.167806262525866E-47";
+ results[56][22]="1.439176904603599E-31";
+ results[56][23]="1.279924970982950E-52";
+ results[56][24]="7.623144988404633E-37";
+ results[56][25]="7.631275638562877E-37";
+ results[56][26]="2.044016597510373E-12";
+ results[56][27]="8.896379729748234E-42";
+ results[56][28]="3.152332601134258E-17";
+ results[56][29]="1.518626518466200E-46";
+ results[56][30]="7.104481033905097E-23";
+ results[56][31]="1.852931456982391E-51";
+ results[56][32]="1.444378291521926E-27";
+ results[56][33]="7.972907452613771E-57";
+ results[56][34]="3.821185072852883E-32";
+ results[56][35]="9.380150811181354E-41";
+ results[56][36]="1.976567264789908E-8";
+ results[56][37]="7.936347185751581E-46";
+ results[56][38]="9.673448719794147E-14";
+ results[56][39]="8.458545437455212E-51";
+ results[56][40]="1.753881457824083E-18";
+ results[56][41]="1.354198700046664E-55";
+ results[56][42]="6.333920077629528E-24";
+ results[56][43]="2.442927955717607E-60";
+ results[56][44]="1.663870430445044E-28";
+ results[56][45]="2.142817371937639E-44";
+ results[56][46]="0.0001166676140131492";
+ results[56][47]="7.789691620439270E-50";
+ results[56][48]="9.660775630982277E-10";
+ results[56][49]="3.298985685643760E-54";
+ results[56][50]="3.255820927704967E-14";
+ results[56][51]="8.211456355686501E-60";
+ results[56][52]="5.834049958719679E-19";
+ results[56][53]="1.710450753551403E-64";
+ results[56][54]="2.379191419821972E-24";
+ results[56][55]="8.662915025323579E-49";
+ results[56][56]="1";
+ results[56][57]="8.689006048253338E-54";
+ results[56][58]="0.000007992871271614319";
+ results[56][59]="1.704916271051602E-58";
+ results[56][60]="4.128442171144841E-10";
+ results[56][61]="7.881302291277083E-64";
+ results[56][62]="2.951596168162563E-15";
+ results[56][63]="6.703339914156715E-69";
+ results[56][64]="3.084098958689342E-20";
+ results[56][65]="7.272899072816394E-53";
+ results[56][66]="6483.868250358015";
+ results[56][67]="2.347701170578040E-57";
+ results[56][68]="0.1383239369164440";
+ results[56][69]="1.042737739112631E-62";
+ results[56][70]="0.000001015614172938495";
+ results[56][71]="6.372474234748120E-68";
+ results[56][72]="2.475393192788476E-11";
+ results[56][73]="1.207514587345858E-72";
+ results[56][74]="6.913485406433592E-17";
+ results[57][0]="6.406885781574903E+29";
+ results[57][1]="1.408798001370755E+24";
+ results[57][2]="3.160887756637065E+19";
+ results[57][3]="368593988563342.1";
+ results[57][4]="2572668917.216598";
+ results[57][5]="8.026567406274776E+24";
+ results[57][6]="4.988144128246639E+33";
+ results[57][7]="7.697428081578381E+19";
+ results[57][8]="7.353464094256007E+27";
+ results[57][9]="717510293299212.7";
+ results[57][10]="2.618599060159830E+23";
+ results[57][11]="8694897050.180986";
+ results[57][12]="1.167488072414467E+18";
+ results[57][13]="109396.5074218388";
+ results[57][14]="8796287518974.268";
+ results[57][15]="9.449379117552936E+20";
+ results[57][16]="1.085545228853283E+37";
+ results[57][17]="1.118364188028252E+16";
+ results[57][18]="8.519492999037822E+31";
+ results[57][19]="72083753473.07911";
+ results[57][20]="2.883063439189447E+27";
+ results[57][21]="1344004.430472940";
+ results[57][22]="1.656319372562645E+22";
+ results[57][23]="14.73039567328003";
+ results[57][24]="8.773322225891460E+16";
+ results[57][25]="8.782679625475591E+16";
+ results[57][26]="2.352417049958506E+41";
+ results[57][27]="1023866214425.824";
+ results[57][28]="3.627955353728795E+36";
+ results[57][29]="17477563.14166077";
+ results[57][30]="8.176402449775297E+30";
+ results[57][31]="213.2501055578004";
+ results[57][32]="1.662305542775258E+26";
+ results[57][33]="0.0009175856718636401";
+ results[57][34]="4.397724033833556E+21";
+ results[57][35]="10795424423794.65";
+ results[57][36]="2.274790987384843E+45";
+ results[57][37]="91337802.52514549";
+ results[57][38]="1.113297501011488E+40";
+ results[57][39]="973.4767579262472";
+ results[57][40]="2.018506429946206E+35";
+ results[57][41]="0.01558519688588414";
+ results[57][42]="7.289579547366953E+29";
+ results[57][43]="2.811516003270229E-7";
+ results[57][44]="1.914914572742777E+25";
+ results[57][45]="2466124847.925947";
+ results[57][46]="1.342703795638417E+49";
+ results[57][47]="8964.997350882443";
+ results[57][48]="1.111838981044821E+44";
+ results[57][49]="0.3796735400255500";
+ results[57][50]="3.747057959937145E+39";
+ results[57][51]="9.450397790132930E-7";
+ results[57][52]="6.714289213658032E+34";
+ results[57][53]="1.968522917411524E-11";
+ results[57][54]="2.738162922904441E+29";
+ results[57][55]="99699.72373382105";
+ results[57][56]="1.150879622417825E+53";
+ results[57][57]="1";
+ results[57][58]="9.198832671109769E+47";
+ results[57][59]="0.00001962153394281874";
+ results[57][60]="4.751339967101001E+43";
+ results[57][61]="9.070430205145709E-11";
+ results[57][62]="3.396931883544830E+38";
+ results[57][63]="7.714737309343017E-16";
+ results[57][64]="3.549426645075597E+33";
+ results[57][65]="8.370231338805882";
+ results[57][66]="7.462151843778957E+56";
+ results[57][67]="0.0002701921436744741";
+ results[57][68]="1.591942002897441E+52";
+ results[57][69]="1.200065615470761E-9";
+ results[57][70]="1.168849655873646E+47";
+ results[57][71]="7.333950741154235E-15";
+ results[57][72]="2.848879583052055E+42";
+ results[57][73]="1.389703932348617E-19";
+ results[57][74]="7.956589474147437E+36";
+ results[58][0]="6.964890014465238E-19";
+ results[58][1]="1.531496497153692E-24";
+ results[58][2]="3.436183556816159E-29";
+ results[58][3]="4.006964815448415E-34";
+ results[58][4]="2.796734117467348E-39";
+ results[58][5]="8.725636929437082E-24";
+ results[58][6]="5.422583828394453E-15";
+ results[58][7]="8.367831394252054E-29";
+ results[58][8]="7.993910050511732E-21";
+ results[58][9]="7.800014620905704E-34";
+ results[58][10]="2.846664521232035E-25";
+ results[58][11]="9.452174380221672E-39";
+ results[58][12]="1.269169811166505E-30";
+ results[58][13]="1.189243367426543E-43";
+ results[58][14]="9.562395396755339E-36";
+ results[58][15]="1.027236765294149E-27";
+ results[58][16]="1.180090200208327E-11";
+ results[58][17]="1.215767508784710E-32";
+ results[58][18]="9.261493608634160E-17";
+ results[58][19]="7.836184878051788E-38";
+ results[58][20]="3.134162281529605E-21";
+ results[58][21]="1.461059765435212E-42";
+ results[58][22]="1.800575607560021E-26";
+ results[58][23]="1.601333147361503E-47";
+ results[58][24]="9.537429953960697E-32";
+ results[58][25]="9.547602331172774E-32";
+ results[58][26]="2.557299533609959E-7";
+ results[58][27]="1.113039285562200E-36";
+ results[58][28]="3.943930152271277E-12";
+ results[58][29]="1.899976199866263E-41";
+ results[58][30]="8.888521774566507E-18";
+ results[58][31]="2.318230075295776E-46";
+ results[58][32]="1.807083140011844E-22";
+ results[58][33]="9.975022969440973E-52";
+ results[58][34]="4.780741416946553E-27";
+ results[58][35]="1.173564604311067E-35";
+ results[58][36]="0.002472912671331814";
+ results[58][37]="9.929281876384678E-41";
+ results[58][38]="1.210259541417636E-8";
+ results[58][39]="1.058261186752084E-45";
+ results[58][40]="2.194307149738259E-13";
+ results[58][41]="1.694258113296445E-50";
+ results[58][42]="7.924461513753702E-19";
+ results[58][43]="3.056383460588637E-55";
+ results[58][44]="2.081693016068045E-23";
+ results[58][45]="2.680910650403675E-39";
+ results[58][46]="14.59645852517100";
+ results[58][47]="9.745798919724109E-45";
+ results[58][48]="0.0001208673992447659";
+ results[58][49]="4.127410005162593E-49";
+ results[58][50]="4.073405935195787E-9";
+ results[58][51]="1.027347504625585E-54";
+ results[58][52]="7.299066581290476E-14";
+ results[58][53]="2.139970350361897E-59";
+ results[58][54]="2.976641733579987E-19";
+ results[58][55]="1.083830169527293E-43";
+ results[58][56]="125111.4857249578";
+ results[58][57]="1.087094456170119E-48";
+ results[58][58]="1";
+ results[58][59]="2.133046077079208E-53";
+ results[58][60]="0.00005165155337615015";
+ results[58][61]="9.860414391091898E-59";
+ results[58][62]="3.692785818589105E-10";
+ results[58][63]="8.386648159795576E-64";
+ results[58][64]="3.858562028444187E-15";
+ results[58][65]="9.099232085277269E-48";
+ results[58][66]="811206390.0471738";
+ results[58][67]="2.937243814892411E-52";
+ results[58][68]="17305.91325894164";
+ results[58][69]="1.304584677618646E-57";
+ results[58][70]="0.1270649980996593";
+ results[58][71]="7.972697192533506E-63";
+ results[58][72]="0.000003097001201032130";
+ results[58][73]="1.510739440573996E-67";
+ results[58][74]="8.649564307367203E-12";
+ results[59][0]="3.265231862221327E+34";
+ results[59][1]="7.179856607930284E+28";
+ results[59][2]="1.610927955912394E+24";
+ results[59][3]="1.878517702221967E+19";
+ results[59][4]="131114566512174.5";
+ results[59][5]="4.090693128103987E+29";
+ results[59][6]="2.542178477372429E+38";
+ results[59][7]="3.922949196535957E+24";
+ results[59][8]="3.747649962375796E+32";
+ results[59][9]="3.656749239841227E+19";
+ results[59][10]="1.334553693809554E+28";
+ results[59][11]="443130342180164.7";
+ results[59][12]="5.950034670157650E+22";
+ results[59][13]="5575329010.496484";
+ results[59][14]="4.482976481149991E+17";
+ results[59][15]="4.815820794179703E+25";
+ results[59][16]="5.532417761102616E+41";
+ results[59][17]="5.699677666829715E+20";
+ results[59][18]="4.341909773142817E+36";
+ results[59][19]="3673706331174018";
+ results[59][20]="1.469336417627336E+32";
+ results[59][21]="68496399638.76680";
+ results[59][22]="8.441334797725325E+26";
+ results[59][23]="750725.9991093196";
+ results[59][24]="4.471272353863239E+21";
+ results[59][25]="4.476041297826234E+21";
+ results[59][26]="1.198895589312202E+46";
+ results[59][27]="5.218074271917703E+16";
+ results[59][28]="1.848966224710778E+41";
+ results[59][29]="890733782210.6083";
+ results[59][30]="4.167055681580780E+35";
+ results[59][31]="10868166.89150073";
+ results[59][32]="8.471842964059609E+30";
+ results[59][33]="46.76421703510423";
+ results[59][34]="2.241274329850788E+26";
+ results[59][35]="5.501824910965054E+17";
+ results[59][36]="1.159333920586464E+50";
+ results[59][37]="4654977678672.980";
+ results[59][38]="5.673855592818941E+44";
+ results[59][39]="49612673.54342235";
+ results[59][40]="1.028719994995578E+40";
+ results[59][41]="794.2904429033256";
+ results[59][42]="3.715091576739267E+34";
+ results[59][43]="0.01432872685419792";
+ results[59][44]="9.759250109207765E+29";
+ results[59][45]="125684610342532.4";
+ results[59][46]="6.843011354521704E+53";
+ results[59][47]="456895846.0132791";
+ results[59][48]="5.666422331123308E+48";
+ results[59][49]="19349.83988163200";
+ results[59][50]="1.909666171287554E+44";
+ results[59][51]="0.04816339954701486";
+ results[59][52]="3.421898223260666E+39";
+ results[59][53]="0.000001003246190205216";
+ results[59][54]="1.395488717081967E+34";
+ results[59][55]="5081138101.861297";
+ results[59][56]="5.865390676242383E+57";
+ results[59][57]="50964.41506123880";
+ results[59][58]="4.688131263293223E+52";
+ results[59][59]="1";
+ results[59][60]="2.421492621803881E+48";
+ results[59][61]="0.000004622691697590433";
+ results[59][62]="1.731226464477344E+43";
+ results[59][63]="3.931770743217822E-11";
+ results[59][64]="1.808944527690531E+38";
+ results[59][65]="426583.9441094915";
+ results[59][66]="3.803042038163392E+61";
+ results[59][67]="13.77018455651177";
+ results[59][68]="8.113239298908500E+56";
+ results[59][69]="0.00006116064212757286";
+ results[59][70]="5.956973900613066E+51";
+ results[59][71]="3.737705096108644E-10";
+ results[59][72]="1.451914815301539E+47";
+ results[59][73]="7.082544802045064E-15";
+ results[59][74]="4.055029284323338E+41";
+ results[60][0]="1.348437667255375E-14";
+ results[60][1]="2.965054092372860E-20";
+ results[60][2]="6.652623846164517E-25";
+ results[60][3]="7.757685013397121E-30";
+ results[60][4]="5.414617634246651E-35";
+ results[60][5]="1.689327108110964E-19";
+ results[60][6]="1.049839447984212E-10";
+ results[60][7]="1.620054160484525E-24";
+ results[60][8]="1.547661111428041E-16";
+ results[60][9]="1.510121982992930E-29";
+ results[60][10]="5.511285402205287E-21";
+ results[60][11]="1.829988405457360E-34";
+ results[60][12]="2.457176460742298E-26";
+ results[60][13]="2.302434853732143E-39";
+ results[60][14]="1.851327747515669E-31";
+ results[60][15]="1.988781940038362E-23";
+ results[60][16]="2.284713862551959E-7";
+ results[60][17]="2.353786922788046E-28";
+ results[60][18]="1.793071650950697E-12";
+ results[60][19]="1.517124726334002E-33";
+ results[60][20]="6.067895497169673E-17";
+ results[60][21]="2.828685044174972E-38";
+ results[60][22]="3.486004756618662E-22";
+ results[60][23]="3.100261352644838E-43";
+ results[60][24]="1.846494312475907E-27";
+ results[60][25]="1.848463735764689E-27";
+ results[60][26]="0.004951060261414672";
+ results[60][27]="2.154899926158156E-32";
+ results[60][28]="7.635646741444116E-8";
+ results[60][29]="3.678449292763319E-37";
+ results[60][30]="1.720862431732932E-13";
+ results[60][31]="4.488209789961917E-42";
+ results[60][32]="3.498603666092752E-18";
+ results[60][33]="1.931214516782934E-47";
+ results[60][34]="9.255755353824531E-23";
+ results[60][35]="2.272079981340803E-31";
+ results[60][36]="47.87683060222675";
+ results[60][37]="1.922358811568574E-36";
+ results[60][38]="0.0002343123221491472";
+ results[60][39]="2.048846777260200E-41";
+ results[60][40]="4.248288785737604E-9";
+ results[60][41]="3.280168751088831E-46";
+ results[60][42]="1.534215526112867E-14";
+ results[60][43]="5.917311795698881E-51";
+ results[60][44]="4.030262170254993E-19";
+ results[60][45]="5.190377588220942E-35";
+ results[60][46]="282594.7637793763";
+ results[60][47]="1.886835590161396E-40";
+ results[60][48]="2.340053519098534";
+ results[60][49]="7.990872946462834E-45";
+ results[60][50]="0.00007886318356258115";
+ results[60][51]="1.988996336942614E-50";
+ results[60][52]="1.413135928001109E-9";
+ results[60][53]="4.143090014694539E-55";
+ results[60][54]="5.762927809552455E-15";
+ results[60][55]="2.098349611355051E-39";
+ results[60][56]="2422221163.685803";
+ results[60][57]="2.104669434147318E-44";
+ results[60][58]="19360.50195272046";
+ results[60][59]="4.129684274053472E-49";
+ results[60][60]="1";
+ results[60][61]="1.909025720733676E-54";
+ results[60][62]="0.000007149418705177280";
+ results[60][63]="1.623697180745017E-59";
+ results[60][64]="7.470369768638670E-11";
+ results[60][65]="1.761657005552672E-43";
+ results[60][66]="15705362898567.62";
+ results[60][67]="5.686651461384062E-48";
+ results[60][68]="335051167.4433505";
+ results[60][69]="2.525741419852499E-53";
+ results[60][70]="2460.042143830875";
+ results[60][71]="1.543554195644939E-58";
+ results[60][72]="0.05995949780016016";
+ results[60][73]="2.924867388928466E-63";
+ results[60][74]="1.674599066629639E-7";
+ results[61][0]="7.063486115509977E+39";
+ results[61][1]="1.553176607402299E+34";
+ results[61][2]="3.484826722820572E+29";
+ results[61][3]="4.063688052571492E+24";
+ results[61][4]="2.836325134564299E+19";
+ results[61][5]="8.849158446444201E+34";
+ results[61][6]="5.499346795499110E+43";
+ results[61][7]="8.486287758668364E+29";
+ results[61][8]="8.107073124364424E+37";
+ results[61][9]="7.910432879932915E+24";
+ results[61][10]="2.886962361139478E+33";
+ results[61][11]="9.585980878005454E+19";
+ results[61][12]="1.287136382739755E+28";
+ results[61][13]="1206078487432465";
+ results[61][14]="9.697762200941783E+22";
+ results[61][15]="1.041778493835083E+31";
+ results[61][16]="1.196795746509847E+47";
+ results[61][17]="1.232978108793337E+26";
+ results[61][18]="9.392600798807385E+41";
+ results[61][19]="7.947115169045187E+20";
+ results[61][20]="3.178529985880788E+37";
+ results[61][21]="1.481742762003150E+16";
+ results[61][22]="1.826064844887958E+32";
+ results[61][23]="162400187644.0589";
+ results[61][24]="9.672443343331502E+26";
+ results[61][25]="9.682759722348257E+26";
+ results[61][26]="2.593501076303929E+51";
+ results[61][27]="1.128795648353017E+22";
+ results[61][28]="3.999761060584132E+46";
+ results[61][29]="1.926872567934611E+17";
+ results[61][30]="9.014349115587456E+40";
+ results[61][31]="2351047312362.565";
+ results[61][32]="1.832664499013753E+36";
+ results[61][33]="10116230.99578109";
+ results[61][34]="4.848418359846594E+31";
+ results[61][35]="1.190177773229581E+23";
+ results[61][36]="2.507919620057646E+55";
+ results[61][37]="1.006984238446915E+18";
+ results[61][38]="1.227392169756080E+50";
+ results[61][39]="10732421019831.98";
+ results[61][40]="2.225370113978822E+45";
+ results[61][41]="171824230.3109566";
+ results[61][42]="8.036641462972210E+39";
+ results[61][43]="3099.650115465570";
+ results[61][44]="2.111161796555619E+35";
+ results[61][45]="2.718862051908959E+19";
+ results[61][46]="1.480308833506809E+59";
+ results[61][47]="98837620136215.22";
+ results[61][48]="1.225784175500373E+54";
+ results[61][49]="4185838283.725054";
+ results[61][50]="4.131069723475097E+49";
+ results[61][51]="10418.90800810271";
+ results[61][52]="7.402393339457015E+44";
+ results[61][53]="0.2170264114148377";
+ results[61][54]="3.018779551769291E+39";
+ results[61][55]="1099173043382890";
+ results[61][56]="1.268825839997009E+63";
+ results[61][57]="11024835397.91414";
+ results[61][58]="1.014156160519400E+58";
+ results[61][59]="216324.1819741618";
+ results[61][60]="5.238274105681931E+53";
+ results[61][61]="1";
+ results[61][62]="3.745061487400818E+48";
+ results[61][63]="0.000008505370897365375";
+ results[61][64]="3.913184451892906E+43";
+ results[61][65]="92280422752.79732";
+ results[61][66]="8.226899579190449E+66";
+ results[61][67]="2978823.909820644";
+ results[61][68]="1.755089854497003E+62";
+ results[61][69]="13.23052587726166";
+ results[61][70]="1.288637506091553E+57";
+ results[61][71]="0.00008085559973763583";
+ results[61][72]="3.140842847162717E+52";
+ results[61][73]="1.532125710597750E-9";
+ results[61][74]="8.772008928125169E+46";
+ results[62][0]="1.886080145619249E-9";
+ results[62][1]="4.147265973142270E-15";
+ results[62][2]="9.305125522088941E-20";
+ results[62][3]="1.085079127870824E-24";
+ results[62][4]="7.573507522122931E-30";
+ results[62][5]="2.362887358782933E-14";
+ results[62][6]="0.00001468426303279687";
+ results[62][7]="2.265994239939194E-19";
+ results[62][8]="2.164736988067710E-11";
+ results[62][9]="2.112230441755173E-24";
+ results[62][10]="7.708718190213518E-16";
+ results[62][11]="2.559632441351024E-29";
+ results[62][12]="3.436889853664501E-21";
+ results[62][13]="3.220450429158424E-34";
+ results[62][14]="2.589480101613048E-26";
+ results[62][15]="2.781739358191706E-18";
+ results[62][16]="0.03195663810957770";
+ results[62][17]="3.292277344287504E-23";
+ results[62][18]="2.507996418858833E-7";
+ results[62][19]="2.122025284706531E-28";
+ results[62][20]="8.487257142703900E-12";
+ results[62][21]="3.956524524331703E-33";
+ results[62][22]="4.875927540926171E-17";
+ results[62][23]="4.336382411621481E-38";
+ results[62][24]="2.582719502969886E-22";
+ results[62][25]="2.585474165089977E-22";
+ results[62][26]="692.5122818487806";
+ results[62][27]="3.014091096102228E-27";
+ results[62][28]="0.01068009450322826";
+ results[62][29]="5.145102622258724E-32";
+ results[62][30]="2.406996292561188E-8";
+ results[62][31]="6.277726868495983E-37";
+ results[62][32]="4.893549826028827E-13";
+ results[62][33]="2.701218933204230E-42";
+ results[62][34]="1.294616490585723E-17";
+ results[62][35]="3.177992610357912E-26";
+ results[62][36]="6696604.657880305";
+ results[62][37]="2.688832324474842E-31";
+ results[62][38]="32.77361864111679";
+ results[62][39]="2.865752953840177E-36";
+ results[62][40]="0.0005942145733696068";
+ results[62][41]="4.588021608964494E-41";
+ results[62][42]="2.145930444669381E-9";
+ results[62][43]="8.276633443518753E-46";
+ results[62][44]="5.637188611343273E-14";
+ results[62][45]="7.259859580559060E-30";
+ results[62][46]="39526956726.52857";
+ results[62][47]="2.639145457790906E-35";
+ results[62][48]="327306.8224978871";
+ results[62][49]="1.117695476511428E-39";
+ results[62][50]="11.03071267954583";
+ results[62][51]="2.782039238382100E-45";
+ results[62][52]="0.0001976574580780646";
+ results[62][53]="5.795002622652810E-50";
+ results[62][54]="8.060694228719894E-10";
+ results[62][55]="2.934993316079701E-34";
+ results[62][56]="338799735135353.3";
+ results[62][57]="2.943832947737714E-39";
+ results[62][58]="2707982669.793906";
+ results[62][59]="5.776251810602371E-44";
+ results[62][60]="139871.5114105495";
+ results[62][61]="2.670183128806329E-49";
+ results[62][62]="1";
+ results[62][63]="2.271089787438537E-54";
+ results[62][64]="0.00001044891910335168";
+ results[62][65]="2.464056279536351E-38";
+ results[62][66]="2.196732845873822E+18";
+ results[62][67]="7.954005347687989E-43";
+ results[62][68]="46864113190170.53";
+ results[62][69]="3.532792698269964E-48";
+ results[62][70]="344089812.7912729";
+ results[62][71]="2.158992582889526E-53";
+ results[62][72]="8386.625580725921";
+ results[62][73]="4.091056223648521E-58";
+ results[62][74]="0.02342287024561831";
+ results[63][0]="8.304736149364119E+44";
+ results[63][1]="1.826112730584637E+39";
+ results[63][2]="4.097207241015242E+34";
+ results[63][3]="4.777790529781906E+29";
+ results[63][4]="3.334745972621699E+24";
+ results[63][5]="1.040420053778644E+40";
+ results[63][6]="6.465734254108293E+48";
+ results[63][7]="9.977563425596263E+34";
+ results[63][8]="9.531710283058522E+42";
+ results[63][9]="9.300514904509633E+29";
+ results[63][10]="3.394281561588036E+38";
+ results[63][11]="1.127050306645041E+25";
+ results[63][12]="1.513321874227095E+33";
+ results[63][13]="1.418019862962190E+20";
+ results[63][14]="1.140192746202962E+28";
+ results[63][15]="1.224847812524888E+36";
+ results[63][16]="1.407105887505231E+52";
+ results[63][17]="1.449646492400778E+31";
+ results[63][18]="1.104314075441065E+47";
+ results[63][19]="9.343643287216183E+25";
+ results[63][20]="3.737085688838532E+42";
+ results[63][21]="1.742125981198698E+21";
+ results[63][22]="2.146954985177189E+37";
+ results[63][23]="1.909383959897199E+16";
+ results[63][24]="1.137215938028950E+32";
+ results[63][25]="1.138428863266573E+32";
+ results[63][26]="3.049251005746606E+56";
+ results[63][27]="1.327156289801157E+27";
+ results[63][28]="4.702629795748353E+51";
+ results[63][29]="2.265477415607447E+22";
+ results[63][30]="1.059841978011769E+46";
+ results[63][31]="2.764191404152434E+17";
+ results[63][32]="2.154714381216979E+41";
+ results[63][33]="1189393280769.765";
+ results[63][34]="5.700419674053768E+36";
+ results[63][35]="1.399324953128441E+28";
+ results[63][36]="2.948630518669679E+60";
+ results[63][37]="1.183939243330163E+23";
+ results[63][38]="1.443078949251087E+55";
+ results[63][39]="1.261840447564310E+18";
+ results[63][40]="2.616429243159934E+50";
+ results[63][41]="20201850381878.22";
+ results[63][42]="9.448901829150850E+44";
+ results[63][43]="364434444.1728835";
+ results[63][44]="2.482151362981211E+40";
+ results[63][45]="3.196641374864857E+24";
+ results[63][46]="1.740440071773177E+64";
+ results[63][47]="1.162061259043167E+19";
+ results[63][48]="1.441188385893991E+59";
+ results[63][49]="492140593777240.2";
+ results[63][50]="4.857013025445766E+54";
+ results[63][51]="1224979854.944370";
+ results[63][52]="8.703198753801531E+49";
+ results[63][53]="25516.39593777902";
+ results[63][54]="3.549262681424497E+44";
+ results[63][55]="1.292328173158645E+20";
+ results[63][56]="1.491793662272907E+68";
+ results[63][57]="1296220415423529";
+ results[63][58]="1.192371470635743E+63";
+ results[63][59]="25433832878.60738";
+ results[63][60]="6.158783865974074E+58";
+ results[63][61]="117572.7680858409";
+ results[63][62]="4.403172457253908E+53";
+ results[63][63]="1";
+ results[63][64]="4.600839280395232E+48";
+ results[63][65]="1.084966474317800E+16";
+ results[63][66]="9.672593562896609E+71";
+ results[63][67]="350228572717.9005";
+ results[63][68]="2.063507724325885E+67";
+ results[63][69]="1555549.550621002";
+ results[63][70]="1.515086786504186E+62";
+ results[63][71]="9.506416676394638";
+ results[63][72]="3.692775876635344E+57";
+ results[63][73]="0.0001801362608504635";
+ results[63][74]="1.031349371353387E+52";
+ results[64][0]="0.0001805048088671923";
+ results[64][1]="3.969086115148465E-10";
+ results[64][2]="8.905347462307516E-15";
+ results[64][3]="1.038460645678428E-19";
+ results[64][4]="7.248125329722949E-25";
+ results[64][5]="2.261370133514570E-9";
+ results[64][6]="1.405337995973826";
+ results[64][7]="2.168639854061398E-14";
+ results[64][8]="0.000002071732938743234";
+ results[64][9]="2.021482242194446E-19";
+ results[64][10]="7.377526913516641E-11";
+ results[64][11]="2.449662415828232E-24";
+ results[64][12]="3.289230033910451E-16";
+ results[64][13]="3.082089541802851E-29";
+ results[64][14]="2.478227724801148E-21";
+ results[64][15]="2.662226906608371E-13";
+ results[64][16]="3058.367836279547";
+ results[64][17]="3.150830542109802E-18";
+ results[64][18]="0.02400244842602282";
+ results[64][19]="2.030856267253379E-23";
+ results[64][20]="8.122617333673738E-7";
+ results[64][21]="3.786539531215795E-28";
+ results[64][22]="4.666442043141217E-12";
+ results[64][23]="4.150077504409531E-33";
+ results[64][24]="2.471757583175691E-17";
+ results[64][25]="2.474393896169260E-17";
+ results[64][26]="66275973.14124528";
+ results[64][27]="2.884596068061627E-22";
+ results[64][28]="1022.124336267703";
+ results[64][29]="4.924052498988474E-27";
+ results[64][30]="0.002303584005917990";
+ results[64][31]="6.008015572139217E-32";
+ results[64][32]="4.683307218312307E-8";
+ results[64][33]="2.585165897530746E-37";
+ results[64][34]="1.238995610723459E-12";
+ results[64][35]="3.041455847178024E-21";
+ results[64][36]="640889702718.8438";
+ results[64][37]="2.573311457270591E-26";
+ results[64][38]="3136555.878837656";
+ results[64][39]="2.742631008523106E-31";
+ results[64][40]="56.86852080029998";
+ results[64][41]="4.390905474129667E-36";
+ results[64][42]="0.0002053734384814057";
+ results[64][43]="7.921042704660115E-41";
+ results[64][44]="5.394996894497005E-9";
+ results[64][45]="6.947952710467755E-25";
+ results[64][46]="3782875179294822";
+ results[64][47]="2.525759297863022E-30";
+ results[64][48]="31324467082.23605";
+ results[64][49]="1.069675691290314E-34";
+ results[64][50]="1055679.785673480";
+ results[64][51]="2.662513902983238E-40";
+ results[64][52]="18.91654592432077";
+ results[64][53]="5.546030709333330E-45";
+ results[64][54]="0.00007714380931645150";
+ results[64][55]="2.808896582554887E-29";
+ results[64][56]="3.242438110432659E+19";
+ results[64][57]="2.817356435263650E-34";
+ results[64][58]="259163904228646.2";
+ results[64][59]="5.528085492354452E-39";
+ results[64][60]="13386218232.43738";
+ results[64][61]="2.555463490907705E-44";
+ results[64][62]="95703.67902257296";
+ results[64][63]="2.173516480484612E-49";
+ results[64][64]="1";
+ results[64][65]="2.358192512703023E-33";
+ results[64][66]="2.102354151798515E+23";
+ results[64][67]="7.612275747389602E-38";
+ results[64][68]="4.485068046429608E+18";
+ results[64][69]="3.381012584485181E-43";
+ results[64][70]="32930660998313.20";
+ results[64][71]="2.066235331649750E-48";
+ results[64][72]="802630922.6602931";
+ results[64][73]="3.915291316913575E-53";
+ results[64][74]="2241.654855774030";
+ results[65][0]="7.654371214175933E+28";
+ results[65][1]="1.683105214594628E+23";
+ results[65][2]="3.776344558103940E+18";
+ results[65][3]="44036296446727.19";
+ results[65][4]="307359356.4002524";
+ results[65][5]="9.589421225506852E+23";
+ results[65][6]="5.959386218061519E+32";
+ results[65][7]="9.196195146831527E+18";
+ results[65][8]="8.785257893845823E+26";
+ results[65][9]="85721680113273.25";
+ results[65][10]="3.128466770111285E+22";
+ results[65][11]="1038788140.761402";
+ results[65][12]="1.394809802928366E+17";
+ results[65][13]="13069.71133696832";
+ results[65][14]="1050901362569.648";
+ results[65][15]="1.128926876100059E+20";
+ results[65][16]="1.296911859318036E+36";
+ results[65][17]="1336121001630285";
+ results[65][18]="1.017832441445189E+31";
+ results[65][19]="8611918901.080548";
+ results[65][20]="3.444425037361932E+26";
+ results[65][21]="160569.5680407179";
+ results[65][22]="1.978821499094838E+21";
+ results[65][23]="1.759855262899042";
+ results[65][24]="1.048157675788096E+16";
+ results[65][25]="1.049275613776351E+16";
+ results[65][26]="2.810456431535270E+40";
+ results[65][27]="122322331723.2581";
+ results[65][28]="4.334354938206963E+35";
+ results[65][29]="2088062.137617592";
+ results[65][30]="9.768430666746378E+29";
+ results[65][31]="25.47720569790407";
+ results[65][32]="1.985973237165517E+25";
+ results[65][33]="0.0001096248878581826";
+ results[65][34]="5.254005362366659E+20";
+ results[65][35]="1289740269632.112";
+ results[65][36]="2.717715789811575E+44";
+ results[65][37]="10912219.60636705";
+ results[65][38]="1.330067779429277E+39";
+ results[65][39]="116.3022524136263";
+ results[65][40]="2.411530038110238E+34";
+ results[65][41]="0.001861979227937033";
+ results[65][42]="8.708934379831493E+28";
+ results[65][43]="3.358946592354670E-8";
+ results[65][44]="2.287767799039069E+24";
+ results[65][45]="294630428.7305122";
+ results[65][46]="1.604141798821501E+48";
+ results[65][47]="1071.057296746282";
+ results[65][48]="1.328325270880074E+43";
+ results[65][49]="0.04535998166087906";
+ results[65][50]="4.476648025921479E+38";
+ results[65][51]="1.129048577943026E-7";
+ results[65][52]="8.021629202205431E+33";
+ results[65][53]="2.351814230372703E-12";
+ results[65][54]="3.271310925672783E+28";
+ results[65][55]="11911.22678671919";
+ results[65][56]="1.374967519812914E+52";
+ results[65][57]="0.1194710109580630";
+ results[65][58]="1.098993838851543E+47";
+ results[65][59]="0.000002344204496696504";
+ results[65][60]="5.676473892750065E+42";
+ results[65][61]="1.083653466433309E-11";
+ results[65][62]="4.058348862827780E+37";
+ results[65][63]="9.216874656230971E-17";
+ results[65][64]="4.240535896086675E+32";
+ results[65][65]="1";
+ results[65][66]="8.915108246988459E+55";
+ results[65][67]="0.00003228012855771563";
+ results[65][68]="1.901909204727609E+51";
+ results[65][69]="1.433730522963019E-10";
+ results[65][70]="1.396436500452086E+46";
+ results[65][71]="8.761945093623320E-16";
+ results[65][72]="3.403585238850141E+41";
+ results[65][73]="1.660293337300849E-20";
+ results[65][74]="9.505817882546773E+35";
+ results[66][0]="8.585842148087876E-28";
+ results[66][1]="1.887924597172652E-33";
+ results[66][2]="4.235893108061360E-38";
+ results[66][3]="4.939513377372926E-43";
+ results[66][4]="3.447623381399535E-48";
+ results[66][5]="1.075637104994903E-32";
+ results[66][6]="6.684592102484691E-24";
+ results[66][7]="1.031529275030174E-37";
+ results[66][8]="9.854347979244672E-30";
+ results[66][9]="9.615326896589304E-43";
+ results[66][10]="3.509174183238983E-34";
+ results[66][11]="1.165199694700630E-47";
+ results[66][12]="1.564546121354764E-39";
+ results[66][13]="1.466018243960560E-52";
+ results[66][14]="1.178786991088576E-44";
+ results[66][15]="1.266307536401941E-36";
+ results[66][16]="1.454734842682516E-20";
+ results[66][17]="1.498715399312880E-41";
+ results[66][18]="1.141693867585976E-25";
+ results[66][19]="9.659915126649943E-47";
+ results[66][20]="3.863581845487368E-30";
+ results[66][21]="1.801094990573543E-51";
+ results[66][22]="2.219627002020180E-35";
+ results[66][23]="1.974014464146888E-56";
+ results[66][24]="1.175709421298576E-40";
+ results[66][25]="1.176963402694295E-40";
+ results[66][26]="3.152464730290456E-16";
+ results[66][27]="1.372079040819037E-45";
+ results[66][28]="4.861808536840948E-21";
+ results[66][29]="2.342161283709532E-50";
+ results[66][30]="1.095716439567200E-26";
+ results[66][31]="2.857756181088471E-55";
+ results[66][32]="2.227649044907988E-31";
+ results[66][33]="1.229652908535508E-60";
+ results[66][34]="5.893372482764269E-36";
+ results[66][35]="1.446690532409171E-44";
+ results[66][36]="3.048438352646615E-12";
+ results[66][37]="1.224014258049331E-49";
+ results[66][38]="1.491925552197951E-17";
+ results[66][39]="1.304552330622721E-54";
+ results[66][40]="2.704992436771430E-22";
+ results[66][41]="2.088566034591912E-59";
+ results[66][42]="9.768736552103434E-28";
+ results[66][43]="3.767701411241225E-64";
+ results[66][44]="2.566169401041071E-32";
+ results[66][45]="3.304844097995546E-48";
+ results[66][46]="1.799352015005968E-8";
+ results[66][47]="1.201395728546636E-53";
+ results[66][48]="1.489970995392888E-13";
+ results[66][49]="5.087990005752511E-58";
+ results[66][50]="5.021417465608115E-18";
+ results[66][51]="1.266444048309139E-63";
+ results[66][52]="8.997792264513616E-23";
+ results[66][53]="2.638009730467547E-68";
+ results[66][54]="3.669401240055428E-28";
+ results[66][55]="1.336072031513787E-52";
+ results[66][56]="0.0001542289203585813";
+ results[66][57]="1.340096021811295E-57";
+ results[66][58]="1.232731906786197E-9";
+ results[66][59]="2.629473957860669E-62";
+ results[66][60]="6.367251788185060E-14";
+ results[66][61]="1.215524743403277E-67";
+ results[66][62]="4.552214903502375E-19";
+ results[66][63]="1.033848877756975E-72";
+ results[66][64]="4.756572526776819E-24";
+ results[66][65]="1.121691371877399E-56";
+ results[66][66]="1";
+ results[66][67]="3.620834168628286E-61";
+ results[66][68]="0.00002133355145037165";
+ results[66][69]="1.608203157204890E-66";
+ results[66][70]="1.566370773931775E-10";
+ results[66][71]="9.828198212380789E-72";
+ results[66][72]="3.817772195867480E-15";
+ results[66][73]="1.862336711235894E-76";
+ results[66][74]="1.066259390149060E-20";
+ results[67][0]="2.371233187776874E+33";
+ results[67][1]="5.214059825026099E+27";
+ results[67][2]="1.169866641439169E+23";
+ results[67][3]="1.364192102518798E+18";
+ results[67][4]="9521627395340.313";
+ results[67][5]="2.970688672556348E+28";
+ results[67][6]="1.846146990216091E+37";
+ results[67][7]="2.848871909041218E+23";
+ results[67][8]="2.721568434319621E+31";
+ results[67][9]="2.655555722462696E+18";
+ results[67][10]="9.691618063161386E+26";
+ results[67][11]="32180421428746.45";
+ results[67][12]="4.320954919477782E+21";
+ results[67][13]="404884116.6663938";
+ results[67][14]="3.255567463712780E+16";
+ results[67][15]="3.497281226998773E+24";
+ results[67][16]="4.017678730737416E+40";
+ results[67][17]="4.139143991453913E+19";
+ results[67][18]="3.153123878132466E+35";
+ results[67][19]="266787007544990.6";
+ results[67][20]="1.067041920605562E+31";
+ results[67][21]="4974254292.501521";
+ results[67][22]="6.130153712234388E+25";
+ results[67][23]="54518.22348701272";
+ results[67][24]="3.247067848301876E+20";
+ results[67][25]="3.250531087260965E+20";
+ results[67][26]="8.706459847302905E+44";
+ results[67][27]="3789400389299890";
+ results[67][28]="1.342731622167273E+40";
+ results[67][29]="64685682211.09210";
+ results[67][30]="3.026143668938864E+34";
+ results[67][31]="789253.5388250330";
+ results[67][32]="6.152308946399247E+29";
+ results[67][33]="3.396048676267737";
+ results[67][34]="1.627628388459699E+25";
+ results[67][35]="3.995461998628989E+16";
+ results[67][36]="8.419160366577858E+48";
+ results[67][37]="338047588219.9918";
+ results[67][38]="4.120391828834159E+43";
+ results[67][39]="3602905.490468613";
+ results[67][40]="7.470633314853486E+38";
+ results[67][41]="57.68190249329044";
+ results[67][42]="2.697924317203462E+33";
+ results[67][43]="0.001040561714724588";
+ results[67][44]="7.087232614171990E+28";
+ results[67][45]="9127300351475.501";
+ results[67][46]="4.969440552113530E+52";
+ results[67][47]="33180081.51148695";
+ results[67][48]="4.114993744541877E+47";
+ results[67][49]="1405.198296524041";
+ results[67][50]="1.386812328803897E+43";
+ results[67][51]="0.003497658244837316";
+ results[67][52]="2.485005345583759E+38";
+ results[67][53]="7.285640842996488E-8";
+ results[67][54]="1.013413227219280E+33";
+ results[67][55]="368995642.7968486";
+ results[67][56]="4.259485885734702E+56";
+ results[67][57]="3701.069862359855";
+ results[67][58]="3.404552236793557E+51";
+ results[67][59]="0.07262066792903739";
+ results[67][60]="1.758504115806338E+47";
+ results[67][61]="3.357029587090330E-7";
+ results[67][62]="1.257228221867707E+42";
+ results[67][63]="2.855278175163260E-12";
+ results[67][64]="1.313667598474634E+37";
+ results[67][65]="30978.81094903443";
+ results[67][66]="2.761794529736332E+60";
+ results[67][67]="1";
+ results[67][68]="5.891888569548503E+55";
+ results[67][69]="0.000004441526682273164";
+ results[67][70]="4.325994234983640E+50";
+ results[67][71]="2.714346406011766E-11";
+ results[67][72]="1.054390236632627E+46";
+ results[67][73]="5.143391341618445E-16";
+ results[67][74]="2.944789350993672E+40";
+ results[68][0]="4.024572358737908E-23";
+ results[68][1]="8.849556069295544E-29";
+ results[68][2]="1.985554593624666E-33";
+ results[68][3]="2.315373222720905E-38";
+ results[68][4]="1.616056937083241E-43";
+ results[68][5]="5.041997379091630E-28";
+ results[68][6]="3.133370511719575E-19";
+ results[68][7]="4.835244040026928E-33";
+ results[68][8]="4.619178387700187E-25";
+ results[68][9]="4.507138400728770E-38";
+ results[68][10]="1.644908580459467E-29";
+ results[68][11]="5.461817725994849E-43";
+ results[68][12]="7.333734962012186E-35";
+ results[68][13]="6.871890258736175E-48";
+ results[68][14]="5.525507526633783E-40";
+ results[68][15]="5.935755888314043E-32";
+ results[68][16]="6.818999856009313E-16";
+ results[68][17]="7.025156607418828E-37";
+ results[68][18]="5.351635287926178E-21";
+ results[68][19]="4.528038919877851E-42";
+ results[68][20]="1.811035473617807E-25";
+ results[68][21]="8.442546449724692E-47";
+ results[68][22]="1.040439519497590E-30";
+ results[68][23]="9.253098194827277E-52";
+ results[68][24]="5.511081565737588E-36";
+ results[68][25]="5.516959543432190E-36";
+ results[68][26]="1.477702733941909E-11";
+ results[68][27]="6.431554746104564E-41";
+ results[68][28]="2.278949451126784E-16";
+ results[68][29]="1.097876876786368E-45";
+ results[68][30]="5.136118297584773E-22";
+ results[68][31]="1.339559513912385E-50";
+ results[68][32]="1.044199813655115E-26";
+ results[68][33]="5.763939076885797E-56";
+ results[68][34]="2.762490106944477E-31";
+ results[68][35]="6.781292537131541E-40";
+ results[68][36]="1.428940867974192E-7";
+ results[68][37]="5.737508172967645E-45";
+ results[68][38]="6.993329524475215E-13";
+ results[68][39]="6.115026528318585E-50";
+ results[68][40]="1.267952240893443E-17";
+ results[68][41]="9.790053191333628E-55";
+ results[68][42]="4.579048441525779E-23";
+ results[68][43]="1.766091979577825E-59";
+ results[68][44]="1.202879608212802E-27";
+ results[68][45]="1.549129832266147E-43";
+ results[68][46]="0.0008434376335284867";
+ results[68][47]="5.631484899930744E-49";
+ results[68][48]="6.984167633124823E-9";
+ results[68][49]="2.384970930690432E-53";
+ results[68][50]="2.353765371550753E-13";
+ results[68][51]="5.936395781336616E-59";
+ results[68][52]="4.217672001516121E-18";
+ results[68][53]="1.236554418332251E-63";
+ results[68][54]="1.720014245444119E-23";
+ results[68][55]="6.262773615644344E-48";
+ results[68][56]="7.229406726646745";
+ results[68][57]="6.281635877311693E-53";
+ results[68][58]="0.00005778371733623009";
+ results[68][59]="1.232553315830994E-57";
+ results[68][60]="2.984618760264661E-9";
+ results[68][61]="5.697713979929495E-63";
+ results[68][62]="2.133828919245919E-14";
+ results[68][63]="4.846117066640417E-68";
+ results[68][64]="2.229620575759295E-19";
+ results[68][65]="5.257874547924172E-52";
+ results[68][66]="46874.52074382950";
+ results[68][67]="1.697248663473332E-56";
+ results[68][68]="1";
+ results[68][69]="7.538375225269271E-62";
+ results[68][70]="0.000007342287933519324";
+ results[68][71]="4.606920809807113E-67";
+ results[68][72]="1.789562419904057E-10";
+ results[68][73]="8.729614080282214E-72";
+ results[68][74]="4.998039790184512E-16";
+ results[69][0]="5.338779562533849E+38";
+ results[69][1]="1.173934144274364E+33";
+ results[69][2]="2.633929108448886E+28";
+ results[69][3]="3.071448625904928E+23";
+ results[69][4]="2.143773543755267E+18";
+ results[69][5]="6.688440450921611E+33";
+ results[69][6]="4.156559494698874E+42";
+ results[69][7]="6.414172677182188E+28";
+ results[69][8]="6.127551693389194E+36";
+ results[69][9]="5.978925519149620E+23";
+ results[69][10]="2.182046570122424E+32";
+ results[69][11]="7.245351369200056E+18";
+ results[69][12]="9.728535318099962E+26";
+ results[69][13]="91158771663435.09";
+ results[69][14]="7.329838806791966E+21";
+ results[69][15]="7.874052048267494E+29";
+ results[69][16]="9.045715624703119E+45";
+ results[69][17]="9.319191997593739E+24";
+ results[69][18]="7.099189318657215E+40";
+ results[69][19]="6.006651015061551E+19";
+ results[69][20]="2.402421502642987E+36";
+ results[69][21]="1119942454101324";
+ results[69][22]="1.380190675584772E+31";
+ results[69][23]="12274658554.81710";
+ results[69][24]="7.310702108942491E+25";
+ results[69][25]="7.318499515570511E+25";
+ results[69][26]="1.960240356553922E+50";
+ results[69][27]="8.531751941115174E+20";
+ results[69][28]="3.023130824647137E+45";
+ results[69][29]="1.456383960705739E+16";
+ results[69][30]="6.813296160116931E+39";
+ results[69][31]="177698704811.3589";
+ results[69][32]="1.385178878009241E+35";
+ results[69][33]="764612.9178559042";
+ results[69][34]="3.664569651142300E+30";
+ results[69][35]="8.995695139186061E+21";
+ results[69][36]="1.895555508014859E+54";
+ results[69][37]="7.611067373954845E+16";
+ results[69][38]="9.276971914362904E+48";
+ results[69][39]="811186276297.3776";
+ results[69][40]="1.681996720782961E+44";
+ results[69][41]="12986953.95065576";
+ results[69][42]="6.074317481804861E+38";
+ results[69][43]="234.2801899350586";
+ results[69][44]="1.595674893152901E+34";
+ results[69][45]="2.054991673899878E+18";
+ results[69][46]="1.118858651001097E+58";
+ results[69][47]="7470422646319.768";
+ results[69][48]="9.264818245864578E+52";
+ results[69][49]="316377317.3157802";
+ results[69][50]="3.122377569719179E+48";
+ results[69][51]="787.4900895669555";
+ results[69][52]="5.594935082798914E+43";
+ results[69][53]="0.01640346071109881";
+ results[69][54]="2.281677674624746E+38";
+ results[69][55]="83078560412474.54";
+ results[69][56]="9.590139135570173E+61";
+ results[69][57]="833287769.5256027";
+ results[69][58]="7.665274758748302E+56";
+ results[69][59]="16350.38425388234";
+ results[69][60]="3.959233483443444E+52";
+ results[69][61]="0.07558278554283523";
+ results[69][62]="2.830621792469476E+47";
+ results[69][63]="6.428596244978392E-7";
+ results[69][64]="2.957693812169788E+42";
+ results[69][65]="6974811402.726853";
+ results[69][66]="6.218119865763931E+65";
+ results[69][67]="225147.8087458437";
+ results[69][68]="1.326545800808529E+61";
+ results[69][69]="1";
+ results[69][70]="9.739881226537191E+55";
+ results[69][71]="0.000006111291454907054";
+ results[69][72]="2.373936513408476E+51";
+ results[69][73]="1.158023290087738E-10";
+ results[69][74]="6.630128695943206E+45";
+ results[70][0]="5.481360027253576E-18";
+ results[70][1]="1.205285893092693E-23";
+ results[70][2]="2.704272308036475E-28";
+ results[70][3]="3.153476469031765E-33";
+ results[70][4]="2.201026371773776E-38";
+ results[70][5]="6.867065722216763E-23";
+ results[70][6]="4.267566922042078E-14";
+ results[70][7]="6.585473198283149E-28";
+ results[70][8]="6.291197552485674E-20";
+ results[70][9]="6.138602083626537E-33";
+ results[70][10]="2.240321539216762E-24";
+ results[70][11]="7.438849818270307E-38";
+ results[70][12]="9.988351081318820E-30";
+ results[70][13]="9.359330934659115E-43";
+ results[70][14]="7.525593625126715E-35";
+ results[70][15]="8.084340933043336E-27";
+ results[70][16]="9.287295619229160E-11";
+ results[70][17]="9.568075606715566E-32";
+ results[70][18]="7.288784281388184E-16";
+ results[70][19]="6.167068032304013E-37";
+ results[70][20]="2.466581929251223E-20";
+ results[70][21]="1.149852270323317E-41";
+ results[70][22]="1.417050827913914E-25";
+ results[70][23]="1.260247252438118E-46";
+ results[70][24]="7.505945851807534E-31";
+ results[70][25]="7.513951500384414E-31";
+ results[70][26]="0.000002012591643533670";
+ results[70][27]="8.759605730991504E-36";
+ results[70][28]="3.103868265262150E-11";
+ results[70][29]="1.495278973975256E-40";
+ results[70][30]="6.995255898556019E-17";
+ results[70][31]="1.824444268654967E-45";
+ results[70][32]="1.422172248091892E-21";
+ results[70][33]="7.850331026344006E-51";
+ results[70][34]="3.762437719628292E-26";
+ results[70][35]="9.235939258352015E-35";
+ results[70][36]="0.01946179284866684";
+ results[70][37]="7.814332841367511E-40";
+ results[70][38]="9.524727970077244E-8";
+ results[70][39]="8.328502755118070E-45";
+ results[70][40]="1.726917075949764E-12";
+ results[70][41]="1.333379088368309E-49";
+ results[70][42]="6.236541637956356E-18";
+ results[70][43]="2.405370091133565E-54";
+ results[70][44]="1.638289888797966E-22";
+ results[70][45]="2.109873443118451E-38";
+ results[70][46]="114.8739522564880";
+ results[70][47]="7.669931976137371E-44";
+ results[70][48]="0.0009512249718838192";
+ results[70][49]="3.248266687829637E-48";
+ results[70][50]="3.205765550006891E-8";
+ results[70][51]="8.085212450243923E-54";
+ results[70][52]="5.744356581633671E-13";
+ results[70][53]="1.684154080483660E-58";
+ results[70][54]="2.342613448311986E-18";
+ results[70][55]="8.529730340665701E-43";
+ results[70][56]="984625.8812110530";
+ results[70][57]="8.555420237109612E-48";
+ results[70][58]="7.869987919219759";
+ results[70][59]="1.678704685775246E-52";
+ results[70][60]="0.0004064971010792362";
+ results[70][61]="7.760134213639389E-58";
+ results[70][62]="2.906217978056231E-9";
+ results[70][63]="6.600281970033780E-63";
+ results[70][64]="3.036683654941584E-14";
+ results[70][65]="7.161084658530892E-47";
+ results[70][66]="6384184489.665129";
+ results[70][67]="2.311607333900624E-51";
+ results[70][68]="136197.3282789357";
+ results[70][69]="1.026706565245795E-56";
+ results[70][70]="1";
+ results[70][71]="6.274503058883598E-62";
+ results[70][72]="0.00002437336203793195";
+ results[70][73]="1.188950114640616E-66";
+ results[70][74]="6.807196660549431E-11";
+ results[71][0]="8.735926934473208E+43";
+ results[71][1]="1.920926457094031E+38";
+ results[71][2]="4.309938624075892E+33";
+ results[71][3]="5.025858525269176E+28";
+ results[71][4]="3.507889550962140E+23";
+ results[71][5]="1.094439775990578E+39";
+ results[71][6]="6.801442093489699E+47";
+ results[71][7]="1.049560919244317E+34";
+ results[71][8]="1.002660687778045E+42";
+ results[71][9]="9.783407587849290E+28";
+ results[71][10]="3.570516291397545E+37";
+ results[71][11]="1.185567964261042E+24";
+ results[71][12]="1.591895164857249E+32";
+ results[71][13]="1.491644971215360E+19";
+ results[71][14]="1.199392773340319E+27";
+ results[71][15]="1.288443221267910E+35";
+ results[71][16]="1.480164330477132E+51";
+ results[71][17]="1.524913689087910E+30";
+ results[71][18]="1.161651243610208E+46";
+ results[71][19]="9.828775242323811E+24";
+ results[71][20]="3.931119175659616E+41";
+ results[71][21]="1.832579025832696E+20";
+ results[71][22]="2.258427184775404E+36";
+ results[71][23]="2008521217714331";
+ results[71][24]="1.196261406101385E+31";
+ results[71][25]="1.197537307714907E+31";
+ results[71][26]="3.207571379990312E+55";
+ results[71][27]="1.396063664131845E+26";
+ results[71][28]="4.946795365519211E+50";
+ results[71][29]="2.383103426586433E+21";
+ results[71][30]="1.114870107307058E+45";
+ results[71][31]="2.907711178930534E+16";
+ results[71][32]="2.266589456958420E+40";
+ results[71][33]="125114785229.5539";
+ results[71][34]="5.996391561721113E+35";
+ results[71][35]="1.471979401663617E+27";
+ results[71][36]="3.101726569582645E+59";
+ results[71][37]="1.245410635397457E+22";
+ results[71][38]="1.518005152072067E+54";
+ results[71][39]="1.327356553492530E+17";
+ results[71][40]="2.752277048466415E+49";
+ results[71][41]="2125075206522.494";
+ results[71][42]="9.939498920359126E+43";
+ results[71][43]="38335627.03787325";
+ results[71][44]="2.611027317101128E+39";
+ results[71][45]="3.362614414748335E+23";
+ results[71][46]="1.830805582186251E+63";
+ results[71][47]="1.222396722761668E+18";
+ results[71][48]="1.516016428642984E+58";
+ results[71][49]="51769305988793.17";
+ results[71][50]="5.109194337658483E+53";
+ results[71][51]="128858211.9471067";
+ results[71][52]="9.155078143600022E+48";
+ results[71][53]="2684.123451177847";
+ results[71][54]="3.733544196771496E+43";
+ results[71][55]="1.359427234414859E+19";
+ results[71][56]="1.569249185107967E+67";
+ results[71][57]="136352156606197.4";
+ results[71][58]="1.254280672965365E+62";
+ results[71][59]="2675438469.025040";
+ results[71][60]="6.478554512834406E+57";
+ results[71][61]="12367.72719817611";
+ results[71][62]="4.631789881656898E+52";
+ results[71][63]="0.1051921069779213";
+ results[71][64]="4.839719777715578E+47";
+ results[71][65]="1141299094338961";
+ results[71][66]="1.017480496822173E+71";
+ results[71][67]="36841281488.06609";
+ results[71][68]="2.170647252870554E+66";
+ results[71][69]="163631.5347383819";
+ results[71][70]="1.593751713267834E+61";
+ results[71][71]="1";
+ results[71][72]="3.884508750605123E+56";
+ results[71][73]="0.00001894891282198470";
+ results[71][74]="1.084898134030173E+51";
+ results[72][0]="2.248914211639332E-13";
+ results[72][1]="4.945094941013564E-19";
+ results[72][2]="1.109519607441867E-23";
+ results[72][3]="1.293820878762663E-28";
+ results[72][4]="9.030458614401850E-34";
+ results[72][5]="2.817447060249479E-18";
+ results[72][6]="1.750914344685201E-9";
+ results[72][7]="2.701914158594232E-23";
+ results[72][8]="2.581177575212958E-15";
+ results[72][9]="2.518570098812429E-28";
+ results[72][10]="9.191680391610227E-20";
+ results[72][11]="3.052040915280100E-33";
+ results[72][12]="4.098060442286985E-25";
+ results[72][13]="3.839983552574039E-38";
+ results[72][14]="3.087630509658344E-30";
+ results[72][15]="3.316875579356586E-22";
+ results[72][16]="0.000003810428616608354";
+ results[72][17]="3.925628147575576E-27";
+ results[72][18]="2.990471429442005E-11";
+ results[72][19]="2.530249221550267E-32";
+ results[72][20]="1.011999052659421E-15";
+ results[72][21]="4.717659666868350E-37";
+ results[72][22]="5.813932545327873E-21";
+ results[72][23]="5.170592593983595E-42";
+ results[72][24]="3.079569343009031E-26";
+ results[72][25]="3.082853932375250E-26";
+ results[72][26]="0.08257341110354408";
+ results[72][27]="3.593925908686312E-31";
+ results[72][28]="0.000001273467427444617";
+ results[72][29]="6.134890097017279E-36";
+ results[72][30]="2.870041436084768E-12";
+ results[72][31]="7.485402571116811E-41";
+ results[72][32]="5.834944911902525E-17";
+ results[72][33]="3.220865063312414E-46";
+ results[72][34]="1.543667924750332E-21";
+ results[72][35]="3.789357924433339E-30";
+ results[72][36]="798.4861841537783";
+ results[72][37]="3.206095584682231E-35";
+ results[72][38]="0.003907843306661606";
+ results[72][39]="3.417051263652724E-40";
+ results[72][40]="7.085264122619546E-8";
+ results[72][41]="5.470640801598023E-45";
+ results[72][42]="2.558753129030992E-13";
+ results[72][43]="9.868848160504565E-50";
+ results[72][44]="6.721640971189435E-18";
+ results[72][45]="8.656472750188841E-34";
+ results[72][46]="4713094.241069868";
+ results[72][47]="3.146850222878877E-39";
+ results[72][48]="39.02723680071055";
+ results[72][49]="1.332711787062614E-43";
+ results[72][50]="0.001315274251052358";
+ results[72][51]="3.317233148902893E-49";
+ results[72][52]="2.356817484881160E-8";
+ results[72][53]="6.909814402554038E-54";
+ results[72][54]="9.611367708181607E-14";
+ results[72][55]="3.499611718478145E-38";
+ results[72][56]="40397622604.49307";
+ results[72][57]="3.510151871454961E-43";
+ results[72][58]="322892.9971569699";
+ results[72][59]="6.887456409020225E-48";
+ results[72][60]="16.67792487743833";
+ results[72][61]="3.183858755949381E-53";
+ results[72][62]="0.0001192374680822991";
+ results[72][63]="2.707989960417380E-58";
+ results[72][64]="1.245902658080421E-9";
+ results[72][65]="2.938078319842043E-42";
+ results[72][66]="261932862595217.9";
+ results[72][67]="9.484154587713828E-47";
+ results[72][68]="5587958200.718210";
+ results[72][69]="4.212412566013441E-52";
+ results[72][70]="41028.39807014366";
+ results[72][71]="2.574328091922103E-57";
+ results[72][72]="1";
+ results[72][73]="4.878071858901815E-62";
+ results[72][74]="0.000002792883743307747";
+ results[73][0]="4.610252322411714E+48";
+ results[73][1]="1.013739666829516E+43";
+ results[73][2]="2.274504434405050E+38";
+ results[73][3]="2.652320253137757E+33";
+ results[73][4]="1.851235257619769E+28";
+ results[73][5]="5.775739148057081E+43";
+ results[73][6]="3.589357425085942E+52";
+ results[73][7]="5.538897820177879E+38";
+ results[73][8]="5.291388995229049E+46";
+ results[73][9]="5.163044275816442E+33";
+ results[73][10]="1.884285565584005E+42";
+ results[73][11]="6.256654275624378E+28";
+ results[73][12]="8.400984161003253E+36";
+ results[73][13]="7.871929040091104E+23";
+ results[73][14]="6.329612598928488E+31";
+ results[73][15]="6.799562768440446E+39";
+ results[73][16]="7.811341708004652E+55";
+ results[73][17]="8.047499629206652E+34";
+ results[73][18]="6.130437426797644E+50";
+ results[73][19]="5.186986364157197E+29";
+ results[73][20]="2.074588242919507E+46";
+ results[73][21]="9.671156562114322E+24";
+ results[73][22]="1.191850533058106E+41";
+ results[73][23]="1.059966466985920E+20";
+ results[73][24]="6.313087285479891E+35";
+ results[73][25]="6.319820661824533E+35";
+ results[73][26]="1.692746919110240E+60";
+ results[73][27]="7.367513256550102E+30";
+ results[73][28]="2.610595875336918E+55";
+ results[73][29]="1.257646519868694E+26";
+ results[73][30]="5.883557108424581E+49";
+ results[73][31]="1.534500267243291E+21";
+ results[73][32]="1.196158047826734E+45";
+ results[73][33]="6602742141723014";
+ results[73][34]="3.164504274231525E+40";
+ results[73][35]="7.768146993403301E+31";
+ results[73][36]="1.636888933271145E+64";
+ results[73][37]="6.572464853775255E+26";
+ results[73][38]="8.011040877822095E+58";
+ results[73][39]="7.004921949677867E+21";
+ results[73][40]="1.452472273381932E+54";
+ results[73][41]="1.121476058540394E+17";
+ results[73][42]="5.245419098043044E+48";
+ results[73][43]="2023104301445.511";
+ results[73][44]="1.377929880004403E+44";
+ results[73][45]="1.774568518172187E+28";
+ results[73][46]="9.661797483505934E+67";
+ results[73][47]="6.451012436678859E+22";
+ results[73][48]="8.000545692964971E+62";
+ results[73][49]="2.732046237963053E+18";
+ results[73][50]="2.696299458262718E+58";
+ results[73][51]="6800295782542.430";
+ results[73][52]="4.831452986040559E+53";
+ results[73][53]="141650525.0931179";
+ results[73][54]="1.970321058440780E+48";
+ results[73][55]="7.174170081344397E+23";
+ results[73][56]="8.281473453650119E+71";
+ results[73][57]="7.195777292721534E+18";
+ results[73][58]="6.619275125431665E+66";
+ results[73][59]="141192188394099.9";
+ results[73][60]="3.418958424526566E+62";
+ results[73][61]="652687957.0540302";
+ results[73][62]="2.444356531253368E+57";
+ results[73][63]="5551.353154988210";
+ results[73][64]="2.554088365481576E+52";
+ results[73][65]="6.023032060260553E+19";
+ results[73][66]="5.369598279230475E+75";
+ results[73][67]="1944242492124535";
+ results[73][68]="1.145526011577904E+71";
+ results[73][69]="8635404905.580393";
+ results[73][70]="8.410781812340964E+65";
+ results[73][71]="52773.47620913591";
+ results[73][72]="2.049990301342397E+61";
+ results[73][73]="1";
+ results[73][74]="5.725384586557730E+55";
+ results[74][0]="8.052301557585906E-8";
+ results[74][1]="1.770605365462456E-13";
+ results[74][2]="3.972666639277327E-18";
+ results[74][3]="4.632562604379404E-23";
+ results[74][4]="3.233381495395381E-28";
+ results[74][5]="1.008794965777072E-12";
+ results[74][6]="0.0006269198812448631";
+ results[74][7]="9.674280804091849E-18";
+ results[74][8]="9.241980019390084E-10";
+ results[74][9]="9.017812162240471E-23";
+ results[74][10]="3.291107413129942E-14";
+ results[74][11]="1.092791965506384E-27";
+ results[74][12]="1.467322244295588E-19";
+ results[74][13]="1.374917076937174E-32";
+ results[74][14]="1.105534921407618E-24";
+ results[74][15]="1.187616773274011E-16";
+ results[74][16]="1.364334847713883";
+ results[74][17]="1.405582368754908E-21";
+ results[74][18]="0.00001070746835276518";
+ results[74][19]="9.059629594726956E-27";
+ results[74][20]="3.623491507959662E-10";
+ results[74][21]="1.689171516062104E-31";
+ results[74][22]="2.081695150848690E-15";
+ results[74][23]="1.851345444067719E-36";
+ results[74][24]="1.102648597668354E-20";
+ results[74][25]="1.103824654270814E-20";
+ results[74][26]="29565.64565260007";
+ results[74][27]="1.286815434870144E-25";
+ results[74][28]="0.4559686490696489";
+ results[74][29]="2.196614918797670E-30";
+ results[74][30]="0.000001027626532239985";
+ results[74][31]="2.680169766841597E-35";
+ results[74][32]="2.089218688706290E-11";
+ results[74][33]="1.153239933824738E-40";
+ results[74][34]="5.527147087483460E-16";
+ results[74][35]="1.356790426208511E-24";
+ results[74][36]="285900258.4934282";
+ results[74][37]="1.147951679823628E-29";
+ results[74][38]="1399.214455677041";
+ results[74][39]="1.223484963110475E-34";
+ results[74][40]="0.02536899052671676";
+ results[74][41]="1.958778561659312E-39";
+ results[74][42]="9.161688649454979E-8";
+ results[74][43]="3.533569266587664E-44";
+ results[74][44]="2.406702744894305E-12";
+ results[74][45]="3.099474788713032E-28";
+ results[74][46]="1687536852317.355";
+ results[74][47]="1.126738708841461E-33";
+ results[74][48]="13973813.58756047";
+ results[74][49]="4.771812612164872E-38";
+ results[74][50]="470.9377016512027";
+ results[74][51]="1.187744802071186E-43";
+ results[74][52]="0.008438652308849302";
+ results[74][53]="2.474078779366023E-48";
+ results[74][54]="3.441377655339997E-8";
+ results[74][55]="1.253045969730694E-32";
+ results[74][56]="1.446448413805017E+16";
+ results[74][57]="1.256819901603824E-37";
+ results[74][58]="115612759725.7422";
+ results[74][59]="2.466073435932954E-42";
+ results[74][60]="5971578.629938194";
+ results[74][61]="1.139989719793558E-47";
+ results[74][62]="42.69331595631704";
+ results[74][63]="9.696035386027837E-53";
+ results[74][64]="0.0004460990046813902";
+ results[74][65]="1.051987332763925E-36";
+ results[74][66]="9.378580946051059E+19";
+ results[74][67]="3.395828634270787E-41";
+ results[74][68]="2000784391440555";
+ results[74][69]="1.508266348754094E-46";
+ results[74][70]="14690335094.84779";
+ results[74][71]="9.217455248864755E-52";
+ results[74][72]="358052.8557252626";
+ results[74][73]="1.746607559512835E-56";
+ results[74][74]="1";
+ }
+
+ @Test
+ public void mcDivideTests() {
+ for(int i=0; i<value.length; i++) {
+ for(int j=0; j<value.length; j++) {
+ BigDecimal v1 = new BigDecimal(value[i]);
+ BigDecimal v2 = new BigDecimal(value[j]);
+ BigDecimal res1 = v1.divide(v2, MathContext.DECIMAL64);
+ Assert.assertEquals(res1.toString(), results[i][j],
+ "Unexpected result from " + v1 + " / " + v2 +
+ "; expected " + results[i][j] + " got " + res1);
+ }
+ }
+ for (int mpc = 1; mpc < 23; mpc++) {
+ for (int i = 0; i < value.length; i++) {
+ for (int j = 0; j < value.length; j++) {
+ BigDecimal v1 = new BigDecimal(value[i]);
+ BigDecimal v2 = new BigDecimal(value[j]);
+ BigDecimal res1 = v1.divide(v2, new MathContext(mpc, RoundingMode.HALF_EVEN));
+ BigDecimal res2 = v1.divide(v2, new MathContext(128, RoundingMode.HALF_EVEN)).round(new MathContext(mpc, RoundingMode.HALF_EVEN));
+ Assert.assertEquals(res1, res2, "Unexpected result from " + v1 + " / " + v2 +
+ "; expected " + res2 + " got " + res1);
+ }
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/DivideTests.java b/ojluni/src/test/java/math/BigDecimal/DivideTests.java
new file mode 100644
index 0000000..57773ee
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/DivideTests.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2003, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4851776 4907265 6177836 6876282 8066842
+ * @summary Some tests for the divide methods.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class DivideTests {
+
+ // Preliminary exact divide method; could be used for comparison
+ // purposes.
+ BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {
+ /*
+ * Handle zero cases first.
+ */
+ if (divisor.signum() == 0) { // x/0
+ if (dividend.signum() == 0) // 0/0
+ throw new ArithmeticException("Division undefined"); // NaN
+ throw new ArithmeticException("Division by zero");
+ }
+ if (dividend.signum() == 0) // 0/y
+ return BigDecimal.ZERO;
+ else {
+ /*
+ * Determine if there is a result with a terminating
+ * decimal expansion. Putting aside overflow and
+ * underflow considerations, the existance of an exact
+ * result only depends on the ratio of the intVal's of the
+ * dividend (i.e. this) and and divisor since the scales
+ * of the argument just affect where the decimal point
+ * lies.
+ *
+ * For the ratio of (a = this.intVal) and (b =
+ * divisor.intVal) to have a finite decimal expansion,
+ * once a/b is put in lowest terms, b must be equal to
+ * (2^i)*(5^j) for some integer i,j >= 0. Therefore, we
+ * first compute to see if b_prime =(b/gcd(a,b)) is equal
+ * to (2^i)*(5^j).
+ */
+ BigInteger TWO = BigInteger.valueOf(2);
+ BigInteger FIVE = BigInteger.valueOf(5);
+ BigInteger TEN = BigInteger.valueOf(10);
+
+ BigInteger divisorIntvalue = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();
+ BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();
+
+ BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));
+
+ boolean goodDivisor = false;
+ int i=0, j=0;
+
+ badDivisor: {
+ while(! b_prime.equals(BigInteger.ONE) ) {
+ int b_primeModTen = b_prime.mod(TEN).intValue() ;
+
+ switch(b_primeModTen) {
+ case 0:
+ // b_prime divisible by 10=2*5, increment i and j
+ i++;
+ j++;
+ b_prime = b_prime.divide(TEN);
+ break;
+
+ case 5:
+ // b_prime divisible by 5, increment j
+ j++;
+ b_prime = b_prime.divide(FIVE);
+ break;
+
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ // b_prime divisible by 2, increment i
+ i++;
+ b_prime = b_prime.divide(TWO);
+ break;
+
+ default: // hit something we shouldn't have
+ b_prime = BigInteger.ONE; // terminate loop
+ break badDivisor;
+ }
+ }
+
+ goodDivisor = true;
+ }
+
+ if( ! goodDivisor ) {
+ throw new ArithmeticException("Non terminating decimal expansion");
+ }
+ else {
+ // What is a rule for determining how many digits are
+ // needed? Once that is determined, cons up a new
+ // MathContext object and pass it on to the divide(bd,
+ // mc) method; precision == ?, roundingMode is unnecessary.
+
+ // Are we sure this is the right scale to use? Should
+ // also determine a precision-based method.
+ MathContext mc = new MathContext(dividend.precision() +
+ (int)Math.ceil(
+ 10.0*divisor.precision()/3.0),
+ RoundingMode.UNNECESSARY);
+ // Should do some more work here to rescale, etc.
+ return dividend.divide(divisor, mc);
+ }
+ }
+ }
+
+ @Test
+ public void powersOf2and5() {
+ for(int i = 0; i < 6; i++) {
+ int powerOf2 = (int)StrictMath.pow(2.0, i);
+
+ for(int j = 0; j < 6; j++) {
+ int powerOf5 = (int)StrictMath.pow(5.0, j);
+ int product;
+
+ BigDecimal bd;
+
+ try {
+ bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));
+ } catch (ArithmeticException e) {
+ Assert.fail((new BigDecimal(powerOf2)).toString() + " / " +
+ (new BigDecimal(powerOf5)).toString() + " threw an exception.");
+ }
+
+ try {
+ bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));
+ } catch (ArithmeticException e) {
+ Assert.fail((new BigDecimal(powerOf2)).toString() + " / " +
+ (new BigDecimal(powerOf5)).toString() + " threw an exception.");
+ }
+
+ try {
+ bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));
+ } catch (ArithmeticException e) {
+ Assert.fail((new BigDecimal(powerOf5)).toString() + " / " +
+ (new BigDecimal(powerOf2)).toString() + " threw an exception.");
+ }
+
+ }
+ }
+ }
+
+ @Test
+ public void nonTerminating() {
+ int[] primes = {1, 3, 7, 13, 17};
+
+ // For each pair of prime products, verify the ratio of
+ // non-equal products has a non-terminating expansion.
+
+ for(int i = 0; i < primes.length; i++) {
+ for(int j = i+1; j < primes.length; j++) {
+
+ for(int m = 0; m < primes.length; m++) {
+ for(int n = m+1; n < primes.length; n++) {
+ int dividend = primes[i] * primes[j];
+ int divisor = primes[m] * primes[n];
+
+ if ( ((dividend/divisor) * divisor) != dividend ) {
+ try {
+ BigDecimal quotient = (new BigDecimal(dividend).
+ divide(new BigDecimal(divisor)));
+ Assert.fail("Exact quotient " + quotient.toString() +
+ " returned for non-terminating fraction " +
+ dividend + " / " + divisor + ".");
+ }
+ catch (ArithmeticException e) {
+ ; // Correct result
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ public void properScaleTests(){
+ BigDecimal[][] testCases = {
+ {new BigDecimal("1"), new BigDecimal("5"), new BigDecimal("2e-1")},
+ {new BigDecimal("1"), new BigDecimal("50e-1"), new BigDecimal("2e-1")},
+ {new BigDecimal("10e-1"), new BigDecimal("5"), new BigDecimal("2e-1")},
+ {new BigDecimal("1"), new BigDecimal("500e-2"), new BigDecimal("2e-1")},
+ {new BigDecimal("100e-2"), new BigDecimal("5"), new BigDecimal("20e-2")},
+ {new BigDecimal("1"), new BigDecimal("32"), new BigDecimal("3125e-5")},
+ {new BigDecimal("1"), new BigDecimal("64"), new BigDecimal("15625e-6")},
+ {new BigDecimal("1.0000000"), new BigDecimal("64"), new BigDecimal("156250e-7")},
+ };
+
+
+ for(BigDecimal[] tc : testCases) {
+ BigDecimal quotient = tc[0].divide(tc[1]);
+ Assert.assertEquals(quotient, tc[2],
+ "Unexpected quotient from " + tc[0] + " / " + tc[1] +
+ "; expected " + tc[2] + " got " + quotient);
+ }
+ }
+
+ @Test
+ public void trailingZeroTests() {
+ MathContext mc = new MathContext(3, RoundingMode.FLOOR);
+ BigDecimal[][] testCases = {
+ {new BigDecimal("19"), new BigDecimal("100"), new BigDecimal("0.19")},
+ {new BigDecimal("21"), new BigDecimal("110"), new BigDecimal("0.190")},
+ };
+
+ for(BigDecimal[] tc : testCases) {
+ BigDecimal quotient = tc[0].divide(tc[1], mc);
+ Assert.assertEquals(quotient, tc[2],
+ "Unexpected quotient from " + tc[0] + " / " + tc[1] +
+ "; expected " + tc[2] + " got " + quotient);
+ }
+ }
+
+ @Test
+ public void scaledRoundedDivideTests() {
+ // Tests of the traditional scaled divide under different
+ // rounding modes.
+
+ // Encode rounding mode and scale for the divide in a
+ // BigDecimal with the significand equal to the rounding mode
+ // and the scale equal to the number's scale.
+
+ // {dividend, divisor, rounding, quotient}
+ BigDecimal a = new BigDecimal("31415");
+ BigDecimal a_minus = a.negate();
+ BigDecimal b = new BigDecimal("10000");
+
+ BigDecimal c = new BigDecimal("31425");
+ BigDecimal c_minus = c.negate();
+
+ // Ad hoc tests
+ BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
+ BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
+
+ BigDecimal[][] testCases = {
+ {a, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("3.142")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("-3.142")},
+
+ {a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},
+
+ {a, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("3.142")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("-3.141")},
+
+ {a, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("3.141")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("-3.142")},
+
+ {a, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("3.142")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("-3.142")},
+
+ {a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},
+
+ {a, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
+ {a_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
+
+ {c, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
+ {c_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
+
+ {d, e, BigDecimal.valueOf(ROUND_HALF_UP, -5), BigDecimal.valueOf(-1, -5)},
+ {d, e, BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
+ {d, e, BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
+ };
+
+ for(BigDecimal[] tc : testCases) {
+ int scale = tc[2].scale();
+ int rm = tc[2].unscaledValue().intValue();
+
+ BigDecimal quotient = tc[0].divide(tc[1], scale, rm);
+ Assert.assertEquals(quotient, tc[3],
+ "Unexpected quotient from " + tc[0] + " / " + tc[1] +
+ " scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +
+ "; expected " + tc[3] + " got " + quotient);
+ }
+
+ // 6876282
+ BigDecimal[][] testCases2 = {
+ // { dividend, divisor, expected quotient }
+ { new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
+ { new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
+ new BigDecimal(441) },
+ { new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
+ new BigDecimal("0.000115309916") },
+ { new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
+ new BigDecimal(4) },
+ { new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
+ new BigDecimal(4) },
+ { new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
+ new BigDecimal(5) },
+ { new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
+ new BigDecimal(4) },
+ { new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
+ new BigDecimal(4) },
+ };
+
+ for (BigDecimal[] test : testCases2) {
+ BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
+ Assert.assertEquals(quo, test[2], "Unexpected quotient from " + test[0] + " / " + test[1] +
+ " rounding mode HALF_UP" +
+ "; expected " + test[2] + " got " + quo);
+ }
+ }
+
+ @Test
+ public void divideByOneTests() {
+ //problematic divisor: one with scale 17
+ BigDecimal one = BigDecimal.ONE.setScale(17);
+ RoundingMode rounding = RoundingMode.UNNECESSARY;
+
+ long[][] unscaledAndScale = new long[][] {
+ { Long.MAX_VALUE, 17},
+ {-Long.MAX_VALUE, 17},
+ { Long.MAX_VALUE, 0},
+ {-Long.MAX_VALUE, 0},
+ { Long.MAX_VALUE, 100},
+ {-Long.MAX_VALUE, 100}
+ };
+
+ for (long[] uas : unscaledAndScale) {
+ long unscaled = uas[0];
+ int scale = (int)uas[1];
+
+ BigDecimal noRound = null;
+ try {
+ noRound = BigDecimal.valueOf(unscaled, scale).
+ divide(one, RoundingMode.UNNECESSARY);
+ } catch (ArithmeticException e) {
+ Assert.fail("ArithmeticException for value " + unscaled
+ + " and scale " + scale + " without rounding");
+ }
+
+ BigDecimal roundDown = null;
+ try {
+ roundDown = BigDecimal.valueOf(unscaled, scale).
+ divide(one, RoundingMode.DOWN);
+ } catch (ArithmeticException e) {
+ Assert.fail("ArithmeticException for value " + unscaled
+ + " and scale " + scale + " with rounding down");
+ }
+
+ if (noRound != null && roundDown != null && noRound.compareTo(roundDown) != 0) {
+ Assert.fail("Equality failure for value " + unscaled
+ + " and scale " + scale);
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/EqualsTests.java b/ojluni/src/test/java/math/BigDecimal/EqualsTests.java
new file mode 100644
index 0000000..c28249b
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/EqualsTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 1234567
+ * @summary Test BigDecimal.equals() method.
+ * @author xlu
+ */
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class EqualsTests {
+
+ @Test
+ public void testEquals() {
+ BigDecimal[][] testValues = {
+ // The even index is supposed to return true for equals call and
+ // the odd index is supposed to return false, i.e. not equal.
+ {ZERO, ZERO},
+ {ONE, TEN},
+
+ {valueOf(Integer.MAX_VALUE), valueOf(Integer.MAX_VALUE)},
+ {valueOf(Long.MAX_VALUE), valueOf(-Long.MAX_VALUE)},
+
+ {valueOf(12345678), valueOf(12345678)},
+ {valueOf(123456789), valueOf(123456788)},
+
+ {new BigDecimal("123456789123456789123"),
+ new BigDecimal(new BigInteger("123456789123456789123"))},
+ {new BigDecimal("123456789123456789123"),
+ new BigDecimal(new BigInteger("123456789123456789124"))},
+
+ {valueOf(Long.MIN_VALUE), new BigDecimal("-9223372036854775808")},
+ {new BigDecimal("9223372036854775808"), valueOf(Long.MAX_VALUE)},
+
+ {valueOf(Math.round(Math.pow(2, 10))), new BigDecimal("1024")},
+ {new BigDecimal("1020"), valueOf(Math.pow(2, 11))},
+
+ {new BigDecimal(BigInteger.valueOf(2).pow(65)),
+ new BigDecimal("36893488147419103232")},
+ {new BigDecimal("36893488147419103231.81"),
+ new BigDecimal("36893488147419103231.811"),
+ }
+ };
+
+ boolean expected = Boolean.TRUE;
+ for (BigDecimal[] testValuePair : testValues) {
+ equalsTest(testValuePair[0], testValuePair[1], expected);
+ expected = !expected;
+ }
+ }
+
+ private static void equalsTest(BigDecimal l, BigDecimal r, boolean expected) {
+ boolean result = l.equals(r);
+ Assert.assertEquals(result, expected, l + " .equals(" + r + ") => " + result +
+ "\n\tExpected " + expected);
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/FloatDoubleValueTests.java b/ojluni/src/test/java/math/BigDecimal/FloatDoubleValueTests.java
new file mode 100644
index 0000000..559ccc3
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/FloatDoubleValueTests.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6274390 7082971
+ * @summary Verify {float, double}Value methods work with condensed representation
+ * @run main FloatDoubleValueTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 FloatDoubleValueTests
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class FloatDoubleValueTests {
+ private static final long two2the24 = 1L<<23;
+ private static final long two2the53 = 1L<<52;
+
+ // Largest long that fits exactly in a float
+ private static final long maxFltLong = (long)(Integer.MAX_VALUE & ~(0xff));
+
+ // Largest long that fits exactly in a double
+ private static final long maxDblLong = Long.MAX_VALUE & ~(0x7ffL);
+
+ static void testDoubleValue0(long i, BigDecimal bd) {
+ Assert.assertFalse(bd.doubleValue() != i || bd.longValue() != i,
+ "Unexpected equality failure for " + i + "\t" + bd);
+ }
+
+ static void testFloatValue0(long i, BigDecimal bd) {
+ Assert.assertFalse(bd.floatValue() != i || bd.longValue() != i,
+ "Unexpected equality failure for " + i + "\t" + bd);
+ }
+
+ static void checkFloat(BigDecimal bd, float f) {
+ float fbd = bd.floatValue();
+ Assert.assertEquals(fbd, f, String.format("Bad conversion:"+
+ "got %g (%a)\texpected %g (%a)",
+ f, f, fbd, fbd));
+ }
+
+ static void checkDouble(BigDecimal bd, double d) {
+ double dbd = bd.doubleValue();
+
+ Assert.assertEquals(dbd, d, String.format("Bad conversion:"+
+ "got %g (%a)\texpected %g (%a)",
+ d, d, dbd, dbd));
+ }
+
+ // Test integral values that will convert exactly to both float
+ // and double.
+ @Test
+ public void testFloatDoubleValue() {
+ long[] longValues = {
+ Long.MIN_VALUE, // -2^63
+ 0,
+ 1,
+ 2,
+
+ two2the24-1,
+ two2the24,
+ two2the24+1,
+
+ maxFltLong-1,
+ maxFltLong,
+ maxFltLong+1,
+ };
+
+ for(long i : longValues) {
+ BigDecimal bd1 = new BigDecimal(i);
+ BigDecimal bd2 = new BigDecimal(-i);
+
+ testDoubleValue0( i, bd1);
+ testDoubleValue0(-i, bd2);
+
+ testFloatValue0( i, bd1);
+ testFloatValue0(-i, bd2);
+ }
+
+ }
+
+ @Test
+ public void testDoubleValue() {
+ long[] longValues = {
+ Integer.MAX_VALUE-1,
+ Integer.MAX_VALUE,
+ (long)Integer.MAX_VALUE+1,
+
+ two2the53-1,
+ two2the53,
+ two2the53+1,
+
+ maxDblLong,
+ };
+
+ // Test integral values that will convert exactly to double
+ // but not float.
+ for(long i : longValues) {
+ BigDecimal bd1 = new BigDecimal(i);
+ BigDecimal bd2 = new BigDecimal(-i);
+
+ testDoubleValue0( i, bd1);
+ testDoubleValue0(-i, bd2);
+
+ checkFloat(bd1, (float)i);
+ checkFloat(bd2, -(float)i);
+ }
+
+ // Now check values that should not convert the same in double
+ for(long i = maxDblLong; i < Long.MAX_VALUE; i++) {
+ BigDecimal bd1 = new BigDecimal(i);
+ BigDecimal bd2 = new BigDecimal(-i);
+ checkDouble(bd1, (double)i);
+ checkDouble(bd2, -(double)i);
+
+ checkFloat(bd1, (float)i);
+ checkFloat(bd2, -(float)i);
+ }
+
+ checkDouble(new BigDecimal(Long.MIN_VALUE), (double)Long.MIN_VALUE);
+ checkDouble(new BigDecimal(Long.MAX_VALUE), (double)Long.MAX_VALUE);
+ }
+
+ @Test
+ public void testFloatValue() {
+ // Now check values that should not convert the same in float
+ for(long i = maxFltLong; i <= Integer.MAX_VALUE; i++) {
+ BigDecimal bd1 = new BigDecimal(i);
+ BigDecimal bd2 = new BigDecimal(-i);
+ checkFloat(bd1, (float)i);
+ checkFloat(bd2, -(float)i);
+
+ testDoubleValue0( i, bd1);
+ testDoubleValue0(-i, bd2);
+ }
+ }
+
+ @Test
+ public void testFloatValue1() {
+ checkFloat(new BigDecimal("85070591730234615847396907784232501249"), 8.507059e+37f);
+ checkFloat(new BigDecimal("7784232501249e12"), 7.7842326e24f);
+ checkFloat(new BigDecimal("907784232501249e-12"),907.78424f);
+ checkFloat(new BigDecimal("7784e8"),7.7839997e11f);
+ checkFloat(new BigDecimal("9077e-8"),9.077e-5f);
+ }
+
+ @Test
+ public void testDoubleValue1() {
+ checkDouble(new BigDecimal("85070591730234615847396907784232501249"), 8.507059173023462e37);
+ checkDouble(new BigDecimal("7784232501249e12"), 7.784232501249e24);
+ checkDouble(new BigDecimal("907784232501249e-12"), 907.784232501249);
+ checkDouble(new BigDecimal("7784e8"), 7.784e11);
+ checkDouble(new BigDecimal("9077e-8"), 9.077e-5);
+
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/IntegralDivisionTests.java b/ojluni/src/test/java/math/BigDecimal/IntegralDivisionTests.java
new file mode 100644
index 0000000..f5f1ade
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/IntegralDivisionTests.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4904082 4917089 6337226 6378503
+ * @summary Tests that integral division and related methods return the proper result and scale.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class IntegralDivisionTests {
+
+ @Test
+ public void dividetoIntegralValueTests() {
+ // Exact integer quotient should have the same results from
+ // the exact divide and dividetoIntegralValue
+
+
+ // Rounded results
+ BigDecimal [][] moreTestCases = {
+ {new BigDecimal("11003"), new BigDecimal("10"), new BigDecimal("1100")},
+ {new BigDecimal("11003"), new BigDecimal("1e1"), new BigDecimal("1100.0")},
+ {new BigDecimal("1e9"), new BigDecimal("1"), new BigDecimal("1e9")},
+ {new BigDecimal("1e9"), new BigDecimal("1.00"), new BigDecimal("1e9")},
+ {new BigDecimal("1e9"), new BigDecimal("0.1"), new BigDecimal("1e10")},
+ {new BigDecimal("10e8"), new BigDecimal("0.1"), new BigDecimal("10e9")},
+ {new BigDecimal("400e1"), new BigDecimal("5"), new BigDecimal("80e1")},
+ {new BigDecimal("400e1"), new BigDecimal("4.999999999"), new BigDecimal("8e2")},
+ {new BigDecimal("40e2"), new BigDecimal("5"), new BigDecimal("8e2")},
+ {BigDecimal.valueOf(1, Integer.MIN_VALUE),
+ BigDecimal.valueOf(1, -(Integer.MAX_VALUE & 0x7fffff00)),
+ BigDecimal.valueOf(1, -256)},
+ };
+
+ for(BigDecimal [] testCase: moreTestCases) {
+ BigDecimal quotient = testCase[0].divideToIntegralValue(testCase[1]);
+ Assert.assertEquals(quotient, testCase[2],
+ "dividend = " + testCase[0] + " scale = " + testCase[0].scale() +
+ " divisor = " + testCase[1] + " scale = " + testCase[1].scale() +
+ " quotient = " + quotient + " scale = " + quotient.scale() +
+ " expected = " + testCase[2] + " scale = " + testCase[2].scale());
+ }
+ }
+
+ @Test
+ public void dividetoIntegralValueRoundedTests() {
+ BigDecimal dividend = new BigDecimal("11003");
+ BigDecimal divisor = new BigDecimal("10");
+ BigDecimal [] quotients = { // Expected results with precision =
+ new BigDecimal("1100"), // 0
+ null, // 1
+ new BigDecimal("11e2"), // 2
+ new BigDecimal("110e1"), // 3
+ new BigDecimal("1100"), // 4
+ };
+ divideContextTestPrecs(dividend, divisor, quotients);
+
+ dividend = new BigDecimal("11003");
+ divisor = new BigDecimal("1e1");
+ BigDecimal [] quotients2 = { // Expected results with precision =
+ new BigDecimal("1100.0"), // 0
+ null, // 1
+ new BigDecimal("11e2"), // 2
+ new BigDecimal("110e1"), // 3
+ new BigDecimal("1100"), // 4
+ new BigDecimal("1100.0"), // 5
+ };
+ divideContextTestPrecs(dividend, divisor, quotients2);
+
+ dividend = new BigDecimal("1230000");
+ divisor = new BigDecimal("100");
+ BigDecimal [] quotients3 = { // Expected results with precision =
+ new BigDecimal("12300"), // 0
+ null, // 1
+ null, // 2
+ new BigDecimal("123e2"), // 3
+ new BigDecimal("1230e1"), // 4
+ new BigDecimal("12300"), // 5
+ };
+ divideContextTestPrecs(dividend, divisor, quotients3);
+
+ dividend = new BigDecimal("33");
+ divisor = new BigDecimal("3");
+ BigDecimal [] quotients4 = { // Expected results with precision =
+ new BigDecimal("11"), // 0
+ null, // 1
+ new BigDecimal("11"), // 2
+ new BigDecimal("11"), // 3
+ };
+ divideContextTestPrecs(dividend, divisor, quotients4);
+
+ dividend = new BigDecimal("34");
+ divisor = new BigDecimal("3");
+ BigDecimal [] quotients5 = { // Expected results with precision =
+ new BigDecimal("11"), // 0
+ null, // 1
+ new BigDecimal("11"), // 2
+ new BigDecimal("11"), // 3
+ };
+ divideContextTestPrecs(dividend, divisor, quotients5);
+ }
+
+ static void divideContextTestPrecs(BigDecimal dividend,
+ BigDecimal divisor,
+ BigDecimal[] quotients) {
+ for(int i = 0; i < quotients.length; i++) {
+ BigDecimal result = null;
+ BigDecimal quotient = quotients[i];
+
+ try {
+ result = dividend.divideToIntegralValue(divisor,
+ new MathContext(i, RoundingMode.DOWN));
+ } catch (ArithmeticException e) {
+ if (quotient != null) {
+ Assert.fail("Unexpected exception:" +
+ " dividend = " + dividend + " scale = " + dividend.scale() +
+ " divisor = " + divisor + " scale = " + divisor.scale() +
+ " expected = " + quotient + " scale = " + quotient.scale());
+ }
+ }
+
+ if (quotient != null) {
+ Assert.assertEquals(quotient, result, "Unexpected result: " +
+ " dividend = " + dividend + " scale = " + dividend.scale() +
+ " divisor = " + divisor + " scale = " + divisor.scale() +
+ " quotient = " + result + " scale = " + result.scale() +
+ " expected = " + quotient + " scale = " + quotient.scale() +
+ " precision = " + i);
+ } else {
+ if (result != null) {
+ Assert.fail("Unexpected unexceptional result:" +
+ " dividend = " + dividend + " scale = " + dividend.scale() +
+ " divisor = " + divisor + " scale = " + divisor.scale() +
+ " quotient = " + result + " scale = " + result.scale() +
+ " precision = " + i);
+ }
+ }
+ }
+ }
+
+
+ static void divideContextTests(BigDecimal dividend,
+ BigDecimal divisor,
+ BigDecimal expected,
+ MathContext mc) {
+ divideContextTest(dividend, divisor, expected, mc);
+ divideContextTest(dividend.negate(), divisor.negate(), expected, mc);
+
+ if (expected != null) {
+ divideContextTest(dividend.negate(), divisor, expected.negate(), mc);
+ divideContextTest(dividend, divisor.negate(), expected.negate(), mc);
+ }
+ }
+
+
+ static void divideContextTest(BigDecimal dividend,
+ BigDecimal divisor,
+ BigDecimal expected,
+ MathContext mc) {
+ BigDecimal result = null;
+
+ try {
+ result = dividend.divideToIntegralValue(divisor, mc);
+ } catch (ArithmeticException e) {
+ if (expected != null) {
+ Assert.fail("Unexpected exception:" +
+ " dividend = " + dividend + " scale = " + dividend.scale() +
+ " divisor = " + divisor + " scale = " + divisor.scale() +
+ " expected = " + expected + " scale = " + expected.scale() +
+ " MathContext = " + mc);
+ }
+ }
+
+ if (expected != null) {
+ Assert.assertEquals(result, expected, "Unexpected result:" +
+ " dividend = " + dividend + " scale = " + dividend.scale() +
+ " divisor = " + divisor + " scale = " + divisor.scale() +
+ " expected = " + expected + " scale = " + expected.scale() +
+ " result = " + result + " scale = " + result.scale() +
+ " MathContext = " + mc);
+ } else {
+ if (result != null) {
+ Assert.fail("Unexpected unexceptional result:" +
+ "dividend = " + dividend + " scale = " + dividend.scale() +
+ "divisor = " + divisor + " scale = " + divisor.scale() +
+ "quotient = " + result + " scale = " + result.scale() +
+ "MathConext = " + mc);
+ }
+ }
+ }
+
+ @Test
+ public void dividetoIntegralValueScalingTests() {
+ BigDecimal dividend = new BigDecimal("123456789000");
+ BigDecimal divisor = BigDecimal.ONE;
+ BigDecimal expected = new BigDecimal("123456789e3");
+ MathContext mc = new MathContext(9,RoundingMode.DOWN);
+ divideContextTests(dividend, divisor, expected, mc);
+
+
+ // 100/3 = 33 remainder 1
+ int [] precisions = {0, 2, 3, 4};
+ dividend = new BigDecimal(100);
+ divisor = new BigDecimal(3);
+ expected = new BigDecimal(33);
+
+ for(RoundingMode rm: RoundingMode.values())
+ for(int precision: precisions) {
+ divideContextTests(dividend, divisor, expected, new MathContext(precision, rm));
+ }
+
+ // 123000/10 = 12300 remainder 0
+ dividend = new BigDecimal(123000);
+ divisor = new BigDecimal(10);
+ int[] precisions1 = {0, 1, 2, 3, 4, 5};
+ BigDecimal[] expected1 = {
+ new BigDecimal("12300"),
+ null,
+ null,
+ new BigDecimal("123e2"),
+ new BigDecimal("1230e1"),
+ new BigDecimal("12300"),
+ };
+
+ for(RoundingMode rm: RoundingMode.values())
+ for(int i = 0; i < precisions1.length; i++) {
+ divideContextTests(dividend, divisor,
+ expected1[i],
+ new MathContext(precisions1[i], rm));
+ }
+
+ // 123e3/10 = 123e2 remainder 0
+ dividend = new BigDecimal("123e3");
+ divisor = new BigDecimal(10);
+ int[] precisions2 = {0, 1, 2, 3, 4, 5};
+ BigDecimal[] expected2 = {
+ new BigDecimal("123e2"),
+ null,
+ null,
+ new BigDecimal("123e2"),
+ new BigDecimal("123e2"),
+ new BigDecimal("123e2"),
+ };
+
+ for(RoundingMode rm: RoundingMode.values())
+ for(int i = 0; i < precisions2.length; i++) {
+ divideContextTests(dividend, divisor,
+ expected2[i],
+ new MathContext(precisions2[i], rm));
+ }
+
+
+ // 123000/1e1 = 12300.0 remainder 0
+ dividend = new BigDecimal("123000");
+ divisor = new BigDecimal("1e1");
+ int[] precisions3 = {0, 1, 2, 3, 4, 5, 6};
+ BigDecimal[] expected3 = {
+ new BigDecimal("12300.0"),
+ null,
+ null,
+ new BigDecimal("123e2"),
+ new BigDecimal("1230e1"),
+ new BigDecimal("12300"),
+ new BigDecimal("12300.0"),
+ };
+
+ for(RoundingMode rm: RoundingMode.values())
+ for(int i = 0; i < precisions3.length; i++) {
+ divideContextTests(dividend, divisor,
+ expected3[i],
+ new MathContext(precisions3[i], rm));
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/LongValueExactTests.java b/ojluni/src/test/java/math/BigDecimal/LongValueExactTests.java
new file mode 100644
index 0000000..4d53663
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/LongValueExactTests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6806261
+ * @summary Tests of BigDecimal.longValueExact
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class LongValueExactTests {
+
+ @Test
+ public static void longValueExactTests() {
+ String[] testStrings = {
+ "9223372036854775807",
+ "9223372036854775807.0",
+ "9223372036854775807.00",
+ "-9223372036854775808",
+ "-9223372036854775808.0",
+ "-9223372036854775808.00",
+ };
+
+ for (String longValue : testStrings) {
+ try {
+ BigDecimal bd = new BigDecimal(longValue);
+ long longValueExact = bd.longValueExact();
+ } catch (Exception e) {
+ Assert.fail("Unexpected exception for longValueExact(" + longValue + "): " + e.getMessage());
+ }
+ }
+
+ // The following Strings are supposed to make longValueExact throw
+ // ArithmeticException.
+ String[] testStrings2 = {
+ "9223372036854775808",
+ "9223372036854775808.0",
+ "9223372036854775808.00",
+ "-9223372036854775809",
+ "-9223372036854775808.1",
+ "-9223372036854775808.01",
+ };
+
+ for (String bigValue : testStrings2) {
+ try {
+ BigDecimal bd = new BigDecimal(bigValue);
+ long longValueExact = bd.longValueExact();
+ Assert.fail("Unexpectedly no throw for longValueExact(" + bigValue + ")");
+ } catch (ArithmeticException e) {
+ // Success;
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/MultiplyTests.java b/ojluni/src/test/java/math/BigDecimal/MultiplyTests.java
new file mode 100644
index 0000000..a359e45
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/MultiplyTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6850606
+ * @summary Test BigDecimal.multiply(BigDecimal)
+ * @author xlu
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class MultiplyTests {
+
+ @Test
+ public void multiplyTests() {
+ BigDecimal[] bd1 = {
+ new BigDecimal("123456789"),
+ new BigDecimal("1234567898"),
+ new BigDecimal("12345678987")
+ };
+
+ BigDecimal[] bd2 = {
+ new BigDecimal("987654321"),
+ new BigDecimal("8987654321"),
+ new BigDecimal("78987654321")
+ };
+
+ // Two dimensional array recording bd1[i] * bd2[j] &
+ // 0 <= i <= 2 && 0 <= j <= 2;
+ BigDecimal[][] expectedResults = {
+ {new BigDecimal("121932631112635269"),
+ new BigDecimal("1109586943112635269"),
+ new BigDecimal("9751562173112635269")
+ },
+ { new BigDecimal("1219326319027587258"),
+ new BigDecimal("11095869503027587258"),
+ new BigDecimal("97515622363027587258")
+ },
+ { new BigDecimal("12193263197189452827"),
+ new BigDecimal("110958695093189452827"),
+ new BigDecimal("975156224183189452827")
+ }
+ };
+
+ for (int i = 0; i < bd1.length; i++) {
+ for (int j = 0; j < bd2.length; j++) {
+ Assert.assertEquals(bd1[i].multiply(bd2[j]), expectedResults[i][j],
+ bd1[i] + " * " + bd2[j] + " + is " + bd1[i].multiply(bd2[j]) +
+ " but expected: " + expectedResults[i][j]);
+ }
+ }
+
+ BigDecimal x = BigDecimal.valueOf(8L, 1);
+ BigDecimal xPower = BigDecimal.valueOf(-1L);
+ try {
+ for (int i = 0; i < 100; i++) {
+ xPower = xPower.multiply(x);
+ }
+ } catch (Exception ex) {
+ Assert.fail("Unexpected exception: " + ex.getMessage());
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/NegateTests.java b/ojluni/src/test/java/math/BigDecimal/NegateTests.java
new file mode 100644
index 0000000..af5805b
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/NegateTests.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6325535
+ * @summary Test for the rounding behavior of negate(MathContext)
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class NegateTests {
+
+ static BigDecimal negateThenRound(BigDecimal bd, MathContext mc) {
+ return bd.negate().plus(mc);
+ }
+
+
+ static BigDecimal absThenRound(BigDecimal bd, MathContext mc) {
+ return bd.abs().plus(mc);
+ }
+
+
+ static void negateTest(BigDecimal[][] testCases, MathContext mc) {
+ for (BigDecimal [] testCase : testCases) {
+
+ BigDecimal bd = testCase[0];
+ BigDecimal neg1 = bd.negate(mc);
+ BigDecimal neg2 = negateThenRound(bd, mc);
+ BigDecimal expected = testCase[1];
+
+ Assert.assertEquals(neg1, expected, "(" + bd + ").negate(" + mc + ") => " +
+ neg1 + " != expected " + expected);
+
+ Assert.assertEquals(neg1, neg2, "(" + bd + ").negate(" + mc + ") => " +
+ neg1 + " != ntr " + neg2);
+
+ // Test abs consistency
+ BigDecimal abs = bd.abs(mc);
+ BigDecimal expectedAbs = absThenRound(bd,mc);
+ Assert.assertEquals(abs, expectedAbs, "(" + bd + ").abs(" + mc + ") => " +
+ abs + " != atr " + expectedAbs);
+ }
+ }
+
+ @Test
+ public void negateTests() {
+ BigDecimal [][] testCasesCeiling = {
+ {new BigDecimal("1.3"), new BigDecimal("-1")},
+ {new BigDecimal("-1.3"), new BigDecimal("2")},
+ };
+
+ negateTest(testCasesCeiling, new MathContext(1, RoundingMode.CEILING));
+
+ BigDecimal [][] testCasesFloor = {
+ {new BigDecimal("1.3"), new BigDecimal("-2")},
+ {new BigDecimal("-1.3"), new BigDecimal("1")},
+ };
+
+ negateTest(testCasesFloor, new MathContext(1, RoundingMode.FLOOR));
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/PowTests.java b/ojluni/src/test/java/math/BigDecimal/PowTests.java
new file mode 100644
index 0000000..5cc30cf
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/PowTests.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4916097
+ * @summary Some exponent over/undeflow tests for the pow method
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class PowTests {
+ @Test
+ public void zeroAndOneTests() {
+ BigDecimal[][] testCases = {
+ {BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
+ {BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(1), BigDecimal.valueOf(0, Integer.MAX_VALUE)},
+ {BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(2), BigDecimal.valueOf(0, Integer.MAX_VALUE)},
+ {BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(999999999), BigDecimal.valueOf(0, Integer.MAX_VALUE)},
+
+ {BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
+ {BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(1), BigDecimal.valueOf(0, Integer.MIN_VALUE)},
+ {BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(2), BigDecimal.valueOf(0, Integer.MIN_VALUE)},
+ {BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(999999999), BigDecimal.valueOf(0, Integer.MIN_VALUE)},
+
+ {BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
+ {BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(1), BigDecimal.valueOf(1, Integer.MAX_VALUE)},
+ {BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(2), null}, // overflow
+ {BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(999999999), null}, // overflow
+
+ {BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
+ {BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(1), BigDecimal.valueOf(1, Integer.MIN_VALUE)},
+ {BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(2), null}, // underflow
+ {BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(999999999), null}, // underflow
+ };
+
+ for(BigDecimal[] testCase: testCases) {
+ int exponent = testCase[1].intValueExact();
+ BigDecimal result;
+
+ try{
+ result = testCase[0].pow(exponent);
+ Assert.assertEquals(result, testCase[2], "Unexpected result while raising " +
+ testCase[0] +
+ " to the " + exponent + " power; expected " +
+ testCase[2] + ", got " + result + ".");
+ } catch (ArithmeticException e) {
+ if (testCase[2] != null) {
+ Assert.fail("Unexpected exception while raising " + testCase[0] +
+ " to the " + exponent + " power.");
+
+ }
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/PrecisionTests.java b/ojluni/src/test/java/math/BigDecimal/PrecisionTests.java
new file mode 100644
index 0000000..be48794
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/PrecisionTests.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 1234567
+ * @summary Test that precision() is computed properly.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import static java.math.BigDecimal.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class PrecisionTests {
+ private static BigDecimal NINE = valueOf(9);
+
+ @Test
+ public void testPrecision() {
+ // Smallest and largest values of a given length
+ BigDecimal[] testValues = {
+ valueOf(1), valueOf(9),
+ };
+
+ testPrecision(new BigDecimal(0), 1);
+
+ for(int i = 1; i < 100; i++) {
+ for(BigDecimal bd : testValues) {
+ testPrecision(bd, i);
+ testPrecision(bd.negate(), i);
+ }
+
+ testValues[0] = testValues[0].multiply(TEN);
+ testValues[1] = testValues[1].multiply(TEN).add(NINE);
+ }
+
+ // The following test tries to cover testings for precision of long values
+ BigDecimal[] randomTestValues = {
+ valueOf(2147483648L), // 2^31: 10 digits
+ valueOf(-2147483648L), // -2^31: 10 digits
+ valueOf(98893745455L), // random: 11 digits
+ valueOf(3455436789887L), // random: 13 digits
+ valueOf(140737488355328L), // 2^47: 15 digits
+ valueOf(-140737488355328L), // -2^47: 15 digits
+ valueOf(7564232235739573L), // random: 16 digits
+ valueOf(25335434990002322L), // random: 17 digits
+ valueOf(9223372036854775807L), // 2^63 - 1: 19 digits
+ valueOf(-9223372036854775807L) // -2^63 + 1: 19 digits
+ };
+ // The array below contains the expected precision of the above numbers
+ int[] expectedPrecision = {10, 10, 11, 13, 15, 15, 16, 17, 19, 19};
+ for (int i = 0; i < randomTestValues.length; i++) {
+ testPrecision(randomTestValues[i], expectedPrecision[i]);
+ }
+ }
+
+ private static void testPrecision(BigDecimal bd, int expected) {
+ int precision = bd.precision();
+
+ Assert.assertEquals(precision, expected,
+ String.format("For (%s).precision expected %d, got %d%n", bd, expected, precision));
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/RangeTests.java b/ojluni/src/test/java/math/BigDecimal/RangeTests.java
new file mode 100644
index 0000000..07bcf75
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/RangeTests.java
@@ -0,0 +1,212 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 7036582
+ * @summary Some new tests for the add method and constructor with MathContext.
+ * @run main RangeTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 RangeTests
+ * @author Sergey V. Kuksenko
+ */
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class RangeTests {
+
+ private static void addTest(BigDecimal arg1, BigDecimal arg2, BigDecimal expectedResult) {
+ BigDecimal result = arg1.add(arg2);
+ Assert.assertEquals(result, expectedResult, "Sum:" +
+ arg1 + " + " +
+ arg2 + " == " +
+ result + "; expected " +
+ expectedResult
+ );
+ result = arg2.add(arg1);
+ Assert.assertEquals(result, expectedResult, "Sum:" +
+ arg2 + " + " +
+ arg1 + " == " +
+ result + "; expected " +
+ expectedResult
+ );
+ }
+
+ /*
+ * Test BigDecimal.add(BigDecimal) when values are withing different ranges:
+ * 1. within 32 bits
+ * 2. within 64 bits
+ * 3. outside 64 bits.
+ */
+ @Test
+ public void addBoundaryTest() {
+ addTest(
+ new BigDecimal("85070591730234615847396907784232501249"),
+ BigDecimal.valueOf(0),
+ new BigDecimal("85070591730234615847396907784232501249") );
+ addTest(
+ new BigDecimal("-85070591730234615847396907784232501249"),
+ BigDecimal.valueOf(0),
+ new BigDecimal("-85070591730234615847396907784232501249") );
+ addTest(
+ new BigDecimal("85070591730234615847396907784232501249"),
+ BigDecimal.valueOf(1),
+ new BigDecimal("85070591730234615847396907784232501250") );
+ addTest(
+ new BigDecimal("85070591730234615847396907784232501249"),
+ BigDecimal.valueOf(-1),
+ new BigDecimal("85070591730234615847396907784232501248") );
+ addTest(
+ new BigDecimal("-85070591730234615847396907784232501250"),
+ BigDecimal.valueOf(-1),
+ new BigDecimal("-85070591730234615847396907784232501251") );
+ addTest(
+ new BigDecimal("-85070591730234615847396907784232501249"),
+ BigDecimal.valueOf(1),
+ new BigDecimal("-85070591730234615847396907784232501248") );
+ addTest(
+ new BigDecimal("147573952589676412927"),
+ BigDecimal.valueOf(Integer.MAX_VALUE),
+ new BigDecimal("147573952591823896574") );
+ addTest(
+ new BigDecimal("-147573952589676412927"),
+ BigDecimal.valueOf(Integer.MAX_VALUE),
+ new BigDecimal("-147573952587528929280") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(999),
+ new BigDecimal("79228162514264337593543951334") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(Integer.MAX_VALUE/2),
+ new BigDecimal("79228162514264337594617692158") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(Integer.MIN_VALUE/2),
+ new BigDecimal("79228162514264337592470208511") );
+ addTest(
+ new BigDecimal("-79228162514264337593543950335"),
+ BigDecimal.valueOf(Integer.MAX_VALUE/2),
+ new BigDecimal("-79228162514264337592470208512") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(-(Integer.MIN_VALUE/2)),
+ new BigDecimal("79228162514264337594617692159") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(Long.MAX_VALUE/2),
+ new BigDecimal("79228162518876023611971338238") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(Long.MIN_VALUE/2),
+ new BigDecimal("79228162509652651575116562431") );
+ addTest(
+ new BigDecimal("-79228162514264337593543950335"),
+ BigDecimal.valueOf(Long.MAX_VALUE/2),
+ new BigDecimal("-79228162509652651575116562432") );
+ addTest(
+ new BigDecimal("79228162514264337593543950335"),
+ BigDecimal.valueOf(-(Long.MIN_VALUE/2)),
+ new BigDecimal("79228162518876023611971338239") );
+ addTest(
+ new BigDecimal("-9223372036854775808"),
+ BigDecimal.valueOf(1),
+ new BigDecimal("-9223372036854775807") );
+ addTest(
+ new BigDecimal("-9223372036854775808"),
+ BigDecimal.valueOf(Long.MAX_VALUE/2),
+ new BigDecimal("-4611686018427387905") );
+ addTest(
+ new BigDecimal("9223372036854775808"),
+ BigDecimal.valueOf(-1),
+ new BigDecimal("9223372036854775807") );
+ addTest(
+ new BigDecimal("9223372036854775808"),
+ BigDecimal.valueOf(-Long.MAX_VALUE/2),
+ new BigDecimal("4611686018427387905") );
+ }
+
+ private static void testRoundingFromBigInteger(BigInteger bi, int scale, MathContext mc) {
+ BigDecimal bd1 = new BigDecimal(bi,scale, mc);
+ BigDecimal bd2 = (new BigDecimal(bi,scale)).round(mc);
+ Assert.assertEquals(bd1, bd2, "new BigDecimal(BigInteger,int,MathContext):" +
+ "BigInteger == " +
+ bi + "; scale == " + scale + "; result == " +
+ bd1 + "; expected == " +
+ bd2
+ );
+ }
+
+ @Test
+ public void roundingConstructorTest() {
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 7, MathContext.DECIMAL64);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 0, MathContext.DECIMAL64);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ -7, MathContext.DECIMAL64);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 7, MathContext.DECIMAL128);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 177, MathContext.DECIMAL128);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 177, MathContext.DECIMAL32);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 177, MathContext.UNLIMITED);
+ testRoundingFromBigInteger(
+ new BigInteger("85070591730234615847396907784232501249"),
+ 0, MathContext.UNLIMITED);
+ }
+
+ private static void minLongConstructorTest(MathContext mc) {
+ BigDecimal bd1 = new BigDecimal(Long.MIN_VALUE,mc);
+ BigDecimal bd2 = new BigDecimal(Long.MIN_VALUE).round(mc);
+ Assert.assertEquals(bd1, bd2, "new BigDecimal(long,MathContext):" +
+ "long == " +
+ Long.MIN_VALUE + "; result == " +
+ bd1 + "; expected == " +
+ bd2
+ );
+ }
+
+ @Test
+ public void minLongConstructorTest() {
+ minLongConstructorTest(MathContext.UNLIMITED);
+ minLongConstructorTest(MathContext.DECIMAL32);
+ minLongConstructorTest(MathContext.DECIMAL64);
+ minLongConstructorTest(MathContext.DECIMAL128);
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/RoundingTests.java b/ojluni/src/test/java/math/BigDecimal/RoundingTests.java
new file mode 100644
index 0000000..1b4f258
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/RoundingTests.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6334849
+ * @summary Tests of dropping digits near the scale threshold
+ * @author Joseph D. Darcy
+ */
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class RoundingTests {
+
+ @Test
+ public void roundingTests() {
+ BigDecimal bd1 = BigDecimal.valueOf(11, Integer.MIN_VALUE);
+ BigDecimal bd2 = null;
+ MathContext mc = new MathContext(1);
+ try {
+ bd2 = bd1.round(mc); // should overflow here
+ Assert.fail(String.format("Did not get expected overflow rounding %s to %d digits, got %s%n",
+ bd1, mc.getPrecision(), bd2));
+ } catch(ArithmeticException e) {
+ ; // expected
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/ScaleByPowerOfTenTests.java b/ojluni/src/test/java/math/BigDecimal/ScaleByPowerOfTenTests.java
new file mode 100644
index 0000000..d70dcb0
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/ScaleByPowerOfTenTests.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4899722
+ * @summary Basic tests of scaleByPowerOfTen
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class ScaleByPowerOfTenTests {
+
+ @Test
+ public void testScaleByPowerOfTen() {
+ for (int i = -10; i < 10; i++) {
+ BigDecimal bd = BigDecimal.ONE.scaleByPowerOfTen(i);
+ BigDecimal expected;
+
+ expected = new BigDecimal(BigInteger.ONE, -i);
+ Assert.assertEquals(bd, expected, "Unexpected result " +
+ bd.toString() +
+ "; expected " +
+ expected);
+
+ bd = BigDecimal.ONE.negate().scaleByPowerOfTen(i);
+ expected = new BigDecimal(BigInteger.ONE.negate(), -i);
+ Assert.assertEquals(bd, expected, "Unexpected result " +
+ bd.toString() +
+ "; expected " +
+ expected);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/SerializationTests.java b/ojluni/src/test/java/math/BigDecimal/SerializationTests.java
new file mode 100644
index 0000000..d6b6499
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/SerializationTests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 6177836
+ * @summary Verify BigDecimal objects with collapsed values are serialized properly.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import java.io.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class SerializationTests {
+
+ static void checkSerialForm(BigDecimal bd) throws Exception {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(bd);
+ oos.flush();
+ oos.close();
+ ObjectInputStream ois = new
+ ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
+ BigDecimal tmp = (BigDecimal)ois.readObject();
+
+ if (!bd.equals(tmp) || bd.hashCode() != tmp.hashCode()) {
+ Assert.fail(" original : " + bd +
+ " (hash: 0x" + Integer.toHexString(bd.hashCode()) + ")" +
+ " serialized : " + tmp +
+ " (hash: 0x" + Integer.toHexString(tmp.hashCode()) + ")");
+ }
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ BigDecimal values[] = {
+ BigDecimal.ZERO,
+ BigDecimal.ONE,
+ BigDecimal.TEN,
+ new BigDecimal(0),
+ new BigDecimal(1),
+ new BigDecimal(10),
+ new BigDecimal(Integer.MAX_VALUE),
+ new BigDecimal(Long.MAX_VALUE-1),
+ new BigDecimal(BigInteger.valueOf(1), 1),
+ new BigDecimal(BigInteger.valueOf(100), 50),
+ };
+
+ for(BigDecimal value : values) {
+ checkSerialForm(value);
+ checkSerialForm(value.negate());
+ }
+
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/SquareRootTests.java b/ojluni/src/test/java/math/BigDecimal/SquareRootTests.java
new file mode 100644
index 0000000..27b1013
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/SquareRootTests.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4851777
+ * @summary Tests of BigDecimal.sqrt().
+ */
+
+import java.math.*;
+import java.util.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class SquareRootTests {
+
+ @Test
+ public void negativeTests() {
+ for (long i = -10; i < 0; i++) {
+ for (int j = -5; j < 5; j++) {
+ try {
+ BigDecimal input = BigDecimal.valueOf(i, j);
+ BigDecimal result = input.sqrt(MathContext.DECIMAL64);
+ Assert.fail("Unexpected sqrt of negative: (" +
+ input + ").sqrt() = " + result );
+ } catch (ArithmeticException e) {
+ ; // Expected
+ }
+ }
+ }
+ }
+
+ @Test
+ public void zeroTests() {
+ for (int i = -100; i < 100; i++) {
+ BigDecimal expected = BigDecimal.valueOf(0L, i/2);
+ // These results are independent of rounding mode
+ compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.UNLIMITED),
+ expected, true, "zeros");
+
+ compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.DECIMAL64),
+ expected, true, "zeros");
+ }
+ }
+
+ /**
+ * sqrt(10^2N) is 10^N
+ * Both numerical value and representation should be verified
+ */
+ @Test
+ public void evenPowersOfTenTests() {
+ MathContext oneDigitExactly = new MathContext(1, RoundingMode.UNNECESSARY);
+
+ for (int scale = -100; scale <= 100; scale++) {
+ BigDecimal testValue = BigDecimal.valueOf(1, 2*scale);
+ BigDecimal expectedNumericalResult = BigDecimal.valueOf(1, scale);
+
+ BigDecimal result;
+
+
+ equalNumerically(expectedNumericalResult,
+ result = testValue.sqrt(MathContext.DECIMAL64),
+ "Even powers of 10, DECIMAL64");
+
+ // Can round to one digit of precision exactly
+ equalNumerically(expectedNumericalResult,
+ result = testValue.sqrt(oneDigitExactly),
+ "even powers of 10, 1 digit");
+ if (result.precision() > 1) {
+ Assert.fail("Excess precision for " + result);
+ }
+ // If rounding to more than one digit, do precision / scale checking...
+ }
+ }
+
+ @Test
+ public void squareRootTwoTests() {
+ BigDecimal TWO = new BigDecimal(2);
+
+ // Square root of 2 truncated to 65 digits
+ BigDecimal highPrecisionRoot2 =
+ new BigDecimal("1.41421356237309504880168872420969807856967187537694807317667973799");
+
+
+ RoundingMode[] modes = {
+ RoundingMode.UP, RoundingMode.DOWN,
+ RoundingMode.CEILING, RoundingMode.FLOOR,
+ RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN
+ };
+
+ // For each interesting rounding mode, for precisions 1 to, say
+ // 63 numerically compare TWO.sqrt(mc) to
+ // highPrecisionRoot2.round(mc)
+
+ for (RoundingMode mode : modes) {
+ for (int precision = 1; precision < 63; precision++) {
+ MathContext mc = new MathContext(precision, mode);
+ BigDecimal expected = highPrecisionRoot2.round(mc);
+ BigDecimal computed = TWO.sqrt(mc);
+
+ equalNumerically(expected, computed, "sqrt(2)");
+ }
+ }
+ }
+
+ @Test
+ public void lowPrecisionPerfectSquares() {
+ // For 5^2 through 9^2, if the input is rounded to one digit
+ // first before the root is computed, the wrong answer will
+ // result. Verify results and scale for different rounding
+ // modes and precisions.
+ long[][] squaresWithOneDigitRoot = {{ 4, 2},
+ { 9, 3},
+ {25, 5},
+ {36, 6},
+ {49, 7},
+ {64, 8},
+ {81, 9}};
+
+ for (long[] squareAndRoot : squaresWithOneDigitRoot) {
+ BigDecimal square = new BigDecimal(squareAndRoot[0]);
+ BigDecimal expected = new BigDecimal(squareAndRoot[1]);
+
+ for (int scale = 0; scale <= 4; scale++) {
+ BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY);
+ int expectedScale = scale/2;
+ for (int precision = 0; precision <= 5; precision++) {
+ for (RoundingMode rm : RoundingMode.values()) {
+ MathContext mc = new MathContext(precision, rm);
+ BigDecimal computedRoot = scaledSquare.sqrt(mc);
+
+ equalNumerically(expected, computedRoot, "simple squares");
+
+ int computedScale = computedRoot.scale();
+ if (precision >= expectedScale + 1 && computedScale != expectedScale) {
+ Assert.fail(String.format("%s\tprecision=%d\trm=%s%n",
+ computedRoot, precision, rm) +
+ String.format("\t%s does not have expected scale of %d%n.",
+ computedRoot, expectedScale));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static void compare(BigDecimal a, BigDecimal b, boolean expected, String prefix) {
+ boolean result = a.equals(b);
+ Assert.assertEquals(result, expected, "Testing " + prefix +
+ "(" + a + ").compareTo(" + b + ") => " + result +
+ "\n\tExpected " + expected);
+ }
+
+ private static void equalNumerically(BigDecimal a, BigDecimal b, String prefix) {
+ compareNumerically(a, b, 0, prefix);
+ }
+
+ private static void compareNumerically(BigDecimal a, BigDecimal b,
+ int expected, String prefix) {
+ int result = a.compareTo(b);
+ Assert.assertEquals(result, expected, "Testing " + prefix +
+ "(" + a + ").compareTo(" + b + ") => " + result +
+ "\n\tExpected " + expected);
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/StringConstructor.java b/ojluni/src/test/java/math/BigDecimal/StringConstructor.java
new file mode 100644
index 0000000..a4f6dc6
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/StringConstructor.java
@@ -0,0 +1,161 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main StringConstructor
+ * @bug 4103117 4331084 4488017 4490929 6255285 6268365 8074460 8078672
+ * @summary Tests the BigDecimal string constructor (use -Dseed=X to set PRNG seed).
+ * @key randomness
+ */
+
+import java.math.*;
+import java.util.Random;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class StringConstructor {
+
+ @Test
+ public void testBadStrings() {
+ constructWithError("");
+ constructWithError("+");
+ constructWithError("-");
+ constructWithError("+e");
+ constructWithError("-e");
+ constructWithError("e+");
+ constructWithError("1.-0");
+ constructWithError(".-123");
+ constructWithError("-");
+ constructWithError("--1.1");
+ constructWithError("-+1.1");
+ constructWithError("+-1.1");
+ constructWithError("1-.1");
+ constructWithError("1+.1");
+ constructWithError("1.111+1");
+ constructWithError("1.111-1");
+ constructWithError("11.e+");
+ constructWithError("11.e-");
+ constructWithError("11.e+-");
+ constructWithError("11.e-+");
+ constructWithError("11.e-+1");
+ constructWithError("11.e+-1");
+
+ // Range checks
+ constructWithError("1e" + Integer.MIN_VALUE);
+ constructWithError("10e" + Integer.MIN_VALUE);
+ constructWithError("0.01e" + Integer.MIN_VALUE);
+ constructWithError("1e" + ((long) Integer.MIN_VALUE - 1));
+ constructWithError("1e" + ((long) Integer.MAX_VALUE + 1));
+ }
+
+ @Test
+ public void testRoundtrip() {
+ // Roundtrip tests
+ Random random = new Random();
+ for (int i=0; i<100; i++) {
+ int size = random.nextInt(100) + 1;
+ BigInteger bi = new BigInteger(size, random);
+ if (random.nextBoolean())
+ bi = bi.negate();
+ int decimalLength = bi.toString().length();
+ int scale = random.nextInt(decimalLength);
+ BigDecimal bd = new BigDecimal(bi, scale);
+ String bdString = bd.toString();
+ BigDecimal bdDoppel = new BigDecimal(bdString);
+ Assert.assertEquals(bd, bdDoppel, "bd string: scale: " + bd.scale() +
+ "\t" + bdString + "\nbd doppel: scale: " + bdDoppel.scale() +
+ "\t" + bdDoppel.toString());
+ }
+ }
+
+ /*
+ * Verify precision is set properly if the significand has
+ * non-ASCII leading zeros.
+ */
+ @Test
+ public void nonAsciiZeroTest() {
+ String[] values = {
+ "00004e5",
+ "\u0660\u0660\u0660\u06604e5",
+ };
+
+ BigDecimal expected = new BigDecimal("4e5");
+
+ for(String s : values) {
+ BigDecimal tmp = new BigDecimal(s);
+ Assert.assertFalse(! expected.equals(tmp) || tmp.precision() != 1,
+ "Bad conversion of " + s + "got " +
+ tmp + "precision = " + tmp.precision());
+ }
+
+ }
+
+ @Test
+ public void testLeadingExponentZeroTest() {
+ BigDecimal twelve = new BigDecimal("12");
+ BigDecimal onePointTwo = new BigDecimal("1.2");
+
+ String start = "1.2e0";
+ String end = "1";
+ String middle = "";
+
+ // Test with more excess zeros than the largest number of
+ // decimal digits needed to represent a long
+ int limit = ((int)Math.log10(Long.MAX_VALUE)) + 6;
+ for(int i = 0; i < limit; i++, middle += "0") {
+ String t1 = start + middle;
+ String t2 = t1 + end;
+
+ testString(t1, onePointTwo);
+ testString(t2, twelve);
+ }
+ }
+
+ private static void testString(String s, BigDecimal expected) {
+ testString0(s, expected);
+ testString0(switchZero(s), expected);
+ }
+
+ private static void testString0(String s, BigDecimal expected) {
+ Assert.assertEquals(new BigDecimal(s), expected, s + " is not equal to " + expected);
+ }
+
+ private static String switchZero(String s) {
+ return s.replace('0', '\u0660'); // Arabic-Indic zero
+ }
+
+ private static void constructWithError(String badString) {
+ try {
+ BigDecimal d = new BigDecimal(badString);
+ Assert.fail(badString + " accepted");
+ } catch(NumberFormatException e) {
+ // expected
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/StrippingZerosTest.java b/ojluni/src/test/java/math/BigDecimal/StrippingZerosTest.java
new file mode 100644
index 0000000..93084fd
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/StrippingZerosTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4108852
+ * @summary A few tests of stripTrailingZeros
+ * @run main StrippingZerosTest
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 StrippingZerosTest
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class StrippingZerosTest {
+
+ @Test
+ public void testStrippingZeros() {
+ BigDecimal [][] testCases = {
+ {new BigDecimal("1.00000"), new BigDecimal("1")},
+ {new BigDecimal("1.000"), new BigDecimal("1")},
+ {new BigDecimal("1"), new BigDecimal("1")},
+ {new BigDecimal("0.1234"), new BigDecimal("0.1234")},
+ {new BigDecimal("0.12340"), new BigDecimal("0.1234")},
+ {new BigDecimal("0.12340000000"), new BigDecimal("0.1234")},
+ {new BigDecimal("1234.5678"), new BigDecimal("1234.5678")},
+ {new BigDecimal("1234.56780"), new BigDecimal("1234.5678")},
+ {new BigDecimal("1234.567800000"), new BigDecimal("1234.5678")},
+ {new BigDecimal("0"), new BigDecimal("0")},
+ {new BigDecimal("0e2"), BigDecimal.ZERO},
+ {new BigDecimal("0e-2"), BigDecimal.ZERO},
+ {new BigDecimal("0e42"), BigDecimal.ZERO},
+ {new BigDecimal("+0e42"), BigDecimal.ZERO},
+ {new BigDecimal("-0e42"), BigDecimal.ZERO},
+ {new BigDecimal("0e-42"), BigDecimal.ZERO},
+ {new BigDecimal("+0e-42"), BigDecimal.ZERO},
+ {new BigDecimal("-0e-42"), BigDecimal.ZERO},
+ {new BigDecimal("0e-2"), BigDecimal.ZERO},
+ {new BigDecimal("0e100"), BigDecimal.ZERO},
+ {new BigDecimal("0e-100"), BigDecimal.ZERO},
+ {new BigDecimal("10"), new BigDecimal("1e1")},
+ {new BigDecimal("20"), new BigDecimal("2e1")},
+ {new BigDecimal("100"), new BigDecimal("1e2")},
+ {new BigDecimal("1000000000"), new BigDecimal("1e9")},
+ {new BigDecimal("100000000e1"), new BigDecimal("1e9")},
+ {new BigDecimal("10000000e2"), new BigDecimal("1e9")},
+ {new BigDecimal("1000000e3"), new BigDecimal("1e9")},
+ {new BigDecimal("100000e4"), new BigDecimal("1e9")},
+ // BD value which larger than Long.MaxValue
+ {new BigDecimal("1.0000000000000000000000000000"), new BigDecimal("1")},
+ {new BigDecimal("-1.0000000000000000000000000000"), new BigDecimal("-1")},
+ {new BigDecimal("1.00000000000000000000000000001"), new BigDecimal("1.00000000000000000000000000001")},
+ {new BigDecimal("1000000000000000000000000000000e4"), new BigDecimal("1e34")},
+ };
+
+ for(int i = 0; i < testCases.length; i++) {
+
+ BigDecimal stripped = testCases[i][0].stripTrailingZeros();
+ Assert.assertEquals(stripped, testCases[i][1],
+ "For input " + testCases[i][0].toString() +
+ " did not received expected result " +
+ testCases[i][1].toString() + ", got " +
+ testCases[i][0].stripTrailingZeros());
+
+ testCases[i][0] = testCases[i][0].negate();
+ testCases[i][1] = testCases[i][1].negate();
+
+ stripped = testCases[i][0].stripTrailingZeros();
+ Assert.assertEquals(stripped, testCases[i][1],
+ "For input " + testCases[i][0].toString() +
+ " did not received expected result " +
+ testCases[i][1].toString() + ", got " +
+ testCases[i][0].stripTrailingZeros());
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/ToPlainStringTests.java b/ojluni/src/test/java/math/BigDecimal/ToPlainStringTests.java
new file mode 100644
index 0000000..54a70af
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/ToPlainStringTests.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004, 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.
+ *
+ * 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 test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4984872
+ * @summary Basic tests of toPlainString method
+ * @run main ToPlainStringTests
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 ToPlainStringTests
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class ToPlainStringTests {
+
+ @Test
+ public void testToPlainString() {
+ String [][] testCases = {
+ {"0", "0"},
+ {"1", "1"},
+ {"10", "10"},
+ {"2e1", "20"},
+ {"3e2", "300"},
+ {"4e3", "4000"},
+ {"5e4", "50000"},
+ {"6e5", "600000"},
+ {"7e6", "7000000"},
+ {"8e7", "80000000"},
+ {"9e8", "900000000"},
+ {"1e9", "1000000000"},
+
+ {".0", "0.0"},
+ {".1", "0.1"},
+ {".10", "0.10"},
+ {"1e-1", "0.1"},
+ {"1e-1", "0.1"},
+ {"2e-2", "0.02"},
+ {"3e-3", "0.003"},
+ {"4e-4", "0.0004"},
+ {"5e-5", "0.00005"},
+ {"6e-6", "0.000006"},
+ {"7e-7", "0.0000007"},
+ {"8e-8", "0.00000008"},
+ {"9e-9", "0.000000009"},
+ {"9000e-12", "0.000000009000"},
+
+ {"9000e-22", "0.0000000000000000009000"},
+ {"12345678901234567890", "12345678901234567890"},
+ {"12345678901234567890e22", "123456789012345678900000000000000000000000"},
+ {"12345678901234567890e-22", "0.0012345678901234567890"},
+ };
+
+ for(String[] testCase: testCases) {
+ BigDecimal bd = new BigDecimal(testCase[0]);
+ String s;
+
+ s = bd.toPlainString();
+ Assert.assertEquals(s, testCase[1],
+ "Unexpected plain result ``" + s + "'' from BigDecimal " + bd);
+
+ bd = new BigDecimal("-"+testCase[0]);
+ s = bd.toPlainString();
+ Assert.assertFalse(bd.signum()!=0 && !s.equals("-"+testCase[1]),
+ "Unexpected plain result ``" + s + "'' from BigDecimal " + bd);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigDecimal/ZeroScalingTests.java b/ojluni/src/test/java/math/BigDecimal/ZeroScalingTests.java
new file mode 100644
index 0000000..742abc3
--- /dev/null
+++ b/ojluni/src/test/java/math/BigDecimal/ZeroScalingTests.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigDecimal;
+
+/*
+ * @test
+ * @bug 4902952 4905407 4916149 8057793
+ * @summary Tests that the scale of zero is propagated properly and has the
+ * proper effect and that setting the scale to zero does not mutate the
+ * BigDecimal.
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+import java.util.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error counting with asserts.
+public class ZeroScalingTests {
+
+ static MathContext longEnough = new MathContext(50, RoundingMode.UNNECESSARY);
+
+ static BigDecimal[] zeros = new BigDecimal[23];
+ static {
+ for(int i = 0; i < 21; i++) {
+ zeros[i] = new BigDecimal(BigInteger.ZERO, i-10);
+ }
+ zeros[21] = new BigDecimal(BigInteger.ZERO, Integer.MIN_VALUE);
+ zeros[22] = new BigDecimal(BigInteger.ZERO, Integer.MAX_VALUE);
+ }
+
+ static BigDecimal element = BigDecimal.valueOf(100, -2);
+
+ static MathContext[] contexts = {
+ new MathContext(0, RoundingMode.UNNECESSARY),
+ new MathContext(100, RoundingMode.UNNECESSARY),
+ new MathContext(5, RoundingMode.UNNECESSARY),
+ new MathContext(4, RoundingMode.UNNECESSARY),
+ new MathContext(3, RoundingMode.UNNECESSARY),
+ new MathContext(2, RoundingMode.UNNECESSARY),
+ new MathContext(1, RoundingMode.UNNECESSARY),
+ };
+
+
+ @Test
+ public void addTests() {
+ for(BigDecimal zero1: zeros) {
+ for(BigDecimal zero2: zeros) {
+ BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+ Math.max(zero1.scale(), zero2.scale()));
+ BigDecimal result = zero1.add(zero2);
+
+ Assert.assertEquals(result, expected, "For classic exact add, expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero1.add(zero2, MathContext.UNLIMITED);
+ Assert.assertEquals(result, expected, "For UNLIMITED math context add," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero1.add(zero2, longEnough);
+ Assert.assertEquals(result, expected, "For longEnough math context add," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+ }
+ }
+
+ // Test effect of adding zero to a nonzero value.
+ for (MathContext mc: contexts) {
+ for (BigDecimal zero: zeros) {
+ if (Math.abs((long)zero.scale()) < 100 ) {
+
+ int preferredScale = Math.max(zero.scale(), element.scale());
+ if (mc.getPrecision() != 0) {
+ if (preferredScale < -4 )
+ preferredScale = -4;
+ else if (preferredScale > -(5 - mc.getPrecision())) {
+ preferredScale = -(5 - mc.getPrecision());
+ }
+ }
+
+ BigDecimal result = element.add(zero, mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+
+ result = zero.add(element, mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+
+ result = element.negate().add(zero, mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element.negate()) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+
+ result = zero.add(element.negate(), mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element.negate()) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void subtractTests() {
+ for(BigDecimal zero1: zeros) {
+ for(BigDecimal zero2: zeros) {
+ BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+ Math.max(zero1.scale(), zero2.scale()));
+ BigDecimal result = zero1.subtract(zero2);
+
+ Assert.assertEquals(result, expected,
+ "For classic exact subtract, expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero1.subtract(zero2, MathContext.UNLIMITED);
+ Assert.assertEquals(result, expected, "For UNLIMITED math context subtract," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero1.subtract(zero2, longEnough);
+ Assert.assertEquals(result, expected, "For longEnough math context subtract," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+ }
+ }
+
+
+ // Test effect of adding zero to a nonzero value.
+ for (MathContext mc: contexts) {
+ for (BigDecimal zero: zeros) {
+ if (Math.abs((long)zero.scale()) < 100 ) {
+
+ int preferredScale = Math.max(zero.scale(), element.scale());
+ if (mc.getPrecision() != 0) {
+ if (preferredScale < -4 )
+ preferredScale = -4;
+ else if (preferredScale > -(5 - mc.getPrecision())) {
+ preferredScale = -(5 - mc.getPrecision());
+ }
+ }
+
+ BigDecimal result = element.subtract(zero, mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+
+ result = zero.subtract(element, mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element.negate()) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+
+ result = element.negate().subtract(zero, mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element.negate()) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+
+ result = zero.subtract(element.negate(), mc);
+ Assert.assertFalse(result.scale() != preferredScale ||
+ result.compareTo(element) != 0,
+ "Expected scale " + preferredScale +
+ " result scale was " + result.scale() +
+ " ; value was " + result);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void multiplyTests() {
+ BigDecimal[] ones = {
+ BigDecimal.valueOf(1, 0),
+ BigDecimal.valueOf(10, 1),
+ BigDecimal.valueOf(1000, 3),
+ BigDecimal.valueOf(100000000, 8),
+ };
+
+ List<BigDecimal> values = new LinkedList<BigDecimal>();
+ values.addAll(Arrays.asList(zeros));
+ values.addAll(Arrays.asList(ones));
+
+ for(BigDecimal zero1: zeros) {
+ for(BigDecimal value: values) {
+ BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+ (int)Math.min(Math.max((long)zero1.scale()+value.scale(),
+ Integer.MIN_VALUE ),
+ Integer.MAX_VALUE ) );
+ BigDecimal result = zero1.multiply(value);
+
+ Assert.assertEquals(result, expected,
+ "For classic exact multiply, expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero1.multiply(value, MathContext.UNLIMITED);
+ Assert.assertEquals(result, expected, "For UNLIMITED math context multiply," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero1.multiply(value, longEnough);
+ Assert.assertEquals(result, expected, "For longEnough math context multiply," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+ }
+ }
+ }
+
+ @Test
+ public void divideTests() {
+ BigDecimal [] ones = {
+ BigDecimal.valueOf(1, 0),
+ BigDecimal.valueOf(10, -1),
+ BigDecimal.valueOf(100, -2),
+ BigDecimal.valueOf(1000, -3),
+ BigDecimal.valueOf(1000000, -5),
+ };
+
+ for(BigDecimal one: ones) {
+ for(BigDecimal zero: zeros) {
+ BigDecimal expected = new BigDecimal(BigInteger.ZERO,
+ (int)Math.min(Math.max((long)zero.scale() - one.scale(),
+ Integer.MIN_VALUE ),
+ Integer.MAX_VALUE ) );
+ BigDecimal result = zero.divide(one);
+
+ Assert.assertEquals(result, expected, "For classic exact divide, expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero.divide(one, MathContext.UNLIMITED);
+ Assert.assertEquals(result, expected, "For UNLIMITED math context divide," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+
+ result = zero.divide(one, longEnough);
+ Assert.assertEquals(result, expected, "For longEnough math context divide," +
+ " expected scale of " +
+ expected.scale() + "; got " +
+ result.scale() + ".");
+ }
+ }
+ }
+
+ @Test
+ public void setScaleTests() {
+ int[] scales = {
+ Integer.MIN_VALUE,
+ Integer.MIN_VALUE+1,
+ -10000000,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 10,
+ 10000000,
+ Integer.MAX_VALUE-1,
+ Integer.MAX_VALUE
+ };
+
+ for(BigDecimal zero: zeros) {
+ for(int scale: scales) {
+ try {
+ BigDecimal bd = zero.setScale(scale);
+ }
+ catch (ArithmeticException e) {
+ Assert.fail("Exception when trying to set a scale of " + scale + " on " + zero);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void toEngineeringStringTests() {
+ String [][] testCases = {
+ {"0E+10", "0.00E+12"},
+ {"0E+9", "0E+9"},
+ {"0E+8", "0.0E+9"},
+ {"0E+7", "0.00E+9"},
+
+ {"0E-10", "0.0E-9"},
+ {"0E-9", "0E-9"},
+ {"0E-8", "0.00E-6"},
+ {"0E-7", "0.0E-6"},
+ };
+
+ for(String[] testCase: testCases) {
+ BigDecimal bd = new BigDecimal(testCase[0]);
+ String result = bd.toEngineeringString();
+
+ Assert.assertFalse(!result.equals(testCase[1]) || !bd.equals(new BigDecimal(result)),
+ "From input ``" + testCase[0] + ",'' " +
+ " bad engineering string output ``" + result +
+ "''; expected ``" + testCase[1] + ".''");
+ }
+ }
+
+ @Test
+ public void ulpTests() {
+ for(BigDecimal zero: zeros) {
+ BigDecimal result;
+ BigDecimal expected = BigDecimal.valueOf(1, zero.scale());
+
+ result = zero.ulp();
+ Assert.assertEquals(result, expected, "Unexpected ulp value for zero value " +
+ zero + "; expected " + expected +
+ ", got " + result);
+ }
+ }
+
+ @Test
+ public void setScaleDoesNotMutateTest() {
+ BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689"
+ + ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704");
+
+ Assert.assertEquals(total.setScale(0, RoundingMode.DOWN),
+ total.setScale(0, RoundingMode.DOWN));
+ }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/BigIntegerTest.java b/ojluni/src/test/java/math/BigInteger/BigIntegerTest.java
new file mode 100644
index 0000000..04bc7cf
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/BigIntegerTest.java
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (c) 1998, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main BigIntegerTest
+ * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027
+ * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed)
+ * @run main/timeout=400 BigIntegerTest
+ * @author madbot
+ * @key randomness
+ */
+package test.java.math.BigInteger;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Random;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * This is a simple test class created to ensure that the results
+ * generated by BigInteger adhere to certain identities. Passing
+ * this test is a strong assurance that the BigInteger operations
+ * are working correctly.
+ *
+ * Four arguments may be specified which give the number of
+ * decimal digits you desire in the four batches of test numbers.
+ *
+ * The tests are performed on arrays of random numbers which are
+ * generated by a Random class as well as special cases which
+ * throw in boundary numbers such as 0, 1, maximum sized, etc.
+ *
+ */
+
+// Android-changed: Replace error counting with asserts.
+public class BigIntegerTest {
+ //
+ // Bit large number thresholds based on the int thresholds
+ // defined in BigInteger itself:
+ //
+ // KARATSUBA_THRESHOLD = 80 ints = 2560 bits
+ // TOOM_COOK_THRESHOLD = 240 ints = 7680 bits
+ // KARATSUBA_SQUARE_THRESHOLD = 128 ints = 4096 bits
+ // TOOM_COOK_SQUARE_THRESHOLD = 216 ints = 6912 bits
+ //
+ // SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20 ints = 640 bits
+ //
+ // BURNIKEL_ZIEGLER_THRESHOLD = 80 ints = 2560 bits
+ //
+ static final int BITS_KARATSUBA = 2560;
+ static final int BITS_TOOM_COOK = 7680;
+ static final int BITS_KARATSUBA_SQUARE = 4096;
+ static final int BITS_TOOM_COOK_SQUARE = 6912;
+ static final int BITS_SCHOENHAGE_BASE = 640;
+ static final int BITS_BURNIKEL_ZIEGLER = 2560;
+ static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280;
+
+ static final int ORDER_SMALL = 60;
+ static final int ORDER_MEDIUM = 100;
+ // #bits for testing Karatsuba
+ static final int ORDER_KARATSUBA = 2760;
+ // #bits for testing Toom-Cook and Burnikel-Ziegler
+ static final int ORDER_TOOM_COOK = 8000;
+ // #bits for testing Karatsuba squaring
+ static final int ORDER_KARATSUBA_SQUARE = 4200;
+ // #bits for testing Toom-Cook squaring
+ static final int ORDER_TOOM_COOK_SQUARE = 7000;
+
+ static final int SIZE = 1000; // numbers per batch
+
+ private static Random random = new Random();
+
+ static boolean failure = false;
+
+ private static void constructor() {
+ // --- guard condition tests for array indexing ---
+
+ int arrayLength = 23;
+ int halfLength = arrayLength/2;
+ byte[] array = new byte[arrayLength];
+ random.nextBytes(array);
+
+ int[][] offLen = new int[][] { // offset, length, num exceptions
+ {-1, arrayLength, 1}, // negative offset
+ {0, arrayLength, 0}, // OK
+ {1, arrayLength, 1}, // length overflow
+ {arrayLength - 1, 1, 0}, // OK
+ {arrayLength, 1, 1}, // offset overflow
+ {0, -1, 1}, // negative length
+ {halfLength, arrayLength - halfLength + 1, 1} // length overflow
+ };
+
+ // two's complement
+ for (int[] ol : offLen) {
+ try {
+ BigInteger bi = new BigInteger(array, ol[0], ol[1]);
+ if (ol[2] == 1) {
+ Assert.fail("IndexOutOfBoundsException did not occur for "
+ + " two's complement constructor with parameters offset "
+ + ol[0] + " and length " + ol[1]);
+ }
+ } catch (IndexOutOfBoundsException e) {
+ if (ol[2] == 0) {
+ Assert.fail("Unexpected IndexOutOfBoundsException did occur for "
+ + " two's complement constructor with parameters offset "
+ + ol[0] + " and length " + ol[1]);
+ }
+ }
+ }
+
+ // sign-magnitude
+ for (int[] ol : offLen) {
+ try {
+ BigInteger bi = new BigInteger(1, array, ol[0], ol[1]);
+ if (ol[2] == 1) {
+ Assert.fail("IndexOutOfBoundsException did not occur for "
+ + " sign-magnitude constructor with parameters offset "
+ + ol[0] + " and length " + ol[1]);
+ }
+ } catch (IndexOutOfBoundsException e) {
+ if (ol[2] == 0) {
+ Assert.fail("Unexpected IndexOutOfBoundsException did occur for "
+ + " two's complement constructor with parameters offset "
+ + ol[0] + " and length " + ol[1]);
+ }
+ }
+ }
+
+ // --- tests for creation of zero-valued BigIntegers ---
+
+ byte[] magZeroLength = new byte[0];
+ for (int signum = -1; signum <= 1; signum++) {
+ BigInteger bi = new BigInteger(signum, magZeroLength);
+ Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0,
+ "A: Zero length BigInteger != 0 for signum " + signum);
+ }
+
+ for (int signum = -1; signum <= 1; signum++) {
+ BigInteger bi = new BigInteger(signum, magZeroLength, 0, 0);
+ Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0,
+ "B: Zero length BigInteger != 0 for signum " + signum);
+ }
+
+ byte[] magNonZeroLength = new byte[42];
+ random.nextBytes(magNonZeroLength);
+ for (int signum = -1; signum <= 1; signum++) {
+ BigInteger bi = new BigInteger(signum, magNonZeroLength, 0, 0);
+ Assert.assertEquals(bi.compareTo(BigInteger.ZERO), 0,
+ "C: Zero length BigInteger != 0 for signum " + signum);
+ }
+
+ // --- tests for accurate creation of non-zero BigIntegers ---
+
+ for (int i = 0; i < SIZE; i++) {
+ // create reference value via a different code path from those tested
+ BigInteger reference = new BigInteger(2 + random.nextInt(336), 4, random);
+
+ byte[] refArray = reference.toByteArray();
+ int refLen = refArray.length;
+ int factor = random.nextInt(5);
+ int objLen = refArray.length + factor*random.nextInt(refArray.length) + 1;
+ int offset = random.nextInt(objLen - refLen);
+ byte[] objArray = new byte[objLen];
+ System.arraycopy(refArray, 0, objArray, offset, refLen);
+
+ BigInteger twosComp = new BigInteger(objArray, offset, refLen);
+ Assert.assertEquals(twosComp.compareTo(reference), 0,
+ "Two's-complement BigInteger not equal for offset " +
+ offset + " and length " + refLen);
+
+ boolean isNegative = random.nextBoolean();
+ BigInteger signMag = new BigInteger(isNegative ? -1 : 1, objArray, offset, refLen);
+ Assert.assertEquals(signMag.compareTo(isNegative ? reference.negate() : reference), 0,
+ "Sign-magnitude BigInteger not equal for offset " +
+ offset + " and length " + refLen);
+ }
+ }
+
+ private static void pow(int order) {
+ for (int i=0; i<SIZE; i++) {
+ // Test identity x^power == x*x*x ... *x
+ int power = random.nextInt(6) + 2;
+ BigInteger x = fetchNumber(order);
+ BigInteger y = x.pow(power);
+ BigInteger z = x;
+
+ for (int j=1; j<power; j++)
+ z = z.multiply(x);
+
+ Assert.assertEquals(y, z);
+ }
+ }
+
+ private static void square(int order) {
+ for (int i=0; i<SIZE; i++) {
+ // Test identity x^2 == x*x
+ BigInteger x = fetchNumber(order);
+ BigInteger xx = x.multiply(x);
+ BigInteger x2 = x.pow(2);
+
+ Assert.assertEquals(x2, xx);
+ }
+ }
+
+ private static void checkResult(BigInteger expected, BigInteger actual, String failureMessage) {
+ Assert.assertEquals(expected.compareTo(actual), 0,
+ failureMessage + " - expected: " + expected + ", actual: " + actual);
+ }
+
+ private static void squareRootSmall() {
+ // A negative value should cause an exception.
+ BigInteger n = BigInteger.ONE.negate();
+ BigInteger s;
+ try {
+ s = n.sqrt();
+ // If sqrt() does not throw an exception that is a failure.
+ Assert.fail("sqrt() of negative number did not throw an exception");
+ } catch (ArithmeticException expected) {
+ // A negative value should cause an exception and is not a failure.
+ }
+
+ // A zero value should return BigInteger.ZERO.
+ checkResult(BigInteger.ZERO, BigInteger.ZERO.sqrt(), "sqrt(0) != BigInteger.ZERO");
+
+ // 1 <= value < 4 should return BigInteger.ONE.
+ long[] smalls = new long[] {1, 2, 3};
+ for (long small : smalls) {
+ checkResult(BigInteger.ONE, BigInteger.valueOf(small).sqrt(), "sqrt("+small+") != 1");
+ }
+ }
+
+ private static void squareRoot() {
+ squareRootSmall();
+
+
+ Function<BigInteger, Void> f = (n) -> {
+ // square root of n^2 -> n
+ BigInteger n2 = n.pow(2);
+ checkResult(n, n2.sqrt(), "sqrt() n^2 -> n");
+
+ // square root of n^2 + 1 -> n
+ BigInteger n2up = n2.add(BigInteger.ONE);
+ checkResult(n, n2up.sqrt(), "sqrt() n^2 + 1 -> n");
+
+ // square root of (n + 1)^2 - 1 -> n
+ BigInteger up = n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE);
+ checkResult(n, up.sqrt(), "sqrt() (n + 1)^2 - 1 -> n");
+
+ // sqrt(n)^2 <= n
+ BigInteger s = n.sqrt();
+ Assert.assertFalse(s.multiply(s).compareTo(n) > 0,
+ "sqrt(n)^2 > n for n = " + n);
+
+ // (sqrt(n) + 1)^2 > n
+ Assert.assertFalse(s.add(BigInteger.ONE).pow(2).compareTo(n) <= 0,
+ "(sqrt(n) + 1)^2 <= n for n = " + n);
+ return null;
+ };
+
+ Stream.Builder<BigInteger> sb = Stream.builder();
+ int maxExponent = Double.MAX_EXPONENT + 1;
+ for (int i = 1; i <= maxExponent; i++) {
+ BigInteger p2 = BigInteger.ONE.shiftLeft(i);
+ sb.add(p2.subtract(BigInteger.ONE));
+ sb.add(p2);
+ sb.add(p2.add(BigInteger.ONE));
+ }
+ sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger());
+ sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE));
+ // "squareRoot for 2^N and 2^N - 1, 1 <= N <= Double.MAX_EXPONENT"
+ sb.build().map(f).collect(Collectors.toList());
+
+ IntStream ints = random.ints(SIZE, 4, Integer.MAX_VALUE);
+ ints.mapToObj(BigInteger::valueOf).map(f).collect(Collectors.toList());
+
+ LongStream longs = random.longs(SIZE, (long)Integer.MAX_VALUE + 1L,
+ Long.MAX_VALUE);
+ longs.mapToObj(BigInteger::valueOf).map(f).collect(Collectors.toList());
+
+ DoubleStream doubles = random.doubles(SIZE,
+ (double) Long.MAX_VALUE + 1.0, Math.sqrt(Double.MAX_VALUE));
+ doubles.mapToObj(x -> BigDecimal.valueOf(x).toBigInteger()).map(f).collect(Collectors.toList());
+ }
+
+ private static void squareRootAndRemainder() {
+ Function<BigInteger, Void> g = (n) -> {
+ BigInteger n2 = n.pow(2);
+
+ // square root of n^2 -> n
+ BigInteger[] actual = n2.sqrtAndRemainder();
+ checkResult(n, actual[0], "sqrtAndRemainder()[0]");
+ checkResult(BigInteger.ZERO, actual[1], "sqrtAndRemainder()[1]");
+
+ // square root of n^2 + 1 -> n
+ BigInteger n2up = n2.add(BigInteger.ONE);
+ actual = n2up.sqrtAndRemainder();
+ checkResult(n, actual[0], "sqrtAndRemainder()[0]");
+ checkResult(BigInteger.ONE, actual[1], "sqrtAndRemainder()[1]");
+
+ // square root of (n + 1)^2 - 1 -> n
+ BigInteger up = n.add(BigInteger.ONE).pow(2).subtract(BigInteger.ONE);
+ actual = up.sqrtAndRemainder();
+ checkResult(n, actual[0], "sqrtAndRemainder()[0]");
+ BigInteger r = up.subtract(n2);
+ checkResult(r, actual[1], "sqrtAndRemainder()[1]");
+ return null;
+ };
+
+ IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE);
+ bits.mapToObj(BigInteger::valueOf).map(g).collect(Collectors.toList());
+ }
+
+ private static void arithmetic(int order) {
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(order);
+ while(x.compareTo(BigInteger.ZERO) != 1)
+ x = fetchNumber(order);
+ BigInteger y = fetchNumber(order/2);
+ while(x.compareTo(y) == -1)
+ y = fetchNumber(order/2);
+ if (y.equals(BigInteger.ZERO))
+ y = y.add(BigInteger.ONE);
+
+ // Test identity ((x/y))*y + x%y - x == 0
+ // using separate divide() and remainder()
+ BigInteger baz = x.divide(y);
+ baz = baz.multiply(y);
+ baz = baz.add(x.remainder(y));
+ baz = baz.subtract(x);
+ Assert.assertEquals(baz, BigInteger.ZERO);
+ }
+
+ for (int i=0; i<100; i++) {
+ BigInteger x = fetchNumber(order);
+ while(x.compareTo(BigInteger.ZERO) != 1)
+ x = fetchNumber(order);
+ BigInteger y = fetchNumber(order/2);
+ while(x.compareTo(y) == -1)
+ y = fetchNumber(order/2);
+ if (y.equals(BigInteger.ZERO))
+ y = y.add(BigInteger.ONE);
+
+ // Test identity ((x/y))*y + x%y - x == 0
+ // using divideAndRemainder()
+ BigInteger baz[] = x.divideAndRemainder(y);
+ baz[0] = baz[0].multiply(y);
+ baz[0] = baz[0].add(baz[1]);
+ baz[0] = baz[0].subtract(x);
+ Assert.assertEquals(baz[0], BigInteger.ZERO);
+ }
+ }
+
+ /**
+ * Sanity test for Karatsuba and 3-way Toom-Cook multiplication.
+ * For each of the Karatsuba and 3-way Toom-Cook multiplication thresholds,
+ * construct two factors each with a mag array one element shorter than the
+ * threshold, and with the most significant bit set and the rest of the bits
+ * random. Each of these numbers will therefore be below the threshold but
+ * if shifted left be above the threshold. Call the numbers 'u' and 'v' and
+ * define random shifts 'a' and 'b' in the range [1,32]. Then we have the
+ * identity
+ * <pre>
+ * (u << a)*(v << b) = (u*v) << (a + b)
+ * </pre>
+ * For Karatsuba multiplication, the right hand expression will be evaluated
+ * using the standard naive algorithm, and the left hand expression using
+ * the Karatsuba algorithm. For 3-way Toom-Cook multiplication, the right
+ * hand expression will be evaluated using Karatsuba multiplication, and the
+ * left hand expression using 3-way Toom-Cook multiplication.
+ */
+ private static void multiplyLarge() {
+ BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1);
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1);
+ BigInteger u = base.add(x);
+ int a = 1 + random.nextInt(31);
+ BigInteger w = u.shiftLeft(a);
+
+ BigInteger y = fetchNumber(BITS_KARATSUBA - 32 - 1);
+ BigInteger v = base.add(y);
+ int b = 1 + random.nextInt(32);
+ BigInteger z = v.shiftLeft(b);
+
+ BigInteger multiplyResult = u.multiply(v).shiftLeft(a + b);
+ BigInteger karatsubaMultiplyResult = w.multiply(z);
+
+ Assert.assertEquals(karatsubaMultiplyResult, multiplyResult);
+ }
+
+ base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA);
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1);
+ BigInteger u = base.add(x);
+ BigInteger u2 = u.shiftLeft(1);
+ BigInteger y = fetchNumber(BITS_TOOM_COOK - 32 - 1);
+ BigInteger v = base.add(y);
+ BigInteger v2 = v.shiftLeft(1);
+
+ BigInteger multiplyResult = u.multiply(v).shiftLeft(2);
+ BigInteger toomCookMultiplyResult = u2.multiply(v2);
+
+ Assert.assertEquals(toomCookMultiplyResult, multiplyResult);
+ }
+ }
+
+ /**
+ * Sanity test for Karatsuba and 3-way Toom-Cook squaring.
+ * This test is analogous to {@link AbstractMethodError#multiplyLarge}
+ * with both factors being equal. The squaring methods will not be tested
+ * unless the <code>bigInteger.multiply(bigInteger)</code> tests whether
+ * the parameter is the same instance on which the method is being invoked
+ * and calls <code>square()</code> accordingly.
+ */
+ private static void squareLarge() {
+ BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1);
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1);
+ BigInteger u = base.add(x);
+ int a = 1 + random.nextInt(31);
+ BigInteger w = u.shiftLeft(a);
+
+ BigInteger squareResult = u.multiply(u).shiftLeft(2*a);
+ BigInteger karatsubaSquareResult = w.multiply(w);
+
+ Assert.assertEquals(karatsubaSquareResult, squareResult);
+ }
+
+ base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE);
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1);
+ BigInteger u = base.add(x);
+ int a = 1 + random.nextInt(31);
+ BigInteger w = u.shiftLeft(a);
+
+ BigInteger squareResult = u.multiply(u).shiftLeft(2*a);
+ BigInteger toomCookSquareResult = w.multiply(w);
+
+ Assert.assertEquals(toomCookSquareResult, squareResult);
+ }
+ }
+
+ /**
+ * Sanity test for Burnikel-Ziegler division. The Burnikel-Ziegler division
+ * algorithm is used when each of the dividend and the divisor has at least
+ * a specified number of ints in its representation. This test is based on
+ * the observation that if {@code w = u*pow(2,a)} and {@code z = v*pow(2,b)}
+ * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if
+ * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then
+ * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test
+ * ensures that {@code v} is just under the B-Z threshold, that {@code z} is
+ * over the threshold and {@code w} is much larger than {@code z}. This
+ * implies that {@code u/v} uses the standard division algorithm and
+ * {@code w/z} uses the B-Z algorithm. The results of the two algorithms
+ * are then compared using the observation described in the foregoing and
+ * if they are not equal a failure is logged.
+ */
+ private static void divideLarge() {
+ BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33);
+ for (int i=0; i<SIZE; i++) {
+ BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 34, random);
+ BigInteger v = base.add(addend);
+
+ BigInteger u = v.multiply(BigInteger.valueOf(2 + random.nextInt(Short.MAX_VALUE - 1)));
+
+ if(random.nextBoolean()) {
+ u = u.negate();
+ }
+ if(random.nextBoolean()) {
+ v = v.negate();
+ }
+
+ int a = BITS_BURNIKEL_ZIEGLER_OFFSET + random.nextInt(16);
+ int b = 1 + random.nextInt(16);
+ BigInteger w = u.multiply(BigInteger.ONE.shiftLeft(a));
+ BigInteger z = v.multiply(BigInteger.ONE.shiftLeft(b));
+
+ BigInteger[] divideResult = u.divideAndRemainder(v);
+ divideResult[0] = divideResult[0].multiply(BigInteger.ONE.shiftLeft(a - b));
+ divideResult[1] = divideResult[1].multiply(BigInteger.ONE.shiftLeft(b));
+ BigInteger[] bzResult = w.divideAndRemainder(z);
+
+ Assert.assertEquals(divideResult[0].compareTo(bzResult[0]), 0);
+ Assert.assertEquals(divideResult[1].compareTo(bzResult[1]), 0);
+ }
+ }
+
+ private static void bitCount() {
+ for (int i=0; i<SIZE*10; i++) {
+ int x = random.nextInt();
+ BigInteger bigX = BigInteger.valueOf((long)x);
+ int bit = (x < 0 ? 0 : 1);
+ int tmp = x, bitCount = 0;
+ for (int j=0; j<32; j++) {
+ bitCount += ((tmp & 1) == bit ? 1 : 0);
+ tmp >>= 1;
+ }
+
+ Assert.assertEquals (bigX.bitCount(), bitCount);
+ }
+ }
+
+ private static void bitLength() {
+ for (int i=0; i<SIZE*10; i++) {
+ int x = random.nextInt();
+ BigInteger bigX = BigInteger.valueOf((long)x);
+ int signBit = (x < 0 ? 0x80000000 : 0);
+ int tmp = x, bitLength, j;
+ for (j=0; j<32 && (tmp & 0x80000000)==signBit; j++)
+ tmp <<= 1;
+ bitLength = 32 - j;
+
+ Assert.assertEquals(bigX.bitLength(), bitLength);
+ }
+ }
+
+ private static void bitOps(int order) {
+ for (int i=0; i<SIZE*5; i++) {
+ BigInteger x = fetchNumber(order);
+ BigInteger y;
+
+ // Test setBit and clearBit (and testBit)
+ if (x.signum() < 0) {
+ y = BigInteger.valueOf(-1);
+ for (int j=0; j<x.bitLength(); j++)
+ if (!x.testBit(j))
+ y = y.clearBit(j);
+ } else {
+ y = BigInteger.ZERO;
+ for (int j=0; j<x.bitLength(); j++)
+ if (x.testBit(j))
+ y = y.setBit(j);
+ }
+ Assert.assertEquals(y, x);
+
+ // Test flipBit (and testBit)
+ y = BigInteger.valueOf(x.signum()<0 ? -1 : 0);
+ for (int j=0; j<x.bitLength(); j++)
+ if (x.signum()<0 ^ x.testBit(j))
+ y = y.flipBit(j);
+ Assert.assertEquals(y, x);
+ }
+
+ for (int i=0; i<SIZE*5; i++) {
+ BigInteger x = fetchNumber(order);
+
+ // Test getLowestSetBit()
+ int k = x.getLowestSetBit();
+ if (x.signum() == 0) {
+ Assert.assertEquals(k, -1);
+ } else {
+ BigInteger z = x.and(x.negate());
+ int j;
+ for (j=0; j<z.bitLength() && !z.testBit(j); j++)
+ ;
+ Assert.assertEquals(k, j);
+ }
+ }
+ }
+
+ private static void bitwise(int order) {
+
+ // Test identity x^y == x|y &~ x&y
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(order);
+ BigInteger y = fetchNumber(order);
+ BigInteger z = x.xor(y);
+ BigInteger w = x.or(y).andNot(x.and(y));
+ Assert.assertEquals(z, w, "Test identity x^y == x|y &~ x&y");
+ }
+
+ // Test identity x &~ y == ~(~x | y)
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(order);
+ BigInteger y = fetchNumber(order);
+ BigInteger z = x.andNot(y);
+ BigInteger w = x.not().or(y).not();
+ Assert.assertEquals(z, w, "Test identity x &~ y == ~(~x | y)");
+ }
+ }
+
+ private static void shift(int order) {
+ for (int i=0; i<100; i++) {
+ BigInteger x = fetchNumber(order);
+ int n = Math.abs(random.nextInt()%200);
+
+ Assert.assertEquals(x.shiftLeft(n), x.multiply(BigInteger.valueOf(2L).pow(n)));
+
+ BigInteger y[] =x.divideAndRemainder(BigInteger.valueOf(2L).pow(n));
+ BigInteger z = (x.signum()<0 && y[1].signum()!=0
+ ? y[0].subtract(BigInteger.ONE)
+ : y[0]);
+
+ BigInteger b = x.shiftRight(n);
+
+ Assert.assertEquals(z, b);
+
+ Assert.assertEquals(x.shiftLeft(n).shiftRight(n), x);
+ }
+ }
+
+ private static void divideAndRemainder(int order) {
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(order).abs();
+ while(x.compareTo(BigInteger.valueOf(3L)) != 1)
+ x = fetchNumber(order).abs();
+ BigInteger z = x.divide(BigInteger.valueOf(2L));
+ BigInteger y[] = x.divideAndRemainder(x);
+
+ Assert.assertEquals(y[0], BigInteger.ONE);
+ Assert.assertEquals(y[1], BigInteger.ZERO);
+
+ y = x.divideAndRemainder(z);
+ Assert.assertEquals(y[0], BigInteger.valueOf(2));
+ }
+ }
+
+ private static void stringConv() {
+ // Generic string conversion.
+ for (int i=0; i<100; i++) {
+ byte[] xBytes = new byte[Math.abs(random.nextInt())%100+1];
+ random.nextBytes(xBytes);
+ BigInteger x = new BigInteger(xBytes);
+
+ for (int radix=Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {
+ String result = x.toString(radix);
+ BigInteger test = new BigInteger(result, radix);
+ Assert.assertEquals(test, x,
+ "BigInteger toString: "+x+" Test: "+test+" radix: " + radix);
+ }
+ }
+
+ // String conversion straddling the Schoenhage algorithm crossover
+ // threshold, and at twice and four times the threshold.
+ for (int k = 0; k <= 2; k++) {
+ int factor = 1 << k;
+ int upper = factor * BITS_SCHOENHAGE_BASE + 33;
+ int lower = upper - 35;
+
+ for (int bits = upper; bits >= lower; bits--) {
+ for (int i = 0; i < 50; i++) {
+ BigInteger x = BigInteger.ONE.shiftLeft(bits - 1).or(new BigInteger(bits - 2, random));
+
+ for (int radix = Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) {
+ String result = x.toString(radix);
+ BigInteger test = new BigInteger(result, radix);
+ Assert.assertEquals(test, x,
+ "BigInteger toString: "+x+" Test: "+test+" radix: " + radix);
+ }
+ }
+ }
+ }
+ }
+
+ private static void byteArrayConv(int order) {
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(order);
+ while (x.equals(BigInteger.ZERO))
+ x = fetchNumber(order);
+ BigInteger y = new BigInteger(x.toByteArray());
+ Assert.assertEquals(y, x, "orig is " + x + ", new is " + y);
+ }
+ }
+
+ private static void modInv(int order) {
+ for (int i=0; i<SIZE; i++) {
+ BigInteger x = fetchNumber(order);
+ while(x.equals(BigInteger.ZERO))
+ x = fetchNumber(order);
+ BigInteger m = fetchNumber(order).abs();
+ while(m.compareTo(BigInteger.ONE) != 1)
+ m = fetchNumber(order).abs();
+
+ try {
+ BigInteger inv = x.modInverse(m);
+ BigInteger prod = inv.multiply(x).remainder(m);
+
+ if (prod.signum() == -1)
+ prod = prod.add(m);
+
+ Assert.assertEquals(prod, BigInteger.ONE);
+ } catch(ArithmeticException ignored) {
+ }
+ }
+ }
+
+ private static void modExp(int order1, int order2) {
+ for (int i=0; i<SIZE/10; i++) {
+ BigInteger m = fetchNumber(order1).abs();
+ while(m.compareTo(BigInteger.ONE) != 1)
+ m = fetchNumber(order1).abs();
+ BigInteger base = fetchNumber(order2);
+ BigInteger exp = fetchNumber(8).abs();
+
+ BigInteger z = base.modPow(exp, m);
+ BigInteger w = base.pow(exp.intValue()).mod(m);
+
+ Assert.assertEquals(z, w, "z is "+z+" w is "+w+" mod is "+m+" base is "+base+" exp is "+exp);
+ }
+ }
+
+ // This test is based on Fermat's theorem
+ // which is not ideal because base must not be multiple of modulus
+ // and modulus must be a prime or pseudoprime (Carmichael number)
+ private static void modExp2(int order) {
+ for (int i=0; i<10; i++) {
+ BigInteger m = new BigInteger(100, 5, random);
+ while(m.compareTo(BigInteger.ONE) != 1)
+ m = new BigInteger(100, 5, random);
+ BigInteger exp = m.subtract(BigInteger.ONE);
+ BigInteger base = fetchNumber(order).abs();
+ while(base.compareTo(m) != -1)
+ base = fetchNumber(order).abs();
+ while(base.equals(BigInteger.ZERO))
+ base = fetchNumber(order).abs();
+
+ BigInteger one = base.modPow(exp, m);
+ Assert.assertEquals(one, BigInteger.ONE, "m is "+m+" base is "+base+" exp is "+exp);
+ }
+ }
+
+ private static final int[] mersenne_powers = {
+ 521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937,
+ 21701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433,
+ 1257787, 1398269, 2976221, 3021377, 6972593, 13466917 };
+
+ private static final long[] carmichaels = {
+ 561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633,
+ 62745,63973,75361,101101,115921,126217,162401,172081,188461,252601,
+ 278545,294409,314821,334153,340561,399001,410041,449065,488881,512461,
+ 225593397919L };
+
+ // Note: testing the larger ones takes too long.
+ private static final int NUM_MERSENNES_TO_TEST = 7;
+ // Note: this constant used for computed Carmichaels, not the array above
+ private static final int NUM_CARMICHAELS_TO_TEST = 5;
+
+ private static final String[] customer_primes = {
+ "120000000000000000000000000000000019",
+ "633825300114114700748351603131",
+ "1461501637330902918203684832716283019651637554291",
+ "779626057591079617852292862756047675913380626199",
+ "857591696176672809403750477631580323575362410491",
+ "910409242326391377348778281801166102059139832131",
+ "929857869954035706722619989283358182285540127919",
+ "961301750640481375785983980066592002055764391999",
+ "1267617700951005189537696547196156120148404630231",
+ "1326015641149969955786344600146607663033642528339" };
+
+ private static final BigInteger ZERO = BigInteger.ZERO;
+ private static final BigInteger ONE = BigInteger.ONE;
+ private static final BigInteger TWO = new BigInteger("2");
+ private static final BigInteger SIX = new BigInteger("6");
+ private static final BigInteger TWELVE = new BigInteger("12");
+ private static final BigInteger EIGHTEEN = new BigInteger("18");
+
+ private static void prime() {
+ BigInteger p1, p2, c1;
+
+ // Test consistency
+ for(int i=0; i<10; i++) {
+ p1 = BigInteger.probablePrime(100, random);
+ Assert.assertTrue(p1.isProbablePrime(100), p1.toString(16));
+ }
+
+ // Test some known Mersenne primes (2^n)-1
+ // The array holds the exponents, not the numbers being tested
+ for (int i=0; i<NUM_MERSENNES_TO_TEST; i++) {
+ p1 = new BigInteger("2");
+ p1 = p1.pow(mersenne_powers[i]);
+ p1 = p1.subtract(BigInteger.ONE);
+ Assert.assertTrue(p1.isProbablePrime(100), "Mersenne prime "+i+ " failed.");
+ }
+
+ // Test some primes reported by customers as failing in the past
+ for (int i=0; i<customer_primes.length; i++) {
+ p1 = new BigInteger(customer_primes[i]);
+ Assert.assertTrue(p1.isProbablePrime(100), "Customer prime "+i+ " failed.");
+ }
+
+ // Test some known Carmichael numbers.
+ for (int i=0; i<carmichaels.length; i++) {
+ c1 = BigInteger.valueOf(carmichaels[i]);
+ Assert.assertFalse(c1.isProbablePrime(100), "Carmichael "+i+ " reported as prime.");
+ }
+
+ // Test some computed Carmichael numbers.
+ // Numbers of the form (6k+1)(12k+1)(18k+1) are Carmichael numbers if
+ // each of the factors is prime
+ int found = 0;
+ BigInteger f1 = new BigInteger(40, 100, random);
+ while (found < NUM_CARMICHAELS_TO_TEST) {
+ BigInteger k = null;
+ BigInteger f2, f3;
+ f1 = f1.nextProbablePrime();
+ BigInteger[] result = f1.subtract(ONE).divideAndRemainder(SIX);
+ if (result[1].equals(ZERO)) {
+ k = result[0];
+ f2 = k.multiply(TWELVE).add(ONE);
+ if (f2.isProbablePrime(100)) {
+ f3 = k.multiply(EIGHTEEN).add(ONE);
+ if (f3.isProbablePrime(100)) {
+ c1 = f1.multiply(f2).multiply(f3);
+ Assert.assertFalse(c1.isProbablePrime(100), "Computed Carmichael "
+ +c1.toString(16));
+ found++;
+ }
+ }
+ }
+ f1 = f1.add(TWO);
+ }
+
+ // Test some composites that are products of 2 primes
+ for (int i=0; i<50; i++) {
+ p1 = BigInteger.probablePrime(100, random);
+ p2 = BigInteger.probablePrime(100, random);
+ c1 = p1.multiply(p2);
+ Assert.assertFalse(c1.isProbablePrime(100),
+ "Composite failed "+c1.toString(16));
+ }
+
+ for (int i=0; i<4; i++) {
+ p1 = BigInteger.probablePrime(600, random);
+ p2 = BigInteger.probablePrime(600, random);
+ c1 = p1.multiply(p2);
+ Assert.assertFalse(c1.isProbablePrime(100),
+ "Composite failed "+c1.toString(16));
+ }
+ }
+
+ private static final long[] primesTo100 = {
+ 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
+ };
+
+ private static final long[] aPrimeSequence = {
+ 1999999003L, 1999999013L, 1999999049L, 1999999061L, 1999999081L,
+ 1999999087L, 1999999093L, 1999999097L, 1999999117L, 1999999121L,
+ 1999999151L, 1999999171L, 1999999207L, 1999999219L, 1999999271L,
+ 1999999321L, 1999999373L, 1999999423L, 1999999439L, 1999999499L,
+ 1999999553L, 1999999559L, 1999999571L, 1999999609L, 1999999613L,
+ 1999999621L, 1999999643L, 1999999649L, 1999999657L, 1999999747L,
+ 1999999763L, 1999999777L, 1999999811L, 1999999817L, 1999999829L,
+ 1999999853L, 1999999861L, 1999999871L, 1999999873
+ };
+
+ private static void nextProbablePrime() throws Exception {
+ BigInteger p1, p2, p3;
+ p1 = p2 = p3 = ZERO;
+
+ // First test nextProbablePrime on the low range starting at zero
+ for (long l : primesTo100) {
+ p1 = p1.nextProbablePrime();
+ Assert.assertEquals(p1.longValue(), l,
+ "low range primes failed: p1 is " + p1 + ", expected " + l);
+ }
+
+ // Test nextProbablePrime on a relatively small, known prime sequence
+ p1 = BigInteger.valueOf(aPrimeSequence[0]);
+ for (int i=1; i<aPrimeSequence.length; i++) {
+ p1 = p1.nextProbablePrime();
+ Assert.assertEquals(p1.longValue(), aPrimeSequence[i], "prime sequence failed");
+ }
+
+ // Next, pick some large primes, use nextProbablePrime to find the
+ // next one, and make sure there are no primes in between
+ for (int i=0; i<100; i+=10) {
+ p1 = BigInteger.probablePrime(50 + i, random);
+ p2 = p1.add(ONE);
+ p3 = p1.nextProbablePrime();
+ while(p2.compareTo(p3) < 0) {
+ Assert.assertFalse(p2.isProbablePrime(100),
+ "nextProbablePrime failed along range "+p1.toString(16)+" to "+p3.toString(16));
+ p2 = p2.add(ONE);
+ }
+ }
+ }
+
+ // Android-changed: Replace File streams with ByteArray
+ public static void serialize() throws Exception {
+ String[] bitPatterns = {
+ "ffffffff00000000ffffffff00000000ffffffff00000000",
+ "ffffffffffffffffffffffff000000000000000000000000",
+ "ffffffff0000000000000000000000000000000000000000",
+ "10000000ffffffffffffffffffffffffffffffffffffffff",
+ "100000000000000000000000000000000000000000000000",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "-ffffffff00000000ffffffff00000000ffffffff00000000",
+ "-ffffffffffffffffffffffff000000000000000000000000",
+ "-ffffffff0000000000000000000000000000000000000000",
+ "-10000000ffffffffffffffffffffffffffffffffffffffff",
+ "-100000000000000000000000000000000000000000000000",
+ "-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ };
+
+ for (String bitPattern : bitPatterns) {
+ BigInteger b1 = new BigInteger(bitPattern, 16);
+ BigInteger b2 = null;
+
+ try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
+ try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
+ oos.writeObject(b1);
+ oos.flush();
+ }
+
+ try (ByteArrayInputStream fis = new ByteArrayInputStream(fos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(fis)) {
+ b2 = (BigInteger) ois.readObject();
+ }
+
+ Assert.assertEquals(b1, b2, "Serialized failed for hex " + b1.toString(16));
+ Assert.assertEquals(b1.or(b2), b1, "Serialized failed for hex " + b1.toString(16));
+ }
+ }
+
+ for(int i=0; i<10; i++) {
+ BigInteger b1 = fetchNumber(random.nextInt(100));
+ BigInteger b2 = null;
+
+ try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
+ try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
+ oos.writeObject(b1);
+ oos.flush();
+ }
+
+ try (ByteArrayInputStream fis = new ByteArrayInputStream(fos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(fis))
+ {
+ b2 = (BigInteger)ois.readObject();
+ }
+ }
+
+ Assert.assertEquals(b1, b2, "Serialized failed for hex " + b1.toString(16));
+ Assert.assertEquals(b1.or(b2), b1, "Serialized failed for hex " + b1.toString(16));
+ }
+ }
+
+ private static final int ORDER_1 = ORDER_MEDIUM;
+ private static final int ORDER_2 = ORDER_SMALL;
+ private static final int ORDER_3 = ORDER_KARATSUBA;
+ private static final int ORDER_4 = ORDER_TOOM_COOK;
+
+ @Test
+ public void testConstructor() {
+ constructor();
+ }
+
+ @Test
+ public void testPrime() {
+ prime();
+ }
+
+ @Test
+ public void testNextProbablePrime() throws Exception {
+ nextProbablePrime();
+ }
+
+ @Test
+ public void testArithmetic() {
+ arithmetic(ORDER_1); // small numbers
+ arithmetic(ORDER_3); // Karatsuba range
+ arithmetic(ORDER_4); // Toom-Cook / Burnikel-Ziegler range
+ }
+
+ @Test
+ public void testDivideAndReminder() {
+ divideAndRemainder(ORDER_1); // small numbers
+ divideAndRemainder(ORDER_3); // Karatsuba range
+ divideAndRemainder(ORDER_4); // Toom-Cook / Burnikel-Ziegler range
+ }
+
+ @Test
+ public void testPow() {
+ pow(ORDER_1);
+ pow(ORDER_3);
+ pow(ORDER_4);
+ }
+
+ @Test
+ public void testSquare() {
+ square(ORDER_MEDIUM);
+ square(ORDER_KARATSUBA_SQUARE);
+ square(ORDER_TOOM_COOK_SQUARE);
+ }
+
+ @Test
+ public void testSquareRoot() {
+ squareRoot();
+ }
+
+ @Test
+ public void testSquareRootAndReminder() {
+ squareRootAndRemainder();
+ }
+
+ @Test
+ public void testBitCount() {
+ bitCount();
+ }
+
+ @Test
+ public void testBitLength() {
+ bitLength();
+ }
+
+ @Test
+ public void testBitOps() {
+ bitOps(ORDER_1);
+ }
+
+ @Test
+ public void testBitwise() {
+ bitwise(ORDER_1);
+ }
+
+ @Test
+ public void testShift() {
+ shift(ORDER_1);
+ }
+
+ @Test
+ public void testByteArrayConv() {
+ byteArrayConv(ORDER_1);
+ }
+
+ @Test
+ public void testModInv() {
+ modInv(ORDER_1); // small numbers
+ modInv(ORDER_3); // Karatsuba range
+ modInv(ORDER_4); // Toom-Cook / Burnikel-Ziegler range
+ }
+
+ @Test
+ public void testModExp() {
+ modExp(ORDER_1, ORDER_2);
+ modExp2(ORDER_1);
+ }
+
+ @Test
+ public void testStringConv() {
+ stringConv();
+ }
+
+ @Test
+ public void testSerialize() throws Exception {
+ serialize();
+ }
+
+ @Test
+ public void testMultiplyLarge() {
+ multiplyLarge();
+ }
+
+ @Test
+ public void testSquareLarge() {
+ squareLarge();
+ }
+
+ @Test
+ public void testDivideLarge() {
+ divideLarge();
+ }
+
+ /*
+ * Get a random or boundary-case number. This is designed to provide
+ * a lot of numbers that will find failure points, such as max sized
+ * numbers, empty BigIntegers, etc.
+ *
+ * If order is less than 2, order is changed to 2.
+ */
+ private static BigInteger fetchNumber(int order) {
+ boolean negative = random.nextBoolean();
+ int numType = random.nextInt(7);
+ BigInteger result = null;
+ if (order < 2) order = 2;
+
+ switch (numType) {
+ case 0: // Empty
+ result = BigInteger.ZERO;
+ break;
+
+ case 1: // One
+ result = BigInteger.ONE;
+ break;
+
+ case 2: // All bits set in number
+ int numBytes = (order+7)/8;
+ byte[] fullBits = new byte[numBytes];
+ for(int i=0; i<numBytes; i++)
+ fullBits[i] = (byte)0xff;
+ int excessBits = 8*numBytes - order;
+ fullBits[0] &= (1 << (8-excessBits)) - 1;
+ result = new BigInteger(1, fullBits);
+ break;
+
+ case 3: // One bit in number
+ result = BigInteger.ONE.shiftLeft(random.nextInt(order));
+ break;
+
+ case 4: // Random bit density
+ byte[] val = new byte[(order+7)/8];
+ int iterations = random.nextInt(order);
+ for (int i=0; i<iterations; i++) {
+ int bitIdx = random.nextInt(order);
+ val[bitIdx/8] |= 1 << (bitIdx%8);
+ }
+ result = new BigInteger(1, val);
+ break;
+ case 5: // Runs of consecutive ones and zeros
+ result = ZERO;
+ int remaining = order;
+ int bit = random.nextInt(2);
+ while (remaining > 0) {
+ int runLength = Math.min(remaining, random.nextInt(order));
+ result = result.shiftLeft(runLength);
+ if (bit > 0)
+ result = result.add(ONE.shiftLeft(runLength).subtract(ONE));
+ remaining -= runLength;
+ bit = 1 - bit;
+ }
+ break;
+
+ default: // random bits
+ result = new BigInteger(order, random);
+ }
+
+ if (negative)
+ result = result.negate();
+
+ return result;
+ }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/CompareToTests.java b/ojluni/src/test/java/math/BigInteger/CompareToTests.java
new file mode 100644
index 0000000..abb8b4c
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/CompareToTests.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigInteger;
+
+/*
+ * @test
+ * @bug 6473768
+ * @summary Tests of BigInteger.compareTo
+ * @author Joseph D. Darcy
+ */
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import static java.math.BigInteger.*;
+
+// Android-changed: Replace error printing with asserts.
+public class CompareToTests {
+
+ @Test
+ public void compareToTests() {
+ final BigInteger MINUS_ONE = BigInteger.ONE.negate();
+ final BigInteger TWO_POW_126 = ONE.shiftLeft(126);
+ final BigInteger TWO_POW_127 = ONE.shiftLeft(127);
+ final BigInteger TWO_POW_128 = ONE.shiftLeft(128);
+
+ // First operand, second operand, expected compareTo result
+ BigInteger [][] testCases = {
+ // Basics
+ {valueOf(0), valueOf(0), ZERO},
+ {valueOf(0), valueOf(1), MINUS_ONE},
+ {valueOf(1), valueOf(2), MINUS_ONE},
+ {valueOf(2), valueOf(1), ONE},
+ {valueOf(10), valueOf(10), ZERO},
+
+ // Various relative lengths of internal mag array.
+ {TWO_POW_127, TWO_POW_127, ZERO},
+ {TWO_POW_127.negate(), TWO_POW_127, MINUS_ONE},
+
+ {TWO_POW_128.or(TWO_POW_126), TWO_POW_128, ONE},
+ {TWO_POW_128.or(TWO_POW_126), TWO_POW_128.negate(), ONE},
+
+ {TWO_POW_128, TWO_POW_128.or(TWO_POW_126), MINUS_ONE},
+ {TWO_POW_128.negate(), TWO_POW_128.or(TWO_POW_126), MINUS_ONE},
+
+ {TWO_POW_127, TWO_POW_128, MINUS_ONE},
+ {TWO_POW_127.negate(), TWO_POW_128, MINUS_ONE},
+
+ {TWO_POW_128, TWO_POW_127, ONE},
+ {TWO_POW_128.negate(), TWO_POW_127, MINUS_ONE},
+
+ // Long boundary and near boundary values
+ {valueOf(Long.MAX_VALUE), valueOf(Long.MAX_VALUE), ZERO},
+ {valueOf(Long.MAX_VALUE).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+ {valueOf(Long.MAX_VALUE-1), valueOf(Long.MAX_VALUE), MINUS_ONE},
+ {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
+
+ {valueOf(Long.MIN_VALUE), valueOf(Long.MAX_VALUE), MINUS_ONE},
+ {valueOf(Long.MIN_VALUE).negate(), valueOf(Long.MAX_VALUE), ONE},
+
+ {valueOf(Long.MIN_VALUE+1), valueOf(Long.MAX_VALUE), MINUS_ONE},
+ {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MAX_VALUE), ZERO},
+
+ {valueOf(Long.MAX_VALUE), valueOf(Long.MIN_VALUE), ONE},
+ {valueOf(Long.MAX_VALUE).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+ {valueOf(Long.MAX_VALUE-1), valueOf(Long.MIN_VALUE), ONE},
+ {valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+ {valueOf(Long.MIN_VALUE), valueOf(Long.MIN_VALUE), ZERO},
+ {valueOf(Long.MIN_VALUE).negate(), valueOf(Long.MIN_VALUE), ONE},
+
+ {valueOf(Long.MIN_VALUE+1), valueOf(Long.MIN_VALUE), ONE},
+ {valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MIN_VALUE), ONE},
+ };
+
+ for (BigInteger[] testCase : testCases) {
+ BigInteger a = testCase[0];
+ BigInteger a_negate = a.negate();
+ BigInteger b = testCase[1];
+ BigInteger b_negate = b.negate();
+ int expected = testCase[2].intValue();
+
+ compareToTest(a, b, expected);
+ compareToTest(a_negate, b_negate, -expected);
+ }
+ }
+
+ private static void compareToTest(BigInteger a, BigInteger b, int expected) {
+ int result = a.compareTo(b);
+ int failed = (result==expected) ? 0 : 1;
+ if (failed == 1) {
+ Assert.fail("(" + a + ").compareTo(" + b + ") => " + result +
+ "\n\tExpected " + expected);
+ }
+ }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/ModPow.java b/ojluni/src/test/java/math/BigInteger/ModPow.java
new file mode 100644
index 0000000..b31c0f6
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/ModPow.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4181191
+ * @summary test BigInteger modPow method
+ */
+package test.java.math.BigInteger;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class ModPow {
+
+ @Test
+ public void testModPow() {
+ Random rnd = new Random(1234);
+
+ for (int i=0; i<2000; i++) {
+ BigInteger m = new BigInteger(800, rnd);
+ BigInteger base = new BigInteger(16, rnd);
+ if (rnd.nextInt() % 2 == 0)
+ base = base.negate();
+ BigInteger exp = new BigInteger(8, rnd);
+
+ BigInteger z = base.modPow(exp, m);
+ BigInteger w = base.pow(exp.intValue()).mod(m);
+ Assert.assertEquals(z, w,
+ base +" ** " + exp + " mod "+ m + " modPow : " + z + "pow.mod: " + w);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/OperatorNpeTests.java b/ojluni/src/test/java/math/BigInteger/OperatorNpeTests.java
new file mode 100644
index 0000000..5940249
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/OperatorNpeTests.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6365176
+ * @summary Get NullPointerExceptions when expected
+ * @author Joseph D. Darcy
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+import static java.math.BigInteger.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class OperatorNpeTests {
+
+ @Test
+ public void testOperatorsNpe() throws NullPointerException {
+ BigInteger[] specialValues = {ZERO, ONE, TEN};
+
+ for (BigInteger bd : specialValues) {
+ BigInteger result;
+ try {
+ result = bd.multiply(null);
+ Assert.fail("Instead of NPE got " + result);
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+
+ try {
+ result = bd.divide(null);
+ Assert.fail("Instead of NPE got " + result);
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+
+ try {
+ result = bd.add(null);
+ Assert.fail("Instead of NPE got " + result);
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+
+ try {
+ result = bd.subtract(null);
+ Assert.fail("Instead of NPE got " + result);
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/PrimeTest.java b/ojluni/src/test/java/math/BigInteger/PrimeTest.java
new file mode 100644
index 0000000..e0e4c88
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/PrimeTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+/*
+ * @test
+ * @library /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * @run main PrimeTest
+ * @bug 8026236 8074460 8078672
+ * @summary test primality verification methods in BigInteger (use -Dseed=X to set PRNG seed)
+ * @author bpb
+ * @key randomness
+ */
+package test.java.math.BigInteger;
+
+import java.math.BigInteger;
+import java.util.BitSet;
+import java.util.List;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SplittableRandom;
+import java.util.TreeSet;
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toList;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class PrimeTest {
+
+ private static final int DEFAULT_UPPER_BOUND = 1299709; // 100000th prime
+ private static final int DEFAULT_CERTAINTY = 100;
+ private static final int NUM_NON_PRIMES = 10000;
+
+ @Test
+ public void testPrimes() throws Exception {
+ // Get primes through specified bound (inclusive) and Integer.MAX_VALUE
+ NavigableSet<BigInteger> primes = getPrimes();
+
+ // Check whether known primes are identified as such
+ checkPrime(primes, DEFAULT_CERTAINTY);
+
+ // Check whether known non-primes are not identified as primes
+ checkNonPrime(primes, DEFAULT_CERTAINTY);
+
+ checkMersennePrimes(DEFAULT_CERTAINTY);
+ }
+
+ /**
+ * Create a {@code BitSet} wherein a set bit indicates the corresponding
+ * index plus 2 is prime. That is, if bit N is set, then the integer N + 2
+ * is prime. The values 0 and 1 are intentionally excluded. See the
+ * <a
+ * href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Algorithm_description">
+ * Sieve of Eratosthenes</a> algorithm description for more information.
+ *
+ * @return bits indicating which indexes represent primes
+ */
+ private static BitSet createPrimes() {
+ int nbits = PrimeTest.DEFAULT_UPPER_BOUND - 1;
+ BitSet bs = new BitSet(nbits);
+ for (int p = 2; p * p < PrimeTest.DEFAULT_UPPER_BOUND;) {
+ for (int i = p * p; i < nbits + 2; i += p) {
+ bs.set(i - 2, true);
+ }
+ do {
+ ++p;
+ } while (p > 1 && bs.get(p - 2));
+ }
+ bs.flip(0, nbits);
+ return bs;
+ }
+
+ /**
+ * Load the primes up to the specified bound (inclusive) into a
+ * {@code NavigableSet}, appending the prime {@code Integer.MAX_VALUE}.
+ *
+ * @return a set of primes
+ */
+ private static NavigableSet<BigInteger> getPrimes() {
+ BitSet bs = createPrimes();
+ NavigableSet<BigInteger> primes = bs.stream()
+ .mapToObj(p -> BigInteger.valueOf(p + 2))
+ .collect(toCollection(TreeSet::new));
+ primes.add(BigInteger.valueOf(Integer.MAX_VALUE));
+ return primes;
+ }
+
+ /**
+ * Verifies whether the fraction of probable primes detected is at least 1 -
+ * 1/2^certainty.
+ */
+ private static void checkPrime(Set<BigInteger> primes, int certainty) {
+ long probablePrimes = (primes.parallelStream())
+ .filter(bi -> bi.isProbablePrime(certainty))
+ .count();
+
+ // N = certainty / 2
+ // Success if p/t >= 1 - 1/4^N
+ // or (p/t)*4^N >= 4^N - 1
+ // or p*4^N >= t*(4^N - 1)
+ BigInteger p = BigInteger.valueOf(probablePrimes);
+ BigInteger t = BigInteger.valueOf(primes.size());
+ BigInteger fourToTheC = BigInteger.valueOf(4).pow(certainty / 2);
+ BigInteger fourToTheCMinusOne = fourToTheC.subtract(BigInteger.ONE);
+ BigInteger left = p.multiply(fourToTheC);
+ BigInteger right = t.multiply(fourToTheCMinusOne);
+
+ Assert.assertFalse(left.compareTo(right) < 0,
+ "Probable prime certainty test failed");
+ }
+
+ /**
+ * Verifies whether all {@code BigInteger}s in the tested range for which
+ * {@code isProbablePrime()} returns {@code false} are <i>not</i>
+ * prime numbers.
+ */
+ private static void checkNonPrime(NavigableSet<BigInteger> primes, int certainty) {
+ int maxPrime = DEFAULT_UPPER_BOUND;
+ try {
+ maxPrime = primes.last().intValueExact();
+ } catch (ArithmeticException e) {
+ // ignore it
+ }
+
+ // Create a list of non-prime BigIntegers.
+ SplittableRandom splitRandom = new SplittableRandom(0L);
+ List<BigInteger> nonPrimeBigInts = (splitRandom)
+ .ints(NUM_NON_PRIMES, 2, maxPrime).mapToObj(BigInteger::valueOf)
+ .filter(b -> !b.isProbablePrime(certainty)).collect(toList());
+
+ // If there are any non-probable primes also in the primes list then fail.
+ boolean failed = nonPrimeBigInts.stream().anyMatch(primes::contains);
+
+ // In the event, print which purported non-primes were actually prime.
+ if (failed) {
+ for (BigInteger bigInt : nonPrimeBigInts) {
+ if (primes.contains(bigInt)) {
+ Assert.fail("Prime value thought to be non-prime: " + bigInt);
+ }
+ }
+ }
+ }
+
+ /**
+ * Verifies whether a specified subset of Mersenne primes are correctly
+ * identified as being prime. See
+ * <a href="https://en.wikipedia.org/wiki/Mersenne_prime">Mersenne prime</a>
+ * for more information.
+ */
+ private static void checkMersennePrimes(int certainty) {
+ int[] MERSENNE_EXPONENTS = {
+ 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
+ 2281, 3217, 4253, // uncomment remaining array elements to make this test run a long time
+ /* 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497,
+ 86243, 110503, 132049, 216091, 756839, 859433, 1257787, 1398269,
+ 2976221, 3021377, 6972593, 13466917, 20996011, 24036583, 25964951,
+ 30402457, 32582657, 37156667, 42643801, 43112609, 57885161 */
+ };
+
+ for (int n : MERSENNE_EXPONENTS) {
+ BigInteger mp = BigInteger.ONE.shiftLeft(n).subtract(BigInteger.ONE);
+ Assert.assertTrue(mp.isProbablePrime(certainty),
+ "Mp with p = "+n+" not classified as prime");
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/PrimitiveConversionTests.java b/ojluni/src/test/java/math/BigInteger/PrimitiveConversionTests.java
new file mode 100644
index 0000000..834f864
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/PrimitiveConversionTests.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.math.BigInteger;
+
+import static java.math.BigInteger.ONE;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 7131192
+ * @summary This test ensures that BigInteger.floatValue() and
+ * BigInteger.doubleValue() behave correctly.
+ * @author Louis Wasserman
+ */
+
+// Android-changed: Replace error printing with asserts.
+public class PrimitiveConversionTests {
+ static final List<BigInteger> ALL_BIGINTEGER_CANDIDATES;
+
+ static {
+ List<BigInteger> samples = new ArrayList<>();
+ // Now add values near 2^N for lots of values of N.
+ for (int exponent : Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 31, 32, 33,
+ 34, 62, 63, 64, 65, 71, 72, 73, 79, 80, 81, 255, 256, 257, 511,
+ 512, 513, Double.MAX_EXPONENT - 1, Double.MAX_EXPONENT,
+ Double.MAX_EXPONENT + 1, 2000, 2001, 2002)) {
+ BigInteger x = ONE.shiftLeft(exponent);
+ for (BigInteger y : Arrays.asList(x, x.add(ONE), x.subtract(ONE))) {
+ samples.add(y);
+ samples.add(y.negate());
+ }
+ }
+
+ Random rng = new Random(1234567);
+ for (int i = 0; i < 2000; i++) {
+ samples.add(new BigInteger(rng.nextInt(2000), rng));
+ }
+
+ ALL_BIGINTEGER_CANDIDATES = Collections.unmodifiableList(samples);
+ }
+
+ @Test
+ public void testDoubleValue() {
+ for (BigInteger big : ALL_BIGINTEGER_CANDIDATES) {
+ double expected = Double.parseDouble(big.toString());
+ double actual = big.doubleValue();
+
+ // should be bitwise identical
+ Assert.assertEquals(Double.doubleToRawLongBits(actual),
+ Double.doubleToRawLongBits(expected));
+ }
+ }
+
+ @Test
+ public void testFloatValue() {
+ for (BigInteger big : ALL_BIGINTEGER_CANDIDATES) {
+ float expected = Float.parseFloat(big.toString());
+ float actual = big.floatValue();
+
+ // should be bitwise identical
+ Assert.assertEquals(Float.floatToRawIntBits(actual),
+ Float.floatToRawIntBits(expected));
+ }
+ }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/ProbablePrime.java b/ojluni/src/test/java/math/BigInteger/ProbablePrime.java
new file mode 100644
index 0000000..158c0e8
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/ProbablePrime.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4654323
+ * @summary Tests functionality of isProbablePrime(Integer.MAX_VALUE)
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class ProbablePrime {
+
+ @Test
+ public void testProbablePrime() {
+ BigInteger num = new BigInteger("4");
+ int[] certainties = {-1, 0, 1, 2, 100, Integer.MAX_VALUE - 1, Integer.MAX_VALUE};
+ boolean[] expectations = {true, true, false, false, false, false, false};
+
+ for (int i = 0; i < certainties.length; i++) {
+ boolean b = num.isProbablePrime(certainties[i]);
+ Assert.assertEquals(b, expectations[i], "Unexpected answer " + b +
+ " for certainty " + certainties[i]);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/StringConstructor.java b/ojluni/src/test/java/math/BigInteger/StringConstructor.java
new file mode 100644
index 0000000..b7be11b
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/StringConstructor.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4489146 5017980
+ * @summary tests String constructors of BigInteger
+ * @author Joseph D. Darcy
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class StringConstructor {
+
+ @Test
+ public void testStringConstructor() {
+ // Good strings
+ constructWithoutError("0", 0L);
+ constructWithoutError("000000000000000000", 0L);
+ constructWithoutError("1", 1L);
+ constructWithoutError("-1", -1L);
+ constructWithoutError("+1", +1L);
+ constructWithoutError( "123456789123456789", 123456789123456789L);
+ constructWithoutError("+123456789123456789", 123456789123456789L);
+ constructWithoutError("-123456789123456789", -123456789123456789L);
+ constructWithoutError(Integer.toString(Integer.MIN_VALUE),
+ (long)Integer.MIN_VALUE);
+ constructWithoutError(Integer.toString(Integer.MAX_VALUE),
+ (long)Integer.MAX_VALUE);
+ constructWithoutError(Long.toString(Long.MIN_VALUE),
+ Long.MIN_VALUE);
+ constructWithoutError(Long.toString(Long.MAX_VALUE),
+ Long.MAX_VALUE);
+
+ // Bad strings
+ constructWithError("");
+ constructWithError("-");
+ constructWithError("+");
+ constructWithError("--");
+ constructWithError("++");
+ constructWithError("-000-0");
+ constructWithError("+000+0");
+ constructWithError("+000-0");
+ constructWithError("--1234567890");
+ constructWithError("++1234567890");
+ constructWithError("-0-12345678");
+ constructWithError("+0+12345678");
+ constructWithError("--12345678-12345678-12345678");
+ constructWithError("++12345678+12345678+12345678");
+ constructWithError("12345-");
+ constructWithError("12345+");
+ }
+
+ // this method adapted from ../BigDecimal/StringConstructor.java
+ private static void constructWithError(String badString) {
+ try {
+ BigInteger bi = new BigInteger(badString);
+ Assert.fail(badString + " accepted");
+ } catch(NumberFormatException e) {
+ // expected
+ }
+ }
+
+ private static void constructWithoutError(String goodString, long value) {
+ BigInteger bi = new BigInteger(goodString);
+ Assert.assertEquals(bi.longValue(), value,
+ String.format("From ``%s'' expected %d, got %s.\n", goodString, value, bi));
+ }
+
+}
diff --git a/ojluni/src/test/java/math/BigInteger/TestValueExact.java b/ojluni/src/test/java/math/BigInteger/TestValueExact.java
new file mode 100644
index 0000000..92e49783
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/TestValueExact.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6371401
+ * @summary Tests of fooValueExact methods
+ * @author Joseph D. Darcy
+ */
+package test.java.math.BigInteger;
+
+import java.math.BigInteger;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+// Android-changed: Replace error printing with asserts.
+public class TestValueExact {
+
+ @Test
+ public void testLongValueExact() {
+ BigInteger[] inRange = {
+ BigInteger.valueOf(Long.MIN_VALUE),
+ BigInteger.ZERO,
+ BigInteger.valueOf(Long.MAX_VALUE)
+ };
+
+ BigInteger[] outOfRange = {
+ BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE),
+ BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)
+ };
+
+ for (BigInteger bi : inRange) {
+ Assert.assertEquals(bi.longValueExact(), bi.longValue(),
+ "Mismatching int conversion for " + bi);
+ }
+
+ for (BigInteger bi : outOfRange) {
+ try {
+ long value = bi.longValueExact();
+ Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+ } catch(ArithmeticException ae) {
+ ; // Expected
+ }
+ }
+ }
+
+ @Test
+ public void testIntValueExact() {
+ BigInteger[] inRange = {
+ BigInteger.valueOf(Integer.MIN_VALUE),
+ BigInteger.ZERO,
+ BigInteger.ONE,
+ BigInteger.TEN,
+ BigInteger.valueOf(Integer.MAX_VALUE)
+ };
+
+ BigInteger[] outOfRange = {
+ BigInteger.valueOf((long)Integer.MIN_VALUE - 1),
+ BigInteger.valueOf((long)Integer.MAX_VALUE + 1)
+ };
+
+ for (BigInteger bi : inRange) {
+ Assert.assertEquals(bi.intValueExact(), bi.intValue(),
+ "Mismatching int conversion for " + bi);
+ }
+
+ for (BigInteger bi : outOfRange) {
+ try {
+ int value = bi.intValueExact();
+ Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+ } catch(ArithmeticException ae) {
+ ; // Expected
+ }
+ }
+ }
+
+ @Test
+ public void testShortValueExact() {
+ BigInteger[] inRange = {
+ BigInteger.valueOf(Short.MIN_VALUE),
+ BigInteger.ZERO,
+ BigInteger.ONE,
+ BigInteger.TEN,
+ BigInteger.valueOf(Short.MAX_VALUE)
+ };
+
+ BigInteger[] outOfRange = {
+ BigInteger.valueOf((long)Integer.MIN_VALUE - 1),
+ BigInteger.valueOf((long)Integer.MIN_VALUE),
+ BigInteger.valueOf( (int)Short.MIN_VALUE - 1),
+ BigInteger.valueOf( (int)Short.MAX_VALUE + 1),
+ BigInteger.valueOf((long)Integer.MAX_VALUE),
+ BigInteger.valueOf((long)Integer.MAX_VALUE + 1)
+ };
+
+ for (BigInteger bi : inRange) {
+ Assert.assertEquals(bi.shortValueExact(), bi.intValue(),
+ "Mismatching int conversion for " + bi);
+ }
+
+ for (BigInteger bi : outOfRange) {
+ try {
+ int value = bi.shortValueExact();
+ Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+ } catch(ArithmeticException ae) {
+ ; // Expected
+ }
+ }
+ }
+
+ @Test
+ public void testByteValueExact() {
+ BigInteger[] inRange = {
+ BigInteger.valueOf(Byte.MIN_VALUE),
+ BigInteger.valueOf(0),
+ BigInteger.ONE,
+ BigInteger.TEN,
+ BigInteger.valueOf(Byte.MAX_VALUE)
+ };
+
+ BigInteger[] outOfRange = {
+ BigInteger.valueOf((long)Integer.MIN_VALUE - 1),
+ BigInteger.valueOf((long)Integer.MIN_VALUE),
+ BigInteger.valueOf( (int)Short.MIN_VALUE - 1),
+ BigInteger.valueOf( (int)Short.MIN_VALUE),
+ BigInteger.valueOf( (int)Byte.MIN_VALUE - 1),
+ BigInteger.valueOf( (int)Byte.MAX_VALUE + 1),
+ BigInteger.valueOf( (int)Short.MAX_VALUE + 1),
+ BigInteger.valueOf( (int)Short.MAX_VALUE),
+ BigInteger.valueOf((long)Integer.MAX_VALUE),
+ BigInteger.valueOf((long)Integer.MAX_VALUE + 1)
+ };
+
+ for (BigInteger bi : inRange) {
+ Assert.assertEquals(bi.byteValueExact(), bi.intValue(),
+ "Mismatching int conversion for " + bi);
+ }
+
+ for (BigInteger bi : outOfRange) {
+ try {
+ int value = bi.byteValueExact();
+ Assert.fail("Failed to get expected exception on " + bi + " got " + value);
+ } catch(ArithmeticException ae) {
+ ; // Expected
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/math/BigInteger/UnicodeConstructor.java b/ojluni/src/test/java/math/BigInteger/UnicodeConstructor.java
new file mode 100644
index 0000000..b6b18e8
--- /dev/null
+++ b/ojluni/src/test/java/math/BigInteger/UnicodeConstructor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4040456
+ * @summary Test biginteger constructor with i18n string
+ */
+package test.java.math.BigInteger;
+
+import java.math.*;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * This class tests to see if creating a biginteger with an unicode japanese zero and one succeeds
+ */
+
+// Android-changed: Replace error printing with asserts.
+public class UnicodeConstructor {
+
+ @Test
+ public void testUnicodeConstructor() {
+
+ try {
+ // the code for japanese zero
+ BigInteger b1 = new BigInteger("\uff10");
+
+ // Japanese 1010
+ BigInteger b2 = new BigInteger("\uff11\uff10\uff11\uff10");
+
+ // Android-added: more valid inputs
+ final Object[][] inputs = {
+ { "\u0030", 0 }, // ASCII "0"
+ { "\u0031\u0030\u0031\u0030", 1010 }, // ASCII "1010"
+ { "\u0660", 0 }, // Arabic-Indic Digit Zero
+ { "\u0661\u0660\u0661\u0660", 1010 }, // Arabic-Indic Digit, "1010"
+ { "\u09e6", 0 }, // Bengali Digit Zero
+ { "\u09e7\u09e6\u09e7\u09e6", 1010 }, // Bengali Digit, "1010"
+ };
+ for (Object[] test : inputs) {
+ BigInteger b = new BigInteger((String)test[0]);
+ Assert.assertEquals(b.intValue(), (int)test[1]);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ Assert.fail("BigInteger is not accepting unicode initializers.");
+ }
+
+ }
+
+}
diff --git a/ojluni/src/test/java/security/cert/URICertStoreParameters/TestBasic.java b/ojluni/src/test/java/security/cert/URICertStoreParameters/TestBasic.java
new file mode 100644
index 0000000..baa44d5
--- /dev/null
+++ b/ojluni/src/test/java/security/cert/URICertStoreParameters/TestBasic.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.java.security.cert.URICertStoreParameters;
+
+
+import java.security.cert.CertStore;
+import java.security.cert.URICertStoreParameters;
+import java.net.URI;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+
+/*
+ * @test
+ * @bug 8038084
+ * @summary Basic testing for URICertStoreParameters
+ * @run main TestBasic
+ */
+public class TestBasic {
+
+ @Test
+ public static void testURICertStoreParameters(String[] args) throws Exception {
+ String str1 = "ldap://myownhost:5000/";
+ String str2 = "ldap://myownhost:5000/cn=foo";
+ test(str1, str2);
+ System.out.println("Test passed");
+ }
+
+ private static void test(String str1, String str2) throws Exception {
+ URICertStoreParameters p1 = new URICertStoreParameters(new URI(str1));
+ URICertStoreParameters p1Too = p1.clone();
+ assertEquals(p1Too, p1);
+ assertEquals(p1Too.getURI(), p1.getURI());
+
+ p1Too = new URICertStoreParameters(new URI(str1));
+ URICertStoreParameters p2 = new URICertStoreParameters(new URI(str2));
+
+ assertNotNull(p1);
+ assertEquals(p1, p1);
+ assertEquals(p1.hashCode(), p1.hashCode());
+ assertEquals(p1Too, p1);
+ assertEquals(p1, p1Too);
+ assertEquals(p1Too.hashCode(), p1.hashCode());
+ assertEquals(p1, p2);
+ assertEquals(p1Too, p2);
+ }
+}
diff --git a/ojluni/src/test/java/util/Arrays/ArraysEqCmpTest.java b/ojluni/src/test/java/util/Arrays/ArraysEqCmpTest.java
new file mode 100644
index 0000000..727f7dc
--- /dev/null
+++ b/ojluni/src/test/java/util/Arrays/ArraysEqCmpTest.java
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.util.Arrays;
+
+/*
+ * @test
+ * @bug 8033148 8141409
+ * @summary tests for array equals and compare
+ * @run testng ArraysEqCmpTest
+ */
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import java.util.function.LongFunction;
+import java.util.stream.IntStream;
+
+public class ArraysEqCmpTest {
+
+ // Maximum width in bits
+ static final int MAX_WIDTH = 512;
+
+ static final Map<Class, Integer> typeToWidth;
+
+ static {
+ typeToWidth = new HashMap<>();
+ typeToWidth.put(boolean.class, Byte.SIZE);
+ typeToWidth.put(byte.class, Byte.SIZE);
+ typeToWidth.put(short.class, Short.SIZE);
+ typeToWidth.put(char.class, Character.SIZE);
+ typeToWidth.put(int.class, Integer.SIZE);
+ typeToWidth.put(long.class, Long.SIZE);
+ typeToWidth.put(float.class, Float.SIZE);
+ typeToWidth.put(double.class, Double.SIZE);
+ typeToWidth.put(Object.class, Integer.SIZE); // @@@ 32 or 64?
+ }
+
+ static int arraySizeFor(Class<?> type) {
+ type = type.isPrimitive() ? type : Object.class;
+ return 4 * MAX_WIDTH / typeToWidth.get(type);
+ }
+
+ static abstract class ArrayType<T> {
+ final Class<?> arrayType;
+ final Class<?> componentType;
+ final boolean unsigned;
+
+ final MethodHandle cpy;
+
+ final MethodHandle eq;
+ final MethodHandle eqr;
+ final MethodHandle cmp;
+ final MethodHandle cmpr;
+ final MethodHandle mm;
+ final MethodHandle mmr;
+
+ final MethodHandle getter;
+
+ final MethodHandle toString;
+
+ public ArrayType(Class<T> arrayType) {
+ this(arrayType, false);
+ }
+
+ public ArrayType(Class<T> arrayType, boolean unsigned) {
+ this.arrayType = arrayType;
+ this.componentType = arrayType.getComponentType();
+ this.unsigned = unsigned;
+
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+
+ getter = MethodHandles.arrayElementGetter(arrayType);
+
+ if (componentType.isPrimitive()) {
+ cpy = l.findStatic(Arrays.class, "copyOfRange",
+ MethodType.methodType(arrayType, arrayType, int.class, int.class));
+
+ MethodType eqt = MethodType.methodType(
+ boolean.class, arrayType, arrayType);
+ MethodType eqrt = MethodType.methodType(
+ boolean.class, arrayType, int.class, int.class, arrayType, int.class, int.class);
+
+ eq = l.findStatic(Arrays.class, "equals", eqt);
+ eqr = l.findStatic(Arrays.class, "equals", eqrt);
+
+ String compareName = unsigned ? "compareUnsigned" : "compare";
+ cmp = l.findStatic(Arrays.class, compareName,
+ eqt.changeReturnType(int.class));
+ cmpr = l.findStatic(Arrays.class, compareName,
+ eqrt.changeReturnType(int.class));
+
+ mm = l.findStatic(Arrays.class, "mismatch",
+ eqt.changeReturnType(int.class));
+ mmr = l.findStatic(Arrays.class, "mismatch",
+ eqrt.changeReturnType(int.class));
+
+ toString = l.findStatic(Arrays.class, "toString",
+ MethodType.methodType(String.class, arrayType));
+ }
+ else {
+ cpy = l.findStatic(Arrays.class, "copyOfRange",
+ MethodType.methodType(Object[].class, Object[].class, int.class, int.class));
+
+ MethodType eqt = MethodType.methodType(
+ boolean.class, Object[].class, Object[].class);
+ MethodType eqrt = MethodType.methodType(
+ boolean.class, Object[].class, int.class, int.class, Object[].class, int.class, int.class);
+
+ eq = l.findStatic(Arrays.class, "equals", eqt);
+ eqr = l.findStatic(Arrays.class, "equals", eqrt);
+
+ MethodType cmpt = MethodType.methodType(
+ int.class, Comparable[].class, Comparable[].class);
+ MethodType cmprt = MethodType.methodType(
+ int.class, Comparable[].class, int.class, int.class, Comparable[].class, int.class, int.class);
+
+ cmp = l.findStatic(Arrays.class, "compare", cmpt);
+ cmpr = l.findStatic(Arrays.class, "compare", cmprt);
+
+ mm = l.findStatic(Arrays.class, "mismatch",
+ eqt.changeReturnType(int.class));
+ mmr = l.findStatic(Arrays.class, "mismatch",
+ eqrt.changeReturnType(int.class));
+
+ toString = l.findStatic(Arrays.class, "toString",
+ MethodType.methodType(String.class, Object[].class));
+ }
+
+ }
+ catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String s = arrayType.getCanonicalName();
+ return unsigned ? "unsigned " + s : s;
+ }
+
+ Object construct(int length) {
+ return Array.newInstance(componentType, length);
+ }
+
+ Object copyOf(Object a) {
+ return copyOf(a, 0, Array.getLength(a));
+ }
+
+ Object copyOf(Object a, int from, int to) {
+ try {
+ return (Object) cpy.invoke(a, from, to);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ Object get(Object a, int i) {
+ try {
+ return (Object) getter.invoke(a, i);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ abstract void set(Object a, int i, Object v);
+
+ boolean equals(Object a, Object b) {
+ try {
+ return (boolean) eq.invoke(a, b);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ boolean equals(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (boolean) eqr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ int compare(Object a, Object b) {
+ try {
+ return (int) cmp.invoke(a, b);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ int compare(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (int) cmpr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ int mismatch(Object a, Object b) {
+ try {
+ return (int) mm.invoke(a, b);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ int mismatch(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (int) mmr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ String toString(Object a) {
+ try {
+ return (String) toString.invoke(a);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ static class BoxedIntegers extends ArrayType<Integer[]> {
+ public BoxedIntegers() {
+ super(Integer[].class);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ // Ensure unique reference
+ ((Integer[]) a)[i] = v != null ? new Integer((Integer) v) : null;
+ }
+ }
+
+ static class BoxedIntegersWithReverseComparator extends BoxedIntegers {
+ final Comparator<Integer> c = (a, b) -> {
+ // Nulls sort after non-nulls
+ if (a == null || b == null)
+ return a == null ? b == null ? 0 : 1 : -1;
+
+ return Integer.compare(b, a);
+ };
+
+ final MethodHandle eqc;
+ final MethodHandle eqcr;
+ final MethodHandle cmpc;
+ final MethodHandle cmpcr;
+ final MethodHandle mismatchc;
+ final MethodHandle mismatchcr;
+
+ public BoxedIntegersWithReverseComparator() {
+ try {
+ MethodHandles.Lookup l = MethodHandles.lookup();
+
+ MethodType cmpt = MethodType.methodType(
+ int.class, Object[].class, Object[].class, Comparator.class);
+ MethodType cmprt = MethodType.methodType(
+ int.class, Object[].class, int.class, int.class,
+ Object[].class, int.class, int.class, Comparator.class);
+
+ eqc = l.findStatic(Arrays.class, "equals", cmpt.changeReturnType(boolean.class));
+ eqcr = l.findStatic(Arrays.class, "equals", cmprt.changeReturnType(boolean.class));
+ cmpc = l.findStatic(Arrays.class, "compare", cmpt);
+ cmpcr = l.findStatic(Arrays.class, "compare", cmprt);
+ mismatchc = l.findStatic(Arrays.class, "mismatch", cmpt);
+ mismatchcr = l.findStatic(Arrays.class, "mismatch", cmprt);
+ }
+ catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ @Override
+ boolean equals(Object a, Object b) {
+ try {
+ return (boolean) eqc.invoke(a, b, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ boolean equals(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (boolean) eqcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ int compare(Object a, Object b) {
+ try {
+ return (int) cmpc.invoke(a, b, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ int compare(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (int) cmpcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ int mismatch(Object a, Object b) {
+ try {
+ return (int) mismatchc.invoke(a, b, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ int mismatch(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (int) mismatchcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return arrayType.getCanonicalName() + " with Comparator";
+ }
+ }
+
+ static class Booleans extends ArrayType<boolean[]> {
+ public Booleans() {
+ super(boolean[].class);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ boolean pv;
+ if (v instanceof Boolean) {
+ pv = (Boolean) v;
+ }
+ else if (v instanceof Integer) {
+ pv = ((Integer) v) >= 0;
+ }
+ else throw new IllegalStateException();
+
+ ((boolean[]) a)[i] = pv;
+ }
+ }
+
+ static class Bytes extends ArrayType<byte[]> {
+ public Bytes(boolean unsigned) {
+ super(byte[].class, unsigned);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ byte pv;
+ if (v instanceof Byte) {
+ pv = (Byte) v;
+ }
+ else if (v instanceof Integer) {
+ pv = ((Integer) v).byteValue();
+ }
+ else throw new IllegalStateException();
+
+ ((byte[]) a)[i] = pv;
+ }
+ }
+
+ static class Characters extends ArrayType<char[]> {
+ public Characters() {
+ super(char[].class);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ char pv;
+ if (v instanceof Character) {
+ pv = (Character) v;
+ }
+ else if (v instanceof Integer) {
+ pv = (char) ((Integer) v).intValue();
+ }
+ else throw new IllegalStateException();
+
+ ((char[]) a)[i] = pv;
+ }
+ }
+
+ static class Shorts extends ArrayType<short[]> {
+ public Shorts(boolean unsigned) {
+ super(short[].class, unsigned);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ short pv;
+ if (v instanceof Short) {
+ pv = (Short) v;
+ }
+ else if (v instanceof Integer) {
+ pv = ((Integer) v).shortValue();
+ }
+ else throw new IllegalStateException();
+
+ ((short[]) a)[i] = pv;
+ }
+ }
+
+ static class Integers extends ArrayType<int[]> {
+ public Integers(boolean unsigned) {
+ super(int[].class, unsigned);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ int pv;
+ if (v instanceof Integer) {
+ pv = ((Integer) v).shortValue();
+ }
+ else throw new IllegalStateException();
+
+ ((int[]) a)[i] = pv;
+ }
+ }
+
+ static class Longs extends ArrayType<long[]> {
+ public Longs(boolean unsigned) {
+ super(long[].class, unsigned);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ long pv;
+ if (v instanceof Long) {
+ pv = (Long) v;
+ }
+ else if (v instanceof Integer) {
+ pv = ((Integer) v).longValue();
+ }
+ else throw new IllegalStateException();
+
+ ((long[]) a)[i] = pv;
+ }
+ }
+
+ static class Floats extends ArrayType<float[]> {
+ public Floats() {
+ super(float[].class);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ float pv;
+ if (v instanceof Float) {
+ pv = (Float) v;
+ }
+ else if (v instanceof Integer) {
+ pv = ((Integer) v).floatValue();
+ }
+ else throw new IllegalStateException();
+
+ ((float[]) a)[i] = pv;
+ }
+ }
+
+ static class Doubles extends ArrayType<double[]> {
+ public Doubles() {
+ super(double[].class);
+ }
+
+ @Override
+ void set(Object a, int i, Object v) {
+ double pv;
+ if (v instanceof Double) {
+ pv = (Double) v;
+ }
+ else if (v instanceof Integer) {
+ pv = ((Integer) v).doubleValue();
+ }
+ else throw new IllegalStateException();
+
+ ((double[]) a)[i] = pv;
+ }
+ }
+ }
+
+ static Object[][] arrayTypes;
+
+ @DataProvider
+ public static Object[][] arrayTypesProvider() {
+ if (arrayTypes == null) {
+ arrayTypes = new Object[][]{
+ new Object[]{new ArrayType.BoxedIntegers()},
+ new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()},
+ new Object[]{new ArrayType.Booleans()},
+ new Object[]{new ArrayType.Bytes(false)},
+ new Object[]{new ArrayType.Bytes(true)},
+ new Object[]{new ArrayType.Characters()},
+ new Object[]{new ArrayType.Shorts(false)},
+ new Object[]{new ArrayType.Shorts(true)},
+ new Object[]{new ArrayType.Integers(false)},
+ new Object[]{new ArrayType.Integers(true)},
+ new Object[]{new ArrayType.Longs(false)},
+ new Object[]{new ArrayType.Longs(true)},
+ new Object[]{new ArrayType.Floats()},
+ new Object[]{new ArrayType.Doubles()},
+ };
+ }
+ return arrayTypes;
+ }
+
+ static Object[][] floatArrayTypes;
+
+ @DataProvider
+ public static Object[][] floatArrayTypesProvider() {
+ if (floatArrayTypes == null) {
+ LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
+ LongFunction<Object> bToD = Double::longBitsToDouble;
+
+ floatArrayTypes = new Object[][]{
+ new Object[]{new ArrayType.Floats(), 0x7fc00000L, 0x7f800001L, bTof},
+ new Object[]{new ArrayType.Doubles(), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
+ };
+ }
+ return floatArrayTypes;
+ }
+
+ static Object[][] objectArrayTypes;
+
+ @DataProvider
+ public static Object[][] objectArrayTypesProvider() {
+ if (objectArrayTypes == null) {
+ LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
+ LongFunction<Object> bToD = Double::longBitsToDouble;
+
+ objectArrayTypes = new Object[][]{
+ new Object[]{new ArrayType.BoxedIntegers()},
+ new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()},
+ };
+ }
+ return objectArrayTypes;
+ }
+
+
+ static Object[][] signedUnsignedArrayTypes;
+
+ @DataProvider
+ public static Object[][] signedUnsignedArrayTypes() {
+ if (signedUnsignedArrayTypes == null) {
+ signedUnsignedArrayTypes = new Object[][]{
+ new Object[]{new ArrayType.Bytes(false), new ArrayType.Bytes(true)},
+ new Object[]{new ArrayType.Shorts(false), new ArrayType.Shorts(true)},
+ new Object[]{new ArrayType.Integers(false), new ArrayType.Integers(true)},
+ new Object[]{new ArrayType.Longs(false), new ArrayType.Longs(true)},
+ };
+ }
+ return signedUnsignedArrayTypes;
+ }
+
+ // Equality and comparison tests
+
+ @Test(dataProvider = "arrayTypesProvider")
+ public void testArray(ArrayType<?> arrayType) {
+ BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> {
+ Object a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, x % 8);
+ }
+ return a;
+ };
+
+ BiFunction<ArrayType<?>, Object, Object> cloner = (at, a) ->
+ constructor.apply(at, Array.getLength(a));
+
+ testArrayType(arrayType, constructor, cloner);
+ }
+
+ @Test(dataProvider = "floatArrayTypesProvider")
+ public void testPrimitiveFloatArray(
+ ArrayType<?> arrayType,
+ long canonicalNanRawBits, long nonCanonicalNanRawBits,
+ LongFunction<Object> bitsToFloat) {
+ Object canonicalNan = bitsToFloat.apply(canonicalNanRawBits);
+ // If conversion is a signalling NaN it may be subject to conversion to a
+ // quiet NaN on some processors, even if a copy is performed
+ // The tests assume that if conversion occurs it does not convert to the
+ // canonical NaN
+ Object nonCanonicalNan = bitsToFloat.apply(nonCanonicalNanRawBits);
+
+ BiFunction<ArrayType<?>, Integer, Object> canonicalNaNs = (at, s) -> {
+ Object a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, canonicalNan);
+ }
+ return a;
+ };
+
+ BiFunction<ArrayType<?>, Object, Object> nonCanonicalNaNs = (at, a) -> {
+ int s = Array.getLength(a);
+ Object ac = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(ac, x, nonCanonicalNan);
+ }
+ return ac;
+ };
+
+ BiFunction<ArrayType<?>, Object, Object> halfNonCanonicalNaNs = (at, a) -> {
+ int s = Array.getLength(a);
+ Object ac = at.construct(s);
+ for (int x = 0; x < s / 2; x++) {
+ at.set(ac, x, nonCanonicalNan);
+ }
+ for (int x = s / 2; x < s; x++) {
+ at.set(ac, x, 1);
+ }
+ return ac;
+ };
+
+ testArrayType(arrayType, canonicalNaNs, nonCanonicalNaNs);
+ testArrayType(arrayType, canonicalNaNs, halfNonCanonicalNaNs);
+ }
+
+ @Test(dataProvider = "objectArrayTypesProvider")
+ public void testNullElementsInObjectArray(ArrayType<?> arrayType) {
+ BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf;
+
+ // All nulls
+ testArrayType(arrayType,
+ (at, s) -> {
+ Object a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, null);
+ }
+ return a;
+ },
+ cloner);
+
+
+ // Some nulls
+ testArrayType(arrayType,
+ (at, s) -> {
+ Object a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ int v = x % 8;
+ at.set(a, x, v == 0 ? null : v);
+ }
+ return a;
+ },
+ cloner);
+
+ Integer[] a = new Integer[]{null, 0};
+ Integer[] b = new Integer[]{0, 0};
+ Assert.assertTrue(Arrays.compare(a, b) < 0);
+ Assert.assertTrue(Arrays.compare(b, a) > 0);
+ }
+
+ @Test(dataProvider = "objectArrayTypesProvider")
+ public void testSameRefElementsInObjectArray(ArrayType<?> arrayType) {
+ BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf;
+
+ // One ref
+ Integer one = 1;
+ testArrayType(arrayType,
+ (at, s) -> {
+ Integer[] a = (Integer[]) at.construct(s);
+ for (int x = 0; x < s; x++) {
+ a[x] = one;
+ }
+ return a;
+ },
+ cloner);
+
+ // All ref
+ testArrayType(arrayType,
+ (at, s) -> {
+ Integer[] a = (Integer[]) at.construct(s);
+ for (int x = 0; x < s; x++) {
+ a[x] = Integer.valueOf(s);
+ }
+ return a;
+ },
+ cloner);
+
+ // Some same ref
+ testArrayType(arrayType,
+ (at, s) -> {
+ Integer[] a = (Integer[]) at.construct(s);
+ for (int x = 0; x < s; x++) {
+ int v = x % 8;
+ a[x] = v == 1 ? one : new Integer(v);
+ }
+ return a;
+ },
+ cloner);
+ }
+
+ @Test(dataProvider = "signedUnsignedArrayTypes")
+ public void testSignedUnsignedArray(ArrayType<?> sat, ArrayType<?> uat) {
+ BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> {
+ Object a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, 1);
+ }
+ return a;
+ };
+
+ int n = arraySizeFor(sat.componentType);
+
+ for (int s : ranges(0, n)) {
+ Object a = constructor.apply(sat, s);
+
+ for (int aFrom : ranges(0, s)) {
+ for (int aTo : ranges(aFrom, s)) {
+ int aLength = aTo - aFrom;
+
+ if (aLength > 0) {
+ for (int i = aFrom; i < aTo; i++) {
+ Object ac = sat.copyOf(a);
+ // Create common prefix with a length of i - aFrom
+ sat.set(ac, i, -1);
+
+ int sc = sat.compare(ac, aFrom, aTo, a, aFrom, aTo);
+ int uc = uat.compare(ac, aFrom, aTo, a, aFrom, aTo);
+
+ Assert.assertTrue(sc < 0);
+ Assert.assertTrue(uc > 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void testArrayType(ArrayType<?> at,
+ BiFunction<ArrayType<?>, Integer, Object> constructor,
+ BiFunction<ArrayType<?>, Object, Object> cloner) {
+ int n = arraySizeFor(at.componentType);
+
+ for (int s : ranges(0, n)) {
+ Object a = constructor.apply(at, s);
+ Object b = cloner.apply(at, a);
+
+ for (int aFrom : ranges(0, s)) {
+ for (int aTo : ranges(aFrom, s)) {
+ int aLength = aTo - aFrom;
+
+ for (int bFrom : ranges(0, s)) {
+ for (int bTo : ranges(bFrom, s)) {
+ int bLength = bTo - bFrom;
+
+ Object anr = at.copyOf(a, aFrom, aTo);
+ Object bnr = at.copyOf(b, bFrom, bTo);
+
+ boolean eq = isEqual(at, a, aFrom, aTo, b, bFrom, bTo);
+ Assert.assertEquals(at.equals(a, aFrom, aTo, b, bFrom, bTo), eq);
+ Assert.assertEquals(at.equals(b, bFrom, bTo, a, aFrom, aTo), eq);
+ Assert.assertEquals(at.equals(anr, bnr), eq);
+ Assert.assertEquals(at.equals(bnr, anr), eq);
+ if (eq) {
+ Assert.assertEquals(at.compare(a, aFrom, aTo, b, bFrom, bTo), 0);
+ Assert.assertEquals(at.compare(b, bFrom, bTo, a, aFrom, aTo), 0);
+ Assert.assertEquals(at.compare(anr, bnr), 0);
+ Assert.assertEquals(at.compare(bnr, anr), 0);
+
+ Assert.assertEquals(at.mismatch(a, aFrom, aTo, b, bFrom, bTo), -1);
+ Assert.assertEquals(at.mismatch(b, bFrom, bTo, a, aFrom, aTo), -1);
+ Assert.assertEquals(at.mismatch(anr, bnr), -1);
+ Assert.assertEquals(at.mismatch(bnr, anr), -1);
+ }
+ else {
+ int aCb = at.compare(a, aFrom, aTo, b, bFrom, bTo);
+ int bCa = at.compare(b, bFrom, bTo, a, aFrom, aTo);
+ int v = Integer.signum(aCb) * Integer.signum(bCa);
+ Assert.assertTrue(v == -1);
+
+ int anrCbnr = at.compare(anr, bnr);
+ int bnrCanr = at.compare(bnr, anr);
+ Assert.assertEquals(anrCbnr, aCb);
+ Assert.assertEquals(bnrCanr, bCa);
+
+
+ int aMb = at.mismatch(a, aFrom, aTo, b, bFrom, bTo);
+ int bMa = at.mismatch(b, bFrom, bTo, a, aFrom, aTo);
+ int anrMbnr = at.mismatch(anr, bnr);
+ int bnrManr = at.mismatch(bnr, anr);
+
+ Assert.assertNotEquals(aMb, -1);
+ Assert.assertEquals(aMb, bMa);
+ Assert.assertNotEquals(anrMbnr, -1);
+ Assert.assertEquals(anrMbnr, bnrManr);
+ Assert.assertEquals(aMb, anrMbnr);
+ Assert.assertEquals(bMa, bnrManr);
+
+ // Common or proper prefix
+ Assert.assertTrue(at.equals(a, aFrom, aFrom + aMb, b, bFrom, bFrom + aMb));
+ if (aMb < Math.min(aLength, bLength)) {
+ // Common prefix
+ Assert.assertFalse(isEqual(at, a, aFrom + aMb, b, bFrom + aMb));
+ }
+ }
+ }
+ }
+
+ if (aLength > 0) {
+ for (int i = aFrom; i < aTo; i++) {
+ Object ac = at.copyOf(a);
+ // Create common prefix with a length of i - aFrom
+ at.set(ac, i, -1);
+
+ Object acnr = at.copyOf(ac, aFrom, aTo);
+ Object anr = at.copyOf(a, aFrom, aTo);
+
+ Assert.assertFalse(at.equals(ac, aFrom, aTo, a, aFrom, aTo));
+ Assert.assertFalse(at.equals(acnr, anr));
+
+ int acCa = at.compare(ac, aFrom, aTo, a, aFrom, aTo);
+ int aCac = at.compare(a, aFrom, aTo, ac, aFrom, aTo);
+ int v = Integer.signum(acCa) * Integer.signum(aCac);
+ Assert.assertTrue(v == -1);
+
+ int acnrCanr = at.compare(acnr, anr);
+ int anrCacnr = at.compare(anr, acnr);
+ Assert.assertEquals(acnrCanr, acCa);
+ Assert.assertEquals(anrCacnr, aCac);
+
+
+ int acMa = at.mismatch(ac, aFrom, aTo, a, aFrom, aTo);
+ int aMac = at.mismatch(a, aFrom, aTo, ac, aFrom, aTo);
+ Assert.assertEquals(acMa, aMac);
+ Assert.assertEquals(acMa, i - aFrom);
+
+ int acnrManr = at.mismatch(acnr, anr);
+ int anrMacnr = at.mismatch(anr, acnr);
+ Assert.assertEquals(acnrManr, anrMacnr);
+ Assert.assertEquals(acnrManr, i - aFrom);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static boolean isEqual(ArrayType<?> at, Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ int aLength = aToIndex - aFromIndex;
+ int bLength = bToIndex - bFromIndex;
+ if (aLength != bLength)
+ return false;
+
+ for (int i = 0; i < aLength; i++) {
+ Object av = at.get(a, aFromIndex++);
+ Object bv = at.get(b, bFromIndex++);
+ if (!Objects.equals(av, bv)) return false;
+ }
+
+ return true;
+ }
+
+ static boolean isEqual(ArrayType<?> at, Object a, int aFrom, Object b, int bFrom) {
+ Object av = at.get(a, aFrom);
+ Object bv = at.get(b, bFrom);
+
+ return Objects.equals(av, bv);
+ }
+
+ static int[] ranges(int from, int to) {
+ int width = to - from;
+ switch (width) {
+ case 0:
+ return new int[]{};
+ case 1:
+ return new int[]{from, to};
+ case 2:
+ return new int[]{from, from + 1, to};
+ case 3:
+ return new int[]{from, from + 1, from + 2, to};
+ default:
+ return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)
+ .filter(i -> i >= from && i <= to)
+ .distinct().toArray();
+ }
+ }
+
+
+ // Null array reference tests
+
+ @Test(dataProvider = "arrayTypesProvider")
+ public void testNullArrayRefs(ArrayType<?> arrayType) {
+ Object n = null;
+ Object a = arrayType.construct(0);
+
+ Assert.assertTrue(arrayType.equals(n, n));
+ Assert.assertFalse(arrayType.equals(n, a));
+ Assert.assertFalse(arrayType.equals(a, n));
+
+ Assert.assertEquals(arrayType.compare(n, n), 0);
+ Assert.assertTrue(arrayType.compare(n, a) < 0);
+ Assert.assertTrue(arrayType.compare(a, n) > 0);
+ }
+
+
+ // Exception throwing tests
+
+ @Test(dataProvider = "arrayTypesProvider")
+ public void testNPEs(ArrayType<?> arrayType) {
+ Object[] values = new Object[]{null, arrayType.construct(0)};
+
+ for (Object o1 : values) {
+ for (Object o2 : values) {
+ if (o1 != null && o2 != null)
+ continue;
+
+ testNPE(() -> arrayType.equals(o1, 0, 0, o2, 0, 0));
+ testNPE(() -> arrayType.compare(o1, 0, 0, o2, 0, 0));
+ testNPE(() -> arrayType.mismatch(o1, o2));
+ testNPE(() -> arrayType.mismatch(o1, 0, 0, o2, 0, 0));
+ }
+ }
+ }
+
+ @Test
+ public void testObjectNPEs() {
+ String[][] values = new String[][]{null, new String[0]};
+ Comparator<String> c = String::compareTo;
+ Comparator[] cs = new Comparator[]{null, c};
+
+ for (String[] o1 : values) {
+ for (String[] o2 : values) {
+ for (Comparator o3 : cs) {
+ if (o1 != null && o2 != null && o3 != null)
+ continue;
+
+ if (o3 == null) {
+ testNPE(() -> Arrays.equals(o1, o2, o3));
+ testNPE(() -> Arrays.compare(o1, o2, o3));
+ testNPE(() -> Arrays.mismatch(o1, o2, o3));
+ }
+
+ testNPE(() -> Arrays.equals(o1, 0, 0, o2, 0, 0, o3));
+ testNPE(() -> Arrays.compare(o1, 0, 0, o2, 0, 0, o3));
+ testNPE(() -> Arrays.mismatch(o1, 0, 0, o2, 0, 0, o3));
+ }
+ }
+ }
+ }
+
+ @Test(dataProvider = "arrayTypesProvider")
+ public void testIAEs(ArrayType<?> arrayType) {
+ List<Integer> values = Arrays.asList(0, 1);
+
+ for (int s : values) {
+ Object a = arrayType.construct(s);
+
+ for (int o1 : values) {
+ for (int o2 : values) {
+ if (o1 <= o2) continue;
+
+ testIAE(() -> arrayType.equals(a, o1, 0, a, o2, 0));
+ testIAE(() -> arrayType.compare(a, o1, 0, a, o2, 0));
+ testIAE(() -> arrayType.mismatch(a, o1, 0, a, o2, 0));
+ }
+ }
+ }
+ }
+
+ @Test(dataProvider = "arrayTypesProvider")
+ public void testAIOBEs(ArrayType<?> arrayType) {
+ List<Integer> froms = Arrays.asList(-1, 0);
+
+ for (int s : Arrays.asList(0, 1)) {
+ List<Integer> tos = Arrays.asList(s, s + 1);
+ Object a = arrayType.construct(s);
+
+ for (int aFrom : froms) {
+ for (int aTo : tos) {
+ for (int bFrom : froms) {
+ for (int bTo : tos) {
+ if (aFrom >= 0 && aTo <= s &&
+ bFrom >= 0 && bTo <= s) continue;
+
+ testAIOBE(() -> arrayType.equals(a, aFrom, aTo, a, bFrom, bTo));
+ testAIOBE(() -> arrayType.compare(a, aFrom, aTo, a, bFrom, bTo));
+ testAIOBE(() -> arrayType.mismatch(a, aFrom, aTo, a, bFrom, bTo));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static void testNPE(Runnable r) {
+ testThrowable(r, NullPointerException.class);
+ }
+
+ static void testIAE(Runnable r) {
+ testThrowable(r, IllegalArgumentException.class);
+ }
+
+ static void testAIOBE(Runnable r) {
+ testThrowable(r, ArrayIndexOutOfBoundsException.class);
+ }
+
+ static void testThrowable(Runnable r, Class<? extends Throwable> expected) {
+ Throwable caught = null;
+ try {
+ r.run();
+ }
+ catch (Throwable t) {
+ caught = t;
+ }
+ Assert.assertNotNull(caught);
+ Assert.assertTrue(expected.isInstance(caught));
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/util/Collections/EnumerationAsIterator.java b/ojluni/src/test/java/util/Collections/EnumerationAsIterator.java
new file mode 100644
index 0000000..60cad8f
--- /dev/null
+++ b/ojluni/src/test/java/util/Collections/EnumerationAsIterator.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.util.Collections;
+
+/**
+ * @test
+ * @bug 8072726
+ * @summary Tests for Enumeration-to-Iterator conversion.
+ * @run testng EnumerationAsIterator
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import static org.testng.Assert.*;
+
+@Test
+public class EnumerationAsIterator {
+ static Object[] of(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+ return new Object[]{description, s, exp};
+ }
+
+ static Object[] of(String description, Collection<?> c, Collection<?> exp) {
+ return of(description, () -> Collections.enumeration(c), exp);
+ }
+
+ /**
+ * A wrapper Enumeration that doesn't override the
+ * default method on Enumeration.
+ */
+ static <T> Enumeration<T> wrapInDefault(Enumeration<T> e) {
+ return new Enumeration<>() {
+ @Override
+ public boolean hasMoreElements() {
+ return e.hasMoreElements();
+ }
+
+ @Override
+ public T nextElement() {
+ return e.nextElement();
+ }
+ };
+ }
+
+ @DataProvider
+ public static Iterator<Object[]> unmodifiable() {
+ return Arrays.asList(
+ of("Default-wrapped ArrayList",
+ () -> wrapInDefault(
+ Collections.enumeration(new ArrayList<>(Arrays.asList("a")))),
+ Arrays.asList("a")),
+
+ of("Unmodifiable ArrayList",
+ Collections.unmodifiableList(new ArrayList<>(Arrays.asList("a"))),
+ Arrays.asList("a")),
+
+ of("Modifiable ArrayList",
+ new ArrayList<>(Arrays.asList("a")),
+ Arrays.asList("a"))
+ ).iterator();
+ }
+
+ @DataProvider
+ public static Iterator<Object[]> others() {
+ return Arrays.asList(
+ of("Default Collections.emptyEnumeration()",
+ () -> wrapInDefault(Collections.emptyEnumeration()),
+ Collections.emptyList()),
+
+ of("Collections.emptyEnumeration()",
+ Collections::emptyEnumeration,
+ Collections.emptyList()),
+
+ of("Collections.emptyList()",
+ Collections.emptyList(),
+ Collections.emptyList()),
+
+ of("Collections.singletonList()",
+ Collections.singletonList("a"),
+ Collections.singletonList("a")),
+
+ of("Arrays.asList(...)",
+ Arrays.asList("a", "b", "c"),
+ Arrays.asList("a", "b", "c"))
+ ).iterator();
+ }
+
+ @DataProvider
+ public static Iterator<Object[]> all() {
+ List<Object[]> all = new ArrayList<>();
+ unmodifiable().forEachRemaining(all::add);
+ others().forEachRemaining(all::add);
+ return all.iterator();
+ }
+
+ @Test(dataProvider = "all")
+ public void consumeByNext(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+ Iterator<?> i = s.get().asIterator();
+ int count = 0;
+ while (i.hasNext()) {
+ assertTrue(i.hasNext());
+
+ i.next();
+ count++;
+ }
+ assertEquals(count, exp.size());
+
+ assertFalse(i.hasNext());
+
+ try {
+ i.next();
+ fail();
+ } catch (NoSuchElementException e) {
+ }
+ }
+
+ @Test(dataProvider = "all")
+ public void consumeByForEachRemaining(String description,
+ Supplier<Enumeration<?>> s,
+ Collection<?> exp) {
+ Iterator<?> i = s.get().asIterator();
+ AtomicInteger ai = new AtomicInteger();
+ i.forEachRemaining(e -> ai.getAndIncrement());
+ assertEquals(ai.get(), exp.size());
+ i.forEachRemaining(e -> ai.getAndIncrement());
+ assertEquals(ai.get(), exp.size());
+
+ assertFalse(i.hasNext());
+
+ try {
+ i.next();
+ fail();
+ } catch (NoSuchElementException e) {
+ }
+ }
+
+ @Test(dataProvider = "all")
+ public void consumeByNextThenForEachRemaining(String description,
+ Supplier<Enumeration<?>> s,
+ Collection<?> exp) {
+ Iterator<?> i = s.get().asIterator();
+ AtomicInteger ai = new AtomicInteger();
+ if (i.hasNext()) {
+ i.next();
+ ai.getAndIncrement();
+ }
+ i.forEachRemaining(e -> ai.getAndIncrement());
+ assertEquals(ai.get(), exp.size());
+ i.forEachRemaining(e -> ai.getAndIncrement());
+ assertEquals(ai.get(), exp.size());
+
+ assertFalse(i.hasNext());
+
+ try {
+ i.next();
+ fail();
+ } catch (NoSuchElementException e) {
+ }
+ }
+
+ @Test(dataProvider = "all")
+ public void contents(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+ assertEquals(copy(s.get()), exp);
+ }
+
+ private List<?> copy(Enumeration<?> input) {
+ List<Object> output = new ArrayList<>();
+ input.asIterator().forEachRemaining(output::add);
+ return output;
+ }
+
+ @Test(dataProvider = "unmodifiable",
+ expectedExceptions=UnsupportedOperationException.class)
+ public void removeThrowsAfterAdvancingE(String description,
+ Supplier<Enumeration<?>> s,
+ Collection<?> exp) {
+ Enumeration<?> e = s.get();
+ e.nextElement();
+ e.asIterator().remove();
+ }
+
+ @Test(dataProvider = "unmodifiable",
+ expectedExceptions=UnsupportedOperationException.class)
+ public void removeThrowsAfterAdvancingI(String description,
+ Supplier<Enumeration<?>> s,
+ Collection<?> exp) {
+ Iterator<?> i = s.get().asIterator();
+ i.next();
+ i.remove();
+ }
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java b/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
index e97a0ab..ada751c 100644
--- a/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
+++ b/ojluni/src/test/java/util/concurrent/tck/CompletableFutureTest.java
@@ -170,7 +170,7 @@
assertFalse(f.isCancelled());
assertTrue(f.isDone());
assertTrue(f.isCompletedExceptionally());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
}
void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -225,7 +225,7 @@
assertTrue(f.isDone());
assertTrue(f.isCompletedExceptionally());
assertTrue(f.isCancelled());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
}
/**
@@ -372,12 +372,12 @@
f = new CompletableFuture<String>();
assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
f = new CompletableFuture<String>();
assertTrue(f.cancel(mayInterruptIfRunning));
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().contains("[Completed exceptionally:"));
}
}
diff --git a/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java b/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
index 575a8f3..f821a3b 100644
--- a/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
+++ b/ojluni/src/test/java/util/concurrent/tck/JSR166TestCase.java
@@ -590,6 +590,7 @@
"AtomicReferenceArray9Test",
"ExecutorCompletionService9Test",
"ForkJoinPool9Test",
+ "SubmissionPublisherTest",
};
addNamedTestClasses(suite, java9TestClassNames);
}
diff --git a/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java b/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java
new file mode 100644
index 0000000..bfdecbe
--- /dev/null
+++ b/ojluni/src/test/java/util/concurrent/tck/SubmissionPublisherTest.java
@@ -0,0 +1,1036 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package test.java.util.concurrent.tck;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Flow;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.SubmissionPublisher;
+import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import static java.util.concurrent.Flow.Subscriber;
+import static java.util.concurrent.Flow.Subscription;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class SubmissionPublisherTest extends JSR166TestCase {
+
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(SubmissionPublisherTest.class);
+ }
+
+ final Executor basicExecutor = basicPublisher().getExecutor();
+
+ static SubmissionPublisher<Integer> basicPublisher() {
+ return new SubmissionPublisher<Integer>();
+ }
+
+ static class SPException extends RuntimeException {}
+
+ class TestSubscriber implements Subscriber<Integer> {
+ volatile Subscription sn;
+ int last; // Requires that onNexts are in numeric order
+ volatile int nexts;
+ volatile int errors;
+ volatile int completes;
+ volatile boolean throwOnCall = false;
+ volatile boolean request = true;
+ volatile Throwable lastError;
+
+ public synchronized void onSubscribe(Subscription s) {
+ threadAssertTrue(sn == null);
+ sn = s;
+ notifyAll();
+ if (throwOnCall)
+ throw new SPException();
+ if (request)
+ sn.request(1L);
+ }
+ public synchronized void onNext(Integer t) {
+ ++nexts;
+ notifyAll();
+ int current = t.intValue();
+ threadAssertTrue(current >= last);
+ last = current;
+ if (request)
+ sn.request(1L);
+ if (throwOnCall)
+ throw new SPException();
+ }
+ public synchronized void onError(Throwable t) {
+ threadAssertTrue(completes == 0);
+ threadAssertTrue(errors == 0);
+ lastError = t;
+ ++errors;
+ notifyAll();
+ }
+ public synchronized void onComplete() {
+ threadAssertTrue(completes == 0);
+ ++completes;
+ notifyAll();
+ }
+
+ synchronized void awaitSubscribe() {
+ while (sn == null) {
+ try {
+ wait();
+ } catch (Exception ex) {
+ threadUnexpectedException(ex);
+ break;
+ }
+ }
+ }
+ synchronized void awaitNext(int n) {
+ while (nexts < n) {
+ try {
+ wait();
+ } catch (Exception ex) {
+ threadUnexpectedException(ex);
+ break;
+ }
+ }
+ }
+ synchronized void awaitComplete() {
+ while (completes == 0 && errors == 0) {
+ try {
+ wait();
+ } catch (Exception ex) {
+ threadUnexpectedException(ex);
+ break;
+ }
+ }
+ }
+ synchronized void awaitError() {
+ while (errors == 0) {
+ try {
+ wait();
+ } catch (Exception ex) {
+ threadUnexpectedException(ex);
+ break;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * A new SubmissionPublisher has no subscribers, a non-null
+ * executor, a power-of-two capacity, is not closed, and reports
+ * zero demand and lag
+ */
+ void checkInitialState(SubmissionPublisher<?> p) {
+ assertFalse(p.hasSubscribers());
+ assertEquals(0, p.getNumberOfSubscribers());
+ assertTrue(p.getSubscribers().isEmpty());
+ assertFalse(p.isClosed());
+ assertNull(p.getClosedException());
+ int n = p.getMaxBufferCapacity();
+ assertTrue((n & (n - 1)) == 0); // power of two
+ assertNotNull(p.getExecutor());
+ assertEquals(0, p.estimateMinimumDemand());
+ assertEquals(0, p.estimateMaximumLag());
+ }
+
+ /**
+ * A default-constructed SubmissionPublisher has no subscribers,
+ * is not closed, has default buffer size, and uses the
+ * defaultExecutor
+ */
+ public void testConstructor1() {
+ SubmissionPublisher<Integer> p = new SubmissionPublisher<>();
+ checkInitialState(p);
+ assertEquals(p.getMaxBufferCapacity(), Flow.defaultBufferSize());
+ Executor e = p.getExecutor(), c = ForkJoinPool.commonPool();
+ if (ForkJoinPool.getCommonPoolParallelism() > 1)
+ assertSame(e, c);
+ else
+ assertNotSame(e, c);
+ }
+
+ /**
+ * A new SubmissionPublisher has no subscribers, is not closed,
+ * has the given buffer size, and uses the given executor
+ */
+ public void testConstructor2() {
+ Executor e = Executors.newFixedThreadPool(1);
+ SubmissionPublisher<Integer> p = new SubmissionPublisher<>(e, 8);
+ checkInitialState(p);
+ assertSame(p.getExecutor(), e);
+ assertEquals(8, p.getMaxBufferCapacity());
+ }
+
+ /**
+ * A null Executor argument to SubmissionPublisher constructor
+ * throws NullPointerException
+ */
+ public void testConstructor3() {
+ try {
+ new SubmissionPublisher<Integer>(null, 8);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A negative capacity argument to SubmissionPublisher constructor
+ * throws IllegalArgumentException
+ */
+ public void testConstructor4() {
+ Executor e = Executors.newFixedThreadPool(1);
+ try {
+ new SubmissionPublisher<Integer>(e, -1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * A closed publisher reports isClosed with no closedException and
+ * throws IllegalStateException upon attempted submission; a
+ * subsequent close or closeExceptionally has no additional
+ * effect.
+ */
+ public void testClose() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ checkInitialState(p);
+ p.close();
+ assertTrue(p.isClosed());
+ assertNull(p.getClosedException());
+ try {
+ p.submit(1);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ Throwable ex = new SPException();
+ p.closeExceptionally(ex);
+ assertTrue(p.isClosed());
+ assertNull(p.getClosedException());
+ }
+
+ /**
+ * A publisher closedExceptionally reports isClosed with the
+ * closedException and throws IllegalStateException upon attempted
+ * submission; a subsequent close or closeExceptionally has no
+ * additional effect.
+ */
+ public void testCloseExceptionally() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ checkInitialState(p);
+ Throwable ex = new SPException();
+ p.closeExceptionally(ex);
+ assertTrue(p.isClosed());
+ assertSame(p.getClosedException(), ex);
+ try {
+ p.submit(1);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ p.close();
+ assertTrue(p.isClosed());
+ assertSame(p.getClosedException(), ex);
+ }
+
+ /**
+ * Upon subscription, the subscriber's onSubscribe is called, no
+ * other Subscriber methods are invoked, the publisher
+ * hasSubscribers, isSubscribed is true, and existing
+ * subscriptions are unaffected.
+ */
+ public void testSubscribe1() {
+ TestSubscriber s = new TestSubscriber();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ p.subscribe(s);
+ assertTrue(p.hasSubscribers());
+ assertEquals(1, p.getNumberOfSubscribers());
+ assertTrue(p.getSubscribers().contains(s));
+ assertTrue(p.isSubscribed(s));
+ s.awaitSubscribe();
+ assertNotNull(s.sn);
+ assertEquals(0, s.nexts);
+ assertEquals(0, s.errors);
+ assertEquals(0, s.completes);
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s2);
+ assertTrue(p.hasSubscribers());
+ assertEquals(2, p.getNumberOfSubscribers());
+ assertTrue(p.getSubscribers().contains(s));
+ assertTrue(p.getSubscribers().contains(s2));
+ assertTrue(p.isSubscribed(s));
+ assertTrue(p.isSubscribed(s2));
+ s2.awaitSubscribe();
+ assertNotNull(s2.sn);
+ assertEquals(0, s2.nexts);
+ assertEquals(0, s2.errors);
+ assertEquals(0, s2.completes);
+ p.close();
+ }
+
+ /**
+ * If closed, upon subscription, the subscriber's onComplete
+ * method is invoked
+ */
+ public void testSubscribe2() {
+ TestSubscriber s = new TestSubscriber();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ p.close();
+ p.subscribe(s);
+ s.awaitComplete();
+ assertEquals(0, s.nexts);
+ assertEquals(0, s.errors);
+ assertEquals(1, s.completes, 1);
+ }
+
+ /**
+ * If closedExceptionally, upon subscription, the subscriber's
+ * onError method is invoked
+ */
+ public void testSubscribe3() {
+ TestSubscriber s = new TestSubscriber();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ Throwable ex = new SPException();
+ p.closeExceptionally(ex);
+ assertTrue(p.isClosed());
+ assertSame(p.getClosedException(), ex);
+ p.subscribe(s);
+ s.awaitError();
+ assertEquals(0, s.nexts);
+ assertEquals(1, s.errors);
+ }
+
+ /**
+ * Upon attempted resubscription, the subscriber's onError is
+ * called and the subscription is cancelled.
+ */
+ public void testSubscribe4() {
+ TestSubscriber s = new TestSubscriber();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ p.subscribe(s);
+ assertTrue(p.hasSubscribers());
+ assertEquals(1, p.getNumberOfSubscribers());
+ assertTrue(p.getSubscribers().contains(s));
+ assertTrue(p.isSubscribed(s));
+ s.awaitSubscribe();
+ assertNotNull(s.sn);
+ assertEquals(0, s.nexts);
+ assertEquals(0, s.errors);
+ assertEquals(0, s.completes);
+ p.subscribe(s);
+ s.awaitError();
+ assertEquals(0, s.nexts);
+ assertEquals(1, s.errors);
+ assertFalse(p.isSubscribed(s));
+ }
+
+ /**
+ * An exception thrown in onSubscribe causes onError
+ */
+ public void testSubscribe5() {
+ TestSubscriber s = new TestSubscriber();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ s.throwOnCall = true;
+ p.subscribe(s);
+ s.awaitError();
+ assertEquals(0, s.nexts);
+ assertEquals(1, s.errors);
+ assertEquals(0, s.completes);
+ }
+
+ /**
+ * subscribe(null) throws NPE
+ */
+ public void testSubscribe6() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ try {
+ p.subscribe(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ checkInitialState(p);
+ }
+
+ /**
+ * Closing a publisher causes onComplete to subscribers
+ */
+ public void testCloseCompletes() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ p.submit(1);
+ p.close();
+ assertTrue(p.isClosed());
+ assertNull(p.getClosedException());
+ s1.awaitComplete();
+ assertEquals(1, s1.nexts);
+ assertEquals(1, s1.completes);
+ s2.awaitComplete();
+ assertEquals(1, s2.nexts);
+ assertEquals(1, s2.completes);
+ }
+
+ /**
+ * Closing a publisher exceptionally causes onError to subscribers
+ * after they are subscribed
+ */
+ public void testCloseExceptionallyError() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ p.submit(1);
+ p.closeExceptionally(new SPException());
+ assertTrue(p.isClosed());
+ s1.awaitSubscribe();
+ s1.awaitError();
+ assertTrue(s1.nexts <= 1);
+ assertEquals(1, s1.errors);
+ s2.awaitSubscribe();
+ s2.awaitError();
+ assertTrue(s2.nexts <= 1);
+ assertEquals(1, s2.errors);
+ }
+
+ /**
+ * Cancelling a subscription eventually causes no more onNexts to be issued
+ */
+ public void testCancel() {
+ SubmissionPublisher<Integer> p =
+ new SubmissionPublisher<>(basicExecutor, 4); // must be < 20
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s1.awaitSubscribe();
+ p.submit(1);
+ s1.sn.cancel();
+ for (int i = 2; i <= 20; ++i)
+ p.submit(i);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(20, s2.nexts);
+ assertEquals(1, s2.completes);
+ assertTrue(s1.nexts < 20);
+ assertFalse(p.isSubscribed(s1));
+ }
+
+ /**
+ * Throwing an exception in onNext causes onError
+ */
+ public void testThrowOnNext() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s1.awaitSubscribe();
+ p.submit(1);
+ s1.throwOnCall = true;
+ p.submit(2);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(2, s2.nexts);
+ s1.awaitComplete();
+ assertEquals(1, s1.errors);
+ }
+
+ /**
+ * If a handler is supplied in constructor, it is invoked when
+ * subscriber throws an exception in onNext
+ */
+ public void testThrowOnNextHandler() {
+ AtomicInteger calls = new AtomicInteger();
+ SubmissionPublisher<Integer> p = new SubmissionPublisher<>(
+ basicExecutor, 8, (s, e) -> calls.getAndIncrement());
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s1.awaitSubscribe();
+ p.submit(1);
+ s1.throwOnCall = true;
+ p.submit(2);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(2, s2.nexts);
+ assertEquals(1, s2.completes);
+ s1.awaitError();
+ assertEquals(1, s1.errors);
+ assertEquals(1, calls.get());
+ }
+
+ /**
+ * onNext items are issued in the same order to each subscriber
+ */
+ public void testOrder() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ for (int i = 1; i <= 20; ++i)
+ p.submit(i);
+ p.close();
+ s2.awaitComplete();
+ s1.awaitComplete();
+ assertEquals(20, s2.nexts);
+ assertEquals(1, s2.completes);
+ assertEquals(20, s1.nexts);
+ assertEquals(1, s1.completes);
+ }
+
+ /**
+ * onNext is issued only if requested
+ */
+ public void testRequest1() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ p.subscribe(s1);
+ s1.awaitSubscribe();
+ assertEquals(0, p.estimateMinimumDemand());
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s2);
+ p.submit(1);
+ p.submit(2);
+ s2.awaitNext(1);
+ assertEquals(0, s1.nexts);
+ s1.sn.request(3);
+ p.submit(3);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(3, s2.nexts);
+ assertEquals(1, s2.completes);
+ s1.awaitComplete();
+ assertTrue(s1.nexts > 0);
+ assertEquals(1, s1.completes);
+ }
+
+ /**
+ * onNext is not issued when requests become zero
+ */
+ public void testRequest2() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ s1.request = false;
+ p.submit(1);
+ p.submit(2);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(2, s2.nexts);
+ assertEquals(1, s2.completes);
+ s1.awaitNext(1);
+ assertEquals(1, s1.nexts);
+ }
+
+ /**
+ * Non-positive request causes error
+ */
+ public void testRequest3() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ TestSubscriber s3 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ p.subscribe(s3);
+ s3.awaitSubscribe();
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ s1.sn.request(-1L);
+ s3.sn.request(0L);
+ p.submit(1);
+ p.submit(2);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(2, s2.nexts);
+ assertEquals(1, s2.completes);
+ s1.awaitError();
+ assertEquals(1, s1.errors);
+ assertTrue(s1.lastError instanceof IllegalArgumentException);
+ s3.awaitError();
+ assertEquals(1, s3.errors);
+ assertTrue(s3.lastError instanceof IllegalArgumentException);
+ }
+
+ /**
+ * estimateMinimumDemand reports 0 until request, nonzero after
+ * request
+ */
+ public void testEstimateMinimumDemand() {
+ TestSubscriber s = new TestSubscriber();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ s.request = false;
+ p.subscribe(s);
+ s.awaitSubscribe();
+ assertEquals(0, p.estimateMinimumDemand());
+ s.sn.request(1);
+ assertEquals(1, p.estimateMinimumDemand());
+ }
+
+ /**
+ * submit to a publisher with no subscribers returns lag 0
+ */
+ public void testEmptySubmit() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ assertEquals(0, p.submit(1));
+ }
+
+ /**
+ * submit(null) throws NPE
+ */
+ public void testNullSubmit() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ try {
+ p.submit(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * submit returns number of lagged items, compatible with result
+ * of estimateMaximumLag.
+ */
+ public void testLaggedSubmit() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ assertEquals(1, p.submit(1));
+ assertTrue(p.estimateMaximumLag() >= 1);
+ assertTrue(p.submit(2) >= 2);
+ assertTrue(p.estimateMaximumLag() >= 2);
+ s1.sn.request(4);
+ assertTrue(p.submit(3) >= 3);
+ assertTrue(p.estimateMaximumLag() >= 3);
+ s2.sn.request(4);
+ p.submit(4);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(4, s2.nexts);
+ s1.awaitComplete();
+ assertEquals(4, s2.nexts);
+ }
+
+ /**
+ * submit eventually issues requested items when buffer capacity is 1
+ */
+ public void testCap1Submit() {
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 1);
+ TestSubscriber s1 = new TestSubscriber();
+ TestSubscriber s2 = new TestSubscriber();
+ p.subscribe(s1);
+ p.subscribe(s2);
+ for (int i = 1; i <= 20; ++i) {
+ assertTrue(p.submit(i) >= 0);
+ }
+ p.close();
+ s2.awaitComplete();
+ s1.awaitComplete();
+ assertEquals(20, s2.nexts);
+ assertEquals(1, s2.completes);
+ assertEquals(20, s1.nexts);
+ assertEquals(1, s1.completes);
+ }
+
+ static boolean noopHandle(AtomicInteger count) {
+ count.getAndIncrement();
+ return false;
+ }
+
+ static boolean reqHandle(AtomicInteger count, Subscriber s) {
+ count.getAndIncrement();
+ ((TestSubscriber)s).sn.request(Long.MAX_VALUE);
+ return true;
+ }
+
+ /**
+ * offer to a publisher with no subscribers returns lag 0
+ */
+ public void testEmptyOffer() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ assertEquals(0, p.offer(1, null));
+ }
+
+ /**
+ * offer(null) throws NPE
+ */
+ public void testNullOffer() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ try {
+ p.offer(null, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offer returns number of lagged items if not saturated
+ */
+ public void testLaggedOffer() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ assertTrue(p.offer(1, null) >= 1);
+ assertTrue(p.offer(2, null) >= 2);
+ s1.sn.request(4);
+ assertTrue(p.offer(3, null) >= 3);
+ s2.sn.request(4);
+ p.offer(4, null);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(4, s2.nexts);
+ s1.awaitComplete();
+ assertEquals(4, s2.nexts);
+ }
+
+ /**
+ * offer reports drops if saturated
+ */
+ public void testDroppedOffer() {
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 4);
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ for (int i = 1; i <= 4; ++i)
+ assertTrue(p.offer(i, null) >= 0);
+ p.offer(5, null);
+ assertTrue(p.offer(6, null) < 0);
+ s1.sn.request(64);
+ assertTrue(p.offer(7, null) < 0);
+ s2.sn.request(64);
+ p.close();
+ s2.awaitComplete();
+ assertTrue(s2.nexts >= 4);
+ s1.awaitComplete();
+ assertTrue(s1.nexts >= 4);
+ }
+
+ /**
+ * offer invokes drop handler if saturated
+ */
+ public void testHandledDroppedOffer() {
+ AtomicInteger calls = new AtomicInteger();
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 4);
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ for (int i = 1; i <= 4; ++i)
+ assertTrue(p.offer(i, (s, x) -> noopHandle(calls)) >= 0);
+ p.offer(4, (s, x) -> noopHandle(calls));
+ assertTrue(p.offer(6, (s, x) -> noopHandle(calls)) < 0);
+ s1.sn.request(64);
+ assertTrue(p.offer(7, (s, x) -> noopHandle(calls)) < 0);
+ s2.sn.request(64);
+ p.close();
+ s2.awaitComplete();
+ s1.awaitComplete();
+ assertTrue(calls.get() >= 4);
+ }
+
+ /**
+ * offer succeeds if drop handler forces request
+ */
+ public void testRecoveredHandledDroppedOffer() {
+ AtomicInteger calls = new AtomicInteger();
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 4);
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ int n = 0;
+ for (int i = 1; i <= 8; ++i) {
+ int d = p.offer(i, (s, x) -> reqHandle(calls, s));
+ n = n + 2 + (d < 0 ? d : 0);
+ }
+ p.close();
+ s2.awaitComplete();
+ s1.awaitComplete();
+ assertEquals(n, s1.nexts + s2.nexts);
+ assertTrue(calls.get() >= 2);
+ }
+
+ /**
+ * Timed offer to a publisher with no subscribers returns lag 0
+ */
+ public void testEmptyTimedOffer() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ long startTime = System.nanoTime();
+ assertEquals(0, p.offer(1, LONG_DELAY_MS, MILLISECONDS, null));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
+ }
+
+ /**
+ * Timed offer with null item or TimeUnit throws NPE
+ */
+ public void testNullTimedOffer() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ long startTime = System.nanoTime();
+ try {
+ p.offer(null, LONG_DELAY_MS, MILLISECONDS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ try {
+ p.offer(1, LONG_DELAY_MS, null, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
+ }
+
+ /**
+ * Timed offer returns number of lagged items if not saturated
+ */
+ public void testLaggedTimedOffer() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ long startTime = System.nanoTime();
+ assertTrue(p.offer(1, LONG_DELAY_MS, MILLISECONDS, null) >= 1);
+ assertTrue(p.offer(2, LONG_DELAY_MS, MILLISECONDS, null) >= 2);
+ s1.sn.request(4);
+ assertTrue(p.offer(3, LONG_DELAY_MS, MILLISECONDS, null) >= 3);
+ s2.sn.request(4);
+ p.offer(4, LONG_DELAY_MS, MILLISECONDS, null);
+ p.close();
+ s2.awaitComplete();
+ assertEquals(4, s2.nexts);
+ s1.awaitComplete();
+ assertEquals(4, s2.nexts);
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
+ }
+
+ /**
+ * Timed offer reports drops if saturated
+ */
+ public void testDroppedTimedOffer() {
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 4);
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ long delay = timeoutMillis();
+ for (int i = 1; i <= 4; ++i)
+ assertTrue(p.offer(i, delay, MILLISECONDS, null) >= 0);
+ long startTime = System.nanoTime();
+ assertTrue(p.offer(5, delay, MILLISECONDS, null) < 0);
+ s1.sn.request(64);
+ assertTrue(p.offer(6, delay, MILLISECONDS, null) < 0);
+ // 2 * delay should elapse but check only 1 * delay to allow timer slop
+ assertTrue(millisElapsedSince(startTime) >= delay);
+ s2.sn.request(64);
+ p.close();
+ s2.awaitComplete();
+ assertTrue(s2.nexts >= 2);
+ s1.awaitComplete();
+ assertTrue(s1.nexts >= 2);
+ }
+
+ /**
+ * Timed offer invokes drop handler if saturated
+ */
+ public void testHandledDroppedTimedOffer() {
+ AtomicInteger calls = new AtomicInteger();
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 4);
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ long delay = timeoutMillis();
+ for (int i = 1; i <= 4; ++i)
+ assertTrue(p.offer(i, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) >= 0);
+ long startTime = System.nanoTime();
+ assertTrue(p.offer(5, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0);
+ s1.sn.request(64);
+ assertTrue(p.offer(6, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0);
+ assertTrue(millisElapsedSince(startTime) >= delay);
+ s2.sn.request(64);
+ p.close();
+ s2.awaitComplete();
+ s1.awaitComplete();
+ assertTrue(calls.get() >= 2);
+ }
+
+ /**
+ * Timed offer succeeds if drop handler forces request
+ */
+ public void testRecoveredHandledDroppedTimedOffer() {
+ AtomicInteger calls = new AtomicInteger();
+ SubmissionPublisher<Integer> p
+ = new SubmissionPublisher<>(basicExecutor, 4);
+ TestSubscriber s1 = new TestSubscriber();
+ s1.request = false;
+ TestSubscriber s2 = new TestSubscriber();
+ s2.request = false;
+ p.subscribe(s1);
+ p.subscribe(s2);
+ s2.awaitSubscribe();
+ s1.awaitSubscribe();
+ int n = 0;
+ long delay = timeoutMillis();
+ long startTime = System.nanoTime();
+ for (int i = 1; i <= 6; ++i) {
+ int d = p.offer(i, delay, MILLISECONDS, (s, x) -> reqHandle(calls, s));
+ n = n + 2 + (d < 0 ? d : 0);
+ }
+ assertTrue(millisElapsedSince(startTime) >= delay);
+ p.close();
+ s2.awaitComplete();
+ s1.awaitComplete();
+ assertEquals(n, s1.nexts + s2.nexts);
+ assertTrue(calls.get() >= 2);
+ }
+
+ /**
+ * consume returns a CompletableFuture that is done when
+ * publisher completes
+ */
+ public void testConsume() {
+ AtomicInteger sum = new AtomicInteger();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ CompletableFuture<Void> f =
+ p.consume((Integer x) -> sum.getAndAdd(x.intValue()));
+ int n = 20;
+ for (int i = 1; i <= n; ++i)
+ p.submit(i);
+ p.close();
+ f.join();
+ assertEquals((n * (n + 1)) / 2, sum.get());
+ }
+
+ /**
+ * consume(null) throws NPE
+ */
+ public void testConsumeNPE() {
+ SubmissionPublisher<Integer> p = basicPublisher();
+ try {
+ CompletableFuture<Void> f = p.consume(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * consume eventually stops processing published items if cancelled
+ */
+ public void testCancelledConsume() {
+ AtomicInteger count = new AtomicInteger();
+ SubmissionPublisher<Integer> p = basicPublisher();
+ CompletableFuture<Void> f = p.consume(x -> count.getAndIncrement());
+ f.cancel(true);
+ int n = 1000000; // arbitrary limit
+ for (int i = 1; i <= n; ++i)
+ p.submit(i);
+ assertTrue(count.get() < n);
+ }
+
+ /**
+ * Tests scenario for
+ * JDK-8187947: A race condition in SubmissionPublisher
+ * cvs update -D '2017-11-25' src/main/java/util/concurrent/SubmissionPublisher.java && ant -Djsr166.expensiveTests=true -Djsr166.tckTestClass=SubmissionPublisherTest -Djsr166.methodFilter=testMissedSignal tck; cvs update -A src/main/java/util/concurrent/SubmissionPublisher.java
+ */
+ public void testMissedSignal_8187947() throws Exception {
+ if (!atLeastJava9()) return; // backport to jdk8 too hard
+ final int N = expensiveTests ? (1 << 20) : (1 << 10);
+ final CountDownLatch finished = new CountDownLatch(1);
+ final SubmissionPublisher<Boolean> pub = new SubmissionPublisher<>();
+ class Sub implements Subscriber<Boolean> {
+ int received;
+ public void onSubscribe(Subscription s) {
+ s.request(N);
+ }
+ public void onNext(Boolean item) {
+ if (++received == N)
+ finished.countDown();
+ else
+ CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
+ }
+ public void onError(Throwable t) { throw new AssertionError(t); }
+ public void onComplete() {}
+ }
+ pub.subscribe(new Sub());
+ CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
+ await(finished);
+ }
+}
diff --git a/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java b/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java
new file mode 100644
index 0000000..5cddf1c
--- /dev/null
+++ b/ojluni/src/test/java/util/concurrent/tck/TimeUnit8Test.java
@@ -0,0 +1,189 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package test.java.util.concurrent.tck;
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.LongStream;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class TimeUnit8Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+
+ public static Test suite() {
+ return new TestSuite(TimeUnit8Test.class);
+ }
+
+ /**
+ * tests for toChronoUnit.
+ */
+ public void testToChronoUnit() throws Exception {
+ assertSame(ChronoUnit.NANOS, NANOSECONDS.toChronoUnit());
+ assertSame(ChronoUnit.MICROS, MICROSECONDS.toChronoUnit());
+ assertSame(ChronoUnit.MILLIS, MILLISECONDS.toChronoUnit());
+ assertSame(ChronoUnit.SECONDS, SECONDS.toChronoUnit());
+ assertSame(ChronoUnit.MINUTES, MINUTES.toChronoUnit());
+ assertSame(ChronoUnit.HOURS, HOURS.toChronoUnit());
+ assertSame(ChronoUnit.DAYS, DAYS.toChronoUnit());
+
+ // Every TimeUnit has a defined ChronoUnit equivalent
+ for (TimeUnit x : TimeUnit.values())
+ assertSame(x, TimeUnit.of(x.toChronoUnit()));
+ }
+
+ /**
+ * tests for TimeUnit.of(ChronoUnit).
+ */
+ public void testTimeUnitOf() throws Exception {
+ assertSame(NANOSECONDS, TimeUnit.of(ChronoUnit.NANOS));
+ assertSame(MICROSECONDS, TimeUnit.of(ChronoUnit.MICROS));
+ assertSame(MILLISECONDS, TimeUnit.of(ChronoUnit.MILLIS));
+ assertSame(SECONDS, TimeUnit.of(ChronoUnit.SECONDS));
+ assertSame(MINUTES, TimeUnit.of(ChronoUnit.MINUTES));
+ assertSame(HOURS, TimeUnit.of(ChronoUnit.HOURS));
+ assertSame(DAYS, TimeUnit.of(ChronoUnit.DAYS));
+
+ assertThrows(NullPointerException.class,
+ () -> TimeUnit.of((ChronoUnit)null));
+
+ // ChronoUnits either round trip to their TimeUnit
+ // equivalents, or throw IllegalArgumentException.
+ for (ChronoUnit cu : ChronoUnit.values()) {
+ final TimeUnit tu;
+ try {
+ tu = TimeUnit.of(cu);
+ } catch (IllegalArgumentException acceptable) {
+ continue;
+ }
+ assertSame(cu, tu.toChronoUnit());
+ }
+ }
+
+ /**
+ * convert(Duration) roundtrips with Duration.ofXXXX and Duration.of(long, ChronoUnit)
+ */
+ public void testConvertDuration_roundtripDurationOf() {
+ long n = ThreadLocalRandom.current().nextLong();
+
+ assertEquals(n, NANOSECONDS.convert(Duration.ofNanos(n)));
+ assertEquals(n, NANOSECONDS.convert(Duration.of(n, ChronoUnit.NANOS)));
+ assertEquals(n, MILLISECONDS.convert(Duration.ofMillis(n)));
+ assertEquals(n, MILLISECONDS.convert(Duration.of(n, ChronoUnit.MILLIS)));
+ assertEquals(n, SECONDS.convert(Duration.ofSeconds(n)));
+ assertEquals(n, SECONDS.convert(Duration.of(n, ChronoUnit.SECONDS)));
+ n /= 60;
+ assertEquals(n, MINUTES.convert(Duration.ofMinutes(n)));
+ assertEquals(n, MINUTES.convert(Duration.of(n, ChronoUnit.MINUTES)));
+ n /= 60;
+ assertEquals(n, HOURS.convert(Duration.ofHours(n)));
+ assertEquals(n, HOURS.convert(Duration.of(n, ChronoUnit.HOURS)));
+ n /= 24;
+ assertEquals(n, DAYS.convert(Duration.ofDays(n)));
+ assertEquals(n, DAYS.convert(Duration.of(n, ChronoUnit.DAYS)));
+ }
+
+ /**
+ * convert(Duration.ofNanos(n)) agrees with convert(n, NANOSECONDS)
+ */
+ public void testConvertDuration_roundtripDurationOfNanos() {
+ // Test values near unit transitions and near overflow.
+ LongStream.concat(
+ Arrays.stream(TimeUnit.values()).mapToLong(u -> u.toNanos(1)),
+ LongStream.of(Long.MAX_VALUE, Long.MIN_VALUE))
+ .flatMap(n -> LongStream.of(n, n + 1, n - 1))
+ .flatMap(n -> LongStream.of(n, n + 1_000_000_000, n - 1_000_000_000))
+ .flatMap(n -> LongStream.of(n, -n))
+ // .peek(System.err::println)
+ .forEach(n -> Arrays.stream(TimeUnit.values()).forEach(
+ u -> assertEquals(u.convert(n, NANOSECONDS),
+ u.convert(Duration.ofNanos(n)))));
+ }
+
+ /**
+ * convert(Duration) doesn't misbehave near Long.MAX_VALUE and Long.MIN_VALUE.
+ */
+ public void testConvertDuration_nearOverflow() {
+ ChronoUnit NANOS = ChronoUnit.NANOS;
+ Duration maxDuration = Duration.ofSeconds(Long.MAX_VALUE, 999_999_999);
+ Duration minDuration = Duration.ofSeconds(Long.MIN_VALUE, 0);
+
+ for (TimeUnit u : TimeUnit.values()) {
+ ChronoUnit cu = u.toChronoUnit();
+ long r;
+ if (u.toNanos(1) > SECONDS.toNanos(1)) {
+ r = u.toNanos(1) / SECONDS.toNanos(1);
+
+ assertThrows(ArithmeticException.class,
+ () -> Duration.of(Long.MAX_VALUE, cu),
+ () -> Duration.of(Long.MIN_VALUE, cu));
+ } else {
+ r = 1;
+
+ Duration max = Duration.of(Long.MAX_VALUE, cu);
+ Duration min = Duration.of(Long.MIN_VALUE, cu);
+ assertEquals(Long.MAX_VALUE, u.convert(max));
+ assertEquals(Long.MAX_VALUE - 1, u.convert(max.minus(1, NANOS)));
+ assertEquals(Long.MAX_VALUE - 1, u.convert(max.minus(1, cu)));
+ assertEquals(Long.MIN_VALUE, u.convert(min));
+ assertEquals(Long.MIN_VALUE + 1, u.convert(min.plus(1, NANOS)));
+ assertEquals(Long.MIN_VALUE + 1, u.convert(min.plus(1, cu)));
+ assertEquals(Long.MAX_VALUE, u.convert(max.plus(1, NANOS)));
+ if (u != SECONDS) {
+ assertEquals(Long.MAX_VALUE, u.convert(max.plus(1, cu)));
+ assertEquals(Long.MIN_VALUE, u.convert(min.minus(1, NANOS)));
+ assertEquals(Long.MIN_VALUE, u.convert(min.minus(1, cu)));
+ }
+ }
+
+ assertEquals(Long.MAX_VALUE / r, u.convert(maxDuration));
+ assertEquals(Long.MIN_VALUE / r, u.convert(minDuration));
+ }
+ }
+
+}
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index ad34f44..7e6c9c8 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -589,6 +589,7 @@
"ojluni/src/main/java/java/security/cert/PolicyNode.java",
"ojluni/src/main/java/java/security/cert/PolicyQualifierInfo.java",
"ojluni/src/main/java/java/security/cert/TrustAnchor.java",
+ "ojluni/src/main/java/java/security/cert/URICertStoreParameters.java",
"ojluni/src/main/java/java/security/cert/X509Certificate.java",
"ojluni/src/main/java/java/security/cert/X509CertSelector.java",
"ojluni/src/main/java/java/security/cert/X509CRLEntry.java",
@@ -980,6 +981,7 @@
"ojluni/src/main/java/java/util/concurrent/ScheduledFuture.java",
"ojluni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java",
"ojluni/src/main/java/java/util/concurrent/Semaphore.java",
+ "ojluni/src/main/java/java/util/concurrent/SubmissionPublisher.java",
"ojluni/src/main/java/java/util/concurrent/SynchronousQueue.java",
"ojluni/src/main/java/java/util/concurrent/ThreadFactory.java",
"ojluni/src/main/java/java/util/concurrent/ThreadLocalRandom.java",
@@ -1449,6 +1451,7 @@
"ojluni/src/main/java/jdk/net/NetworkPermission.java",
"ojluni/src/main/java/jdk/net/SocketFlow.java",
"ojluni/src/main/java/jdk/net/Sockets.java",
+ "ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java",
"ojluni/src/main/java/jdk/internal/misc/JavaIOFileDescriptorAccess.java",
"ojluni/src/main/java/jdk/internal/misc/JavaObjectInputStreamAccess.java",
"ojluni/src/main/java/jdk/internal/misc/SharedSecrets.java",
@@ -1456,7 +1459,10 @@
"ojluni/src/main/java/jdk/internal/misc/VM.java",
"ojluni/src/main/java/jdk/internal/reflect/CallerSensitive.java",
"ojluni/src/main/java/jdk/internal/reflect/Reflection.java",
+ "ojluni/src/main/java/jdk/internal/vm/annotation/Contended.java",
+ "ojluni/src/main/java/jdk/internal/vm/annotation/ReservedStackAccess.java",
"ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java",
+ "ojluni/src/main/java/jdk/internal/util/ArraysSupport.java",
"ojluni/src/main/java/jdk/internal/util/Preconditions.java",
"ojluni/src/main/java/sun/invoke/util/BytecodeDescriptor.java",
"ojluni/src/main/java/sun/invoke/util/Wrapper.java",
@@ -1707,6 +1713,7 @@
"ojluni/src/main/java/sun/security/util/DerOutputStream.java",
"ojluni/src/main/java/sun/security/util/DerValue.java",
"ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java",
+ "ojluni/src/main/java/sun/security/util/HexDumpEncoder.java",
"ojluni/src/main/java/sun/security/util/KeyUtil.java",
"ojluni/src/main/java/sun/security/util/Length.java",
"ojluni/src/main/java/sun/security/util/ManifestDigester.java",
diff --git a/tools/upstream/pkg-status b/tools/upstream/pkg-status
new file mode 100755
index 0000000..b8bc163
--- /dev/null
+++ b/tools/upstream/pkg-status
@@ -0,0 +1,428 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed 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
+#
+# 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.
+
+"""
+Reports on merge status of Java files in a package based on four
+repositories:
+
+baseline - upstream baseline used for previous Android release
+release - files in previous Android release
+current - target for merge
+upstream - new upstream being merged
+
+Example output:
+$ tools/upstream/pkg-status java.security.spec
+AlgorithmParameterSpec.java: Unchanged, Done
+DSAGenParameterSpec.java: Added, TO DO
+DSAParameterSpec.java: Unchanged, Done
+DSAPrivateKeySpec.java: Unchanged, Done
+DSAPublicKeySpec.java: Unchanged, Done
+ECField.java: Unchanged, Done
+ECFieldF2m.java: Unchanged, Done
+ECFieldFp.java: Unchanged, Done
+ECGenParameterSpec.java: Updated, TO DO
+[...]
+"""
+
+import argparse
+import hashlib
+import os
+import os.path
+import sys
+from enum import Enum
+from pathlib import Path
+
+RED = '\u001b[31m'
+GREEN = "\u001b[32m"
+YELLOW = "\u001b[33m"
+RESET = "\u001b[0m"
+
+
+def colourise(colour, string):
+ """Wrap a string with an ANSI colour code"""
+ return "%s%s%s" % (colour, string, RESET)
+
+
+def red(string):
+ """Wrap a string with a red ANSI colour code"""
+ return colourise(RED, string)
+
+
+def green(string):
+ """Wrap a string with a green ANSI colour code"""
+ return colourise(GREEN, string)
+
+
+def yellow(string):
+ """Wrap a string with a yellow ANSI colour code"""
+ return colourise(YELLOW, string)
+
+
+class WorkStatus(Enum):
+ """Enum for a file's work completion status"""
+ UNKNOWN = ('Unknown', red)
+ TODO = ('TO DO', yellow)
+ DONE = ('Done', green)
+ PROBABLY_DONE = ('Probably done', green)
+ ERROR = ('Error', red)
+
+ def colourise(self, string):
+ """Colourise a string using the method for this enum value"""
+ return self.colourfunc(string)
+
+ def __init__(self, description, colourfunc):
+ self.description = description
+ self.colourfunc = colourfunc
+
+
+class MergeStatus(Enum):
+ """Enum for a file's merge status"""
+ UNKNOWN = 'Unknown!'
+ MISSING = 'Missing'
+ ADDED = 'Added'
+ DELETED = 'Deleted or moved'
+ UNCHANGED = 'Unchanged'
+ UPDATED = 'Updated'
+
+ def __init__(self, description):
+ self.description = description
+
+
+class MergeConfig:
+ """
+ Configuration for an upstream merge.
+
+ Encapsulates the paths to each of the required code repositories.
+ """
+ def __init__(self, baseline, release, current, upstream) -> None:
+ self.baseline = baseline
+ self.release = release
+ self.current = current
+ self.upstream = upstream
+ try:
+ # Root of checked-out Android sources, set by the "lunch" command.
+ self.android_build_top = os.environ['ANDROID_BUILD_TOP']
+ # Root of repository snapshots.
+ self.ojluni_upstreams = os.environ['OJLUNI_UPSTREAMS']
+ except KeyError:
+ sys.exit('`lunch` and set OJLUNI_UPSTREAMS first.')
+
+
+ def java_dir(self, repo, pkg):
+ relpath = pkg.replace('.', '/')
+ if repo == self.current:
+ return '%s/libcore/%s/src/main/java/%s' % (
+ self.android_build_top, self.current, relpath)
+ else:
+ return '%s/%s/%s' % (self.ojluni_upstreams, repo, relpath)
+
+ def baseline_dir(self, pkg):
+ return self.java_dir(self.baseline, pkg)
+
+ def release_dir(self, pkg):
+ return self.java_dir(self.release, pkg)
+
+ def current_dir(self, pkg):
+ return self.java_dir(self.current, pkg)
+
+ def upstream_dir(self, pkg):
+ return self.java_dir(self.upstream, pkg)
+
+
+class JavaPackage:
+ """
+ Encapsulates information about a single Java package, notably paths
+ to it within each repository.
+ """
+ def __init__(self, config, name) -> None:
+ self.name = name
+ self.baseline_dir = config.baseline_dir(name)
+ self.release_dir = config.release_dir(name)
+ self.current_dir = config.current_dir(name)
+ self.upstream_dir = config.upstream_dir(name)
+
+ @staticmethod
+ def list_candidate_files(path):
+ """Returns a list of all the Java filenames in a directory."""
+ return list(filter(
+ lambda f: f.endswith('.java') and f != 'package-info.java',
+ os.listdir(path)))
+
+ def all_files(self):
+ """Returns the union of all the Java filenames in all repositories."""
+ files = set(self.list_candidate_files(self.baseline_dir))
+ files.update(self.list_candidate_files(self.release_dir))
+ files.update(self.list_candidate_files(self.upstream_dir))
+ files.update(self.list_candidate_files(self.current_dir))
+ return sorted(list(files))
+
+ def java_files(self):
+ """Returns a list of JavaFiles corresponding to all filenames."""
+ return map(lambda f: JavaFile(self, f), self.all_files())
+
+ def baseline_path(self, filename):
+ return Path(self.baseline_dir + '/' + filename)
+
+ def release_path(self, filename):
+ return Path(self.release_dir + '/' + filename)
+
+ def current_path(self, filename):
+ return Path(self.current_dir + '/' + filename)
+
+ def upstream_path(self, filename):
+ return Path(self.upstream_dir + '/' + filename)
+
+ def report_merge_status(self):
+ """Report on the mergse status of this package."""
+ for file in self.java_files():
+ merge_status, work_status = file.status()
+ text = '%s: %s, %s' % \
+ (
+ file.name, merge_status.description,
+ work_status.description)
+ print(work_status.colourise(text))
+ if work_status == WorkStatus.ERROR:
+ print(file.baseline_sum, file.baseline)
+ print(file.release_sum, file.release)
+ print(file.current_sum, file.current)
+ print(file.upstream_sum, file.upstream)
+
+
+class JavaFile:
+ """
+ Encapsulates information about a single Java file in a package across
+ all of the repositories involved in a merge.
+ """
+ def __init__(self, package, name):
+ self.package = package
+ self.name = name
+ # Paths for this file in each repository
+ self.baseline = package.baseline_path(name)
+ self.release = package.release_path(name)
+ self.upstream = package.upstream_path(name)
+ self.current = package.current_path(name)
+ # Checksums for this file in each repository, or None if absent
+ self.baseline_sum = self.checksum(self.baseline)
+ self.release_sum = self.checksum(self.release)
+ self.upstream_sum = self.checksum(self.upstream)
+ self.current_sum = self.checksum(self.current)
+ # List of methods for determining file's merge status.
+ # Order matters - see merge_status() for details
+ self.merge_status_methods = [
+ (self.check_for_missing, MergeStatus.MISSING),
+ (self.check_for_unchanged, MergeStatus.UNCHANGED),
+ (self.check_for_added_upstream, MergeStatus.ADDED),
+ (self.check_for_removed_upstream, MergeStatus.DELETED),
+ (self.check_for_changed_upstream, MergeStatus.UPDATED),
+ ]
+ # Map of methods from merge status to determine work status
+ self.work_status_methods = {
+ MergeStatus.MISSING: self.calculate_missing_work_status,
+ MergeStatus.UNCHANGED: self.calculate_unchanged_work_status,
+ MergeStatus.ADDED: self.calculate_added_work_status,
+ MergeStatus.DELETED: self.calculate_deleted_work_status,
+ MergeStatus.UPDATED: self.calculate_updated_work_status,
+ }
+
+ def is_android_changed(self):
+ """
+ Returns true if the file was changed between the baseline and Android
+ release.
+ """
+ return self.is_in_release() and self.baseline_sum != self.release_sum
+
+ def is_android_unchanged(self):
+ """
+ Returns true if the file is in the Android release and is unchanged.
+ """
+ return self.is_in_release() and self.baseline_sum == self.release_sum
+
+ def check_for_changed_upstream(self):
+ """Returns true if the file is changed upstream since the baseline."""
+ return self.baseline_sum != self.upstream_sum
+
+ def is_in_baseline(self):
+ return self.baseline_sum is not None
+
+ def is_in_release(self):
+ """Returns true if the file is present in the baseline and release."""
+ return self.is_in_baseline() and self.release_sum is not None
+
+ def is_in_current(self):
+ """Returns true if the file is in current, release and baseline."""
+ return self.is_in_release() and self.current_sum is not None
+
+ def is_in_upstream(self):
+ return self.upstream_sum is not None
+
+ def check_for_missing(self):
+ """
+ Returns true if the file is expected to be in current, but isn't.
+ """
+ return self.is_in_release() and self.is_in_upstream() \
+ and not self.is_in_current()
+
+ def removed_in_release(self):
+ """Returns true if the file was removed by Android in the release."""
+ return self.is_in_baseline() and not self.is_in_release()
+
+ def check_for_removed_upstream(self):
+ """Returns true if the file was removed upstream since the baseline."""
+ return self.is_in_baseline() and not self.is_in_upstream()
+
+ def check_for_added_upstream(self):
+ """Returns true if the file was added upstream since the baseline."""
+ return self.is_in_upstream() and not self.is_in_baseline()
+
+ def check_for_unchanged(self):
+ """Returns true if the file is unchanged upstream since the baseline."""
+ return not self.check_for_changed_upstream()
+
+ def merge_status(self):
+ """
+ Returns the merge status for this file, or UNKNOWN.
+ Tries each merge_status_method in turn, and if one returns true
+ then this method returns the associated merge status.
+ """
+ for (method, status) in self.merge_status_methods:
+ if method():
+ return status
+ return MergeStatus.UNKNOWN
+
+ def work_status(self):
+ """
+ Returns the work status for this file.
+ Looks up a status method based on the merge statis and uses that to
+ determine the work status.
+ """
+ status = self.merge_status()
+ if status in self.work_status_methods:
+ return self.work_status_methods[status]()
+ return WorkStatus.ERROR
+
+ @staticmethod
+ def calculate_missing_work_status():
+ """Missing files are always an error."""
+ return WorkStatus.ERROR
+
+ def calculate_unchanged_work_status(self):
+ """
+ File is unchanged upstream, so should be unchanged between release and
+ current.
+ """
+ if self.current_sum == self.release_sum:
+ return WorkStatus.DONE
+ return WorkStatus.UNKNOWN
+
+ def calculate_added_work_status(self):
+ """File was added upstream so needs to be added to current."""
+ if self.current_sum is None:
+ return WorkStatus.TODO
+ if self.current_sum == self.upstream_sum:
+ return WorkStatus.DONE
+ # XXX check for change markers if android changed
+ return WorkStatus.UNKNOWN
+
+ def calculate_deleted_work_status(self):
+ """File was removed upstream so needs to be removed from current."""
+ if self.is_in_current():
+ return WorkStatus.TODO
+ return WorkStatus.DONE
+
+ def calculate_updated_work_status(self):
+ """File was updated upstream."""
+ if self.current_sum == self.upstream_sum:
+ if self.is_android_unchanged():
+ return WorkStatus.DONE
+ # Looks like Android changes are missing in current
+ return WorkStatus.ERROR
+ if self.is_android_unchanged():
+ return WorkStatus.TODO
+ # If we get here there are upstream and Android changes that need
+ # to be merged, If possible use the file copyright date as a
+ # heuristic to determine if upstream has been merged into current
+ release_copyright = self.get_copyright(self.release)
+ current_copyright = self.get_copyright(self.current)
+ upstream_copyright = self.get_copyright(self.upstream)
+ if release_copyright == upstream_copyright:
+ # Upstream copyright same as last release, so can't infer anything
+ return WorkStatus.UNKNOWN
+ if current_copyright == upstream_copyright:
+ return WorkStatus.PROBABLY_DONE
+ if current_copyright == release_copyright:
+ return WorkStatus.TODO
+ # Give up
+ return WorkStatus.UNKNOWN
+
+ def status(self):
+ return self.merge_status(), self.work_status()
+
+ @staticmethod
+ def checksum(path):
+ """Returns a checksum string for a file, SHA256 as a hex string."""
+ try:
+ with open(path, 'rb') as file:
+ bytes = file.read()
+ return hashlib.sha256(bytes).hexdigest()
+ except:
+ return None
+
+ @staticmethod
+ def get_copyright(file):
+ """Returns the upstream copyright line for a file."""
+ try:
+ with open(file, 'r') as file:
+ for count in range(5):
+ line = file.readline()
+ if line.startswith(
+ ' * Copyright') and 'Android' not in line:
+ return line
+ return None
+ except:
+ return None
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Report on merge status of Java packages',
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ # TODO(prb): Add help for available repositories
+ parser.add_argument('-b', '--baseline', default='expected',
+ help='Baseline repo')
+ parser.add_argument('-r', '--release', default='sc-release',
+ help='Last released repo')
+ parser.add_argument('-u', '--upstream', default='11+28',
+ help='Upstream repo.')
+ parser.add_argument('-c', '--current', default='ojluni',
+ help='Current repo.')
+ parser.add_argument('pkgs', nargs="+",
+ help='Packages to report on')
+
+ args = parser.parse_args()
+ config = MergeConfig(args.baseline, args.release, args.current,
+ args.upstream)
+
+ for pkg_name in args.pkgs:
+ try:
+ package = JavaPackage(config, pkg_name)
+ package.report_merge_status()
+ except Exception as e:
+ print(red("ERROR: Unable to process package " + pkg_name + e))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/upstream/src/main/java/libcore/CompareUpstreams.java b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
index d9588a7..c2b6cde 100644
--- a/tools/upstream/src/main/java/libcore/CompareUpstreams.java
+++ b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
@@ -165,6 +165,7 @@
headers.add(upstream.name());
}
headers.add("diff");
+ headers.add("guessed_upstream_path");
printTsv(out, headers);
Path snapshotRoot = COMPARE_AGAINST_UPSTREAM_SNAPSHOT
@@ -217,6 +218,8 @@
String changedCommentsSummary = androidChangedCommentsSummary(linesB);
String diffCommand = "";
+ String guessed_upstream_path = guessedUpstream != null ?
+ "" + guessedUpstream.pathFromRepository(relPath) : "";
if (!comparisons.get(0).equals("identical")) {
Path expectedUpstreamPath = expectedUpstream.pathFromRepository(relPath);
if (expectedUpstreamPath != null) {
@@ -232,6 +235,7 @@
values.add(changedCommentsSummary);
values.addAll(comparisons);
values.add(diffCommand);
+ values.add(guessed_upstream_path);
printTsv(out, values);
}
}
diff --git a/tools/upstream/src/main/java/libcore/Repository.java b/tools/upstream/src/main/java/libcore/Repository.java
index 4c7bbd7..51a3a69 100644
--- a/tools/upstream/src/main/java/libcore/Repository.java
+++ b/tools/upstream/src/main/java/libcore/Repository.java
@@ -167,6 +167,36 @@
}
/**
+ * A checkout of the hg repository of OpenJDK 11 or higher, located in the
+ * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
+ */
+ public static Repository openJdk11(Path upstreamRoot, String upstreamName) {
+ List<String> sourceDirs = Arrays.asList(
+ "src/java.base/share/classes",
+ "src/java.logging/share/classes",
+ "src/java.prefs/share/classes",
+ "src/java.sql/share/classes",
+ "src/java.desktop/share/classes",
+ "src/java.base/solaris/classes",
+ "src/java.base/unix/classes",
+ "src/java.prefs/unix/classes",
+ "src/jdk.unsupported/share/classes",
+ "src/jdk.net/share/classes",
+ "src/java.base/linux/classes",
+ "build/linux-x86_64-normal-server-release/support/gensrc/java.base",
+
+ // Native (.c) files
+ "src/java.base/unix/native/libjava",
+ "src/java.base/share/native/libjava",
+ "src/java.base/unix/native/libnio",
+ "src/java.base/unix/native/libnio/ch",
+ "src/java.base/unix/native/libnio/fs",
+ "src/java.base/unix/native/libnet"
+ );
+ return new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs);
+ }
+
+ /**
* A checkout of the hg repository of OpenJDK 8 or earlier, located in the
* subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
*/
diff --git a/tools/upstream/src/main/java/libcore/StandardRepositories.java b/tools/upstream/src/main/java/libcore/StandardRepositories.java
index 7047c60..9b74f55 100644
--- a/tools/upstream/src/main/java/libcore/StandardRepositories.java
+++ b/tools/upstream/src/main/java/libcore/StandardRepositories.java
@@ -28,6 +28,7 @@
import libcore.Repository.OjluniRepository;
import static libcore.Repository.openJdk9;
+import static libcore.Repository.openJdk11;
import static libcore.Repository.openJdkLegacy;
public class StandardRepositories {
@@ -51,10 +52,12 @@
this.openJdk8u222 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u222-b01"));
this.openJdk9p181 = addAndReturn(allUpstreams, openJdk9(upstreamRoot, "9+181"));
Repository openJdk8u60 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u60"));
+ Repository openJdk11p28 = addAndReturn(allUpstreams, openJdk11(upstreamRoot, "11+28"));
this.openJdk7u40 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "7u40"));
this.allUpstreams = Collections.unmodifiableList(new ArrayList<>(allUpstreams));
this.historicUpstreams = Collections.unmodifiableList(new ArrayList<>(
- Arrays.asList(openJdk8u60, openJdk7u40)
+ Arrays.asList(openJdk8u121, openJdk8u60, openJdk11p28, openJdk9p181, openJdk9b113,
+ openJdk7u40)
));
this.ojluni = new OjluniRepository(buildTop);
}