Merge "Port a number of OpenJDK8 stream methods"
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java
index 1da9502..46559dc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java
@@ -573,6 +573,16 @@
}
/**
+ * @tests java.io.BufferedReader#lines()
+ */
+ public void test_lines() {
+ // Test for method java.util.stream.Stream java.io.BufferedReader.lines()
+ br = new BufferedReader(new Support_StringReader(testString));
+ String[] r = br.lines().toArray(String[]::new);
+ assertEquals(107, r.length);
+ }
+
+ /**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
diff --git a/luni/src/test/java/libcore/java/io/UncheckedIOExceptionTest.java b/luni/src/test/java/libcore/java/io/UncheckedIOExceptionTest.java
new file mode 100644
index 0000000..0d67277
--- /dev/null
+++ b/luni/src/test/java/libcore/java/io/UncheckedIOExceptionTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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.io;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+public class UncheckedIOExceptionTest extends TestCase {
+
+ /**
+ * java.lang.UncheckedIOException#UncheckedIOException(java.io.IOException)
+ */
+ public void test_ConstructorLjava_lang_IOException() {
+ IOException ioException = new IOException();
+ UncheckedIOException e = new UncheckedIOException(ioException);
+ assertEquals("java.io.IOException", e.getMessage());
+ assertSame(ioException, e.getCause());
+ }
+
+ /**
+ * java.lang.UncheckedIOException#UncheckedIOException(java.lang.String, java.io.IOException)
+ */
+ public void test_ConstructorLjava_lang_String_IOException() {
+ IOException ioException = new IOException();
+ UncheckedIOException e = new UncheckedIOException("errmsg", ioException);
+ assertEquals("errmsg", e.getMessage());
+ assertSame(ioException, e.getCause());
+ }
+
+ /**
+ * serialization/deserialization.
+ */
+ public void testSerializationSelf() throws Exception {
+ SerializationTest.verifySelf(new UncheckedIOException(new IOException()));
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/BitSetTest.java b/luni/src/test/java/libcore/java/util/BitSetTest.java
index 4998a07..c4e8ad3 100644
--- a/luni/src/test/java/libcore/java/util/BitSetTest.java
+++ b/luni/src/test/java/libcore/java/util/BitSetTest.java
@@ -20,6 +20,7 @@
import java.nio.LongBuffer;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Random;
public class BitSetTest extends junit.framework.TestCase {
public void test_toString() throws Exception {
@@ -231,4 +232,17 @@
result.xor(big());
assertEquals("{10, 1000}", result.toString());
}
+
+ public void test_stream() {
+ final int size = 128;
+
+ // Generate an arbitrary array of bytes.
+ byte[] bytes = new byte[size];
+ new Random(0).nextBytes(bytes);
+
+ BitSet bs = BitSet.valueOf(bytes);
+
+ assertEquals(bs.cardinality(), bs.stream().count());
+ bs.stream().forEach(x -> assertTrue(bs.get(x)));
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/RandomTest.java b/luni/src/test/java/libcore/java/util/RandomTest.java
index 11bdc63..f72a9be 100644
--- a/luni/src/test/java/libcore/java/util/RandomTest.java
+++ b/luni/src/test/java/libcore/java/util/RandomTest.java
@@ -16,6 +16,7 @@
package libcore.java.util;
+import java.util.Arrays;
import java.util.Random;
public class RandomTest extends junit.framework.TestCase {
@@ -40,4 +41,237 @@
r2.nextInt();
assertNotNull(r2.state);
}
+
+ public void test_ints$() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+
+ Random rand = new Random(0);
+ int[] rands = new int[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextInt();
+ }
+
+ int[] streamRands = new Random(0).ints().limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ }
+
+ public void test_ints$L() {
+ final int size = 32;
+
+ Random rand = new Random(0);
+ int[] rands = new int[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextInt();
+ }
+
+ int[] streamRands = new Random(0).ints(size).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).ints(size).count());
+
+ try {
+ new Random(0).ints(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_ints$II() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ int[] rands = new int[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextInt(bound - origin) + origin;
+ }
+
+ int[] streamRands = new Random(0).ints(origin, bound).limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+
+ try {
+ new Random(0).ints(100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_ints$LII() {
+ final int size = 32;
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ int[] rands = new int[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextInt(bound - origin) + origin;
+ }
+
+ int[] streamRands = new Random(0).ints(size, origin, bound).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).ints(size, origin, bound).count());
+
+ try {
+ new Random(0).ints(-1, 10, 20);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ new Random(0).ints(10, 100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_longs$() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+
+ Random rand = new Random(0);
+ long[] rands = new long[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextLong();
+ }
+
+ long[] streamRands = new Random(0).longs().limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ }
+
+ public void test_longs$L() {
+ final int size = 32;
+
+ Random rand = new Random(0);
+ long[] rands = new long[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextLong();
+ }
+
+ long[] streamRands = new Random(0).longs(size).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).longs(size).count());
+
+ try {
+ new Random(0).longs(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_longs$II() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ long[] rands = new long[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = (rand.nextLong() & 127) + origin;
+ }
+
+ long[] streamRands = new Random(0).longs(origin, bound).limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+
+ try {
+ new Random(0).longs(100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_longs$LII() {
+ final int size = 32;
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ long[] rands = new long[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = (rand.nextLong() & 127) + origin;
+ }
+
+ long[] streamRands = new Random(0).longs(size, origin, bound).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).longs(size, origin, bound).count());
+
+ try {
+ new Random(0).longs(-1, 10, 20);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ new Random(0).longs(10, 100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_doubles$() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+
+ Random rand = new Random(0);
+ double[] rands = new double[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextDouble();
+ }
+
+ double[] streamRands = new Random(0).doubles().limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ }
+
+ public void test_doubles$L() {
+ final int size = 32;
+
+ Random rand = new Random(0);
+ double[] rands = new double[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextDouble();
+ }
+
+ double[] streamRands = new Random(0).doubles(size).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).doubles(size).count());
+
+ try {
+ new Random(0).ints(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_doubles$II() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ double[] rands = new double[limit];
+ for(int i = 0; i < limit; ++i) {
+ double r = rand.nextDouble() * (bound - origin) + origin;
+ if (r >= bound) {
+ r = Math.nextDown(r);
+ }
+ rands[i] = r;
+ }
+
+ double[] streamRands = new Random(0).doubles(origin, bound).limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+
+ try {
+ new Random(0).doubles(100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_doubles$LII() {
+ final int size = 32;
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ double[] rands = new double[size];
+ for(int i = 0; i < size; ++i) {
+ double r = rand.nextDouble() * (bound - origin) + origin;
+ if (r >= bound) {
+ r = Math.nextDown(r);
+ }
+ rands[i] = r;
+ }
+
+ double[] streamRands = new Random(0).doubles(size, origin, bound).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).doubles(size, origin, bound).count());
+
+ try {
+ new Random(0).doubles(-1, 10, 20);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ new Random(0).doubles(10, 100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java b/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java
index a4f534b..41b9643 100644
--- a/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java
+++ b/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java
@@ -1840,4 +1840,44 @@
mat = pat.matcher(testString);
assertTrue(mat.matches());
}
+
+ public void testAsPredicate() {
+ String[][] posSeq = {
+ { "abb", "ababb", "abababbababb", "abababbababbabababbbbbabb" },
+ { "213567", "12324567", "1234567", "213213567",
+ "21312312312567", "444444567" },
+ { "abcdaab", "aab", "abaab", "cdaab", "acbdadcbaab" },
+ { "213234567", "3458", "0987654", "7689546432", "0398576",
+ "98432", "5" },
+ {
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" },
+ { "ababbaAabababblice", "ababbaAliceababab", "ababbAabliceaaa",
+ "abbbAbbbliceaaa", "Alice" },
+ { "a123", "bnxnvgds156", "for", "while", "if", "struct" },
+ { "xy" }, { "xy" }, { "xcy" }
+ };
+
+ for (int i = 0; i < testPatterns.length; i++) {
+ Pattern p = Pattern.compile(testPatterns[i]);
+ for (int j = 0; j < posSeq[i].length; j++) {
+ assertTrue(p.asPredicate().test(posSeq[i][j]));
+ }
+ }
+ }
+
+ public void testSplitAsStream() {
+ String s[];
+ Pattern pat = Pattern.compile("b");
+ s = pat.splitAsStream("abccbadfebb").toArray(String[]::new);
+ assertEquals(s.length, 3);
+ s = pat.splitAsStream("").toArray(String[]::new);
+ assertEquals(s.length, 0);
+ pat = Pattern.compile("");
+ s = pat.splitAsStream("").toArray(String[]::new);
+ assertEquals(s.length, 0);
+ s = pat.splitAsStream("abccbadfe").toArray(String[]::new);
+ assertEquals(s.length, 9);
+ }
}
diff --git a/ojluni/src/main/java/java/io/BufferedReader.java b/ojluni/src/main/java/java/io/BufferedReader.java
index 4d2962c..5a45f4b 100755
--- a/ojluni/src/main/java/java/io/BufferedReader.java
+++ b/ojluni/src/main/java/java/io/BufferedReader.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -27,6 +27,13 @@
package java.io;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
/**
* Reads text from a character-input stream, buffering characters so as to
* provide for the efficient reading of characters, arrays, and lines.
@@ -530,4 +537,65 @@
cb = null;
}
}
+
+ /**
+ * Returns a {@code Stream}, the elements of which are lines read from
+ * this {@code BufferedReader}. The {@link Stream} is lazily populated,
+ * i.e., read only occurs during the
+ * <a href="../util/stream/package-summary.html#StreamOps">terminal
+ * stream operation</a>.
+ *
+ * <p> The reader must not be operated on during the execution of the
+ * terminal stream operation. Otherwise, the result of the terminal stream
+ * operation is undefined.
+ *
+ * <p> After execution of the terminal stream operation there are no
+ * guarantees that the reader will be at a specific position from which to
+ * read the next character or line.
+ *
+ * <p> If an {@link IOException} is thrown when accessing the underlying
+ * {@code BufferedReader}, it is wrapped in an {@link
+ * UncheckedIOException} which will be thrown from the {@code Stream}
+ * method that caused the read to take place. This method will return a
+ * Stream if invoked on a BufferedReader that is closed. Any operation on
+ * that stream that requires reading from the BufferedReader after it is
+ * closed, will cause an UncheckedIOException to be thrown.
+ *
+ * @return a {@code Stream<String>} providing the lines of text
+ * described by this {@code BufferedReader}
+ *
+ * @since 1.8
+ */
+ public Stream<String> lines() {
+ Iterator<String> iter = new Iterator<String>() {
+ String nextLine = null;
+
+ @Override
+ public boolean hasNext() {
+ if (nextLine != null) {
+ return true;
+ } else {
+ try {
+ nextLine = readLine();
+ return (nextLine != null);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+ @Override
+ public String next() {
+ if (nextLine != null || hasNext()) {
+ String line = nextLine;
+ nextLine = null;
+ return line;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ };
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
}
diff --git a/ojluni/src/main/java/java/io/UncheckedIOException.java b/ojluni/src/main/java/java/io/UncheckedIOException.java
new file mode 100644
index 0000000..22c43e3
--- /dev/null
+++ b/ojluni/src/main/java/java/io/UncheckedIOException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 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 java.io;
+
+import java.util.Objects;
+
+/**
+ * Wraps an {@link IOException} with an unchecked exception.
+ *
+ * @since 1.8
+ */
+public class UncheckedIOException extends RuntimeException {
+ private static final long serialVersionUID = -8134305061645241065L;
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param message
+ * the detail message, can be null
+ * @param cause
+ * the {@code IOException}
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public UncheckedIOException(String message, IOException cause) {
+ super(message, Objects.requireNonNull(cause));
+ }
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param cause
+ * the {@code IOException}
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public UncheckedIOException(IOException cause) {
+ super(Objects.requireNonNull(cause));
+ }
+
+ /**
+ * Returns the cause of this exception.
+ *
+ * @return the {@code IOException} which is the cause of this exception.
+ */
+ @Override
+ public IOException getCause() {
+ return (IOException) super.getCause();
+ }
+
+ /**
+ * Called to read the object from a stream.
+ *
+ * @throws InvalidObjectException
+ * if the object is invalid or has a cause that is not
+ * an {@code IOException}
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ Throwable cause = super.getCause();
+ if (!(cause instanceof IOException))
+ throw new InvalidObjectException("Cause must be an IOException");
+ }
+}
diff --git a/ojluni/src/main/java/java/util/BitSet.java b/ojluni/src/main/java/java/util/BitSet.java
index fa0be57..3620cee 100755
--- a/ojluni/src/main/java/java/util/BitSet.java
+++ b/ojluni/src/main/java/java/util/BitSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.LongBuffer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
/**
* This class implements a vector of bits that grows as needed. Each
@@ -1188,4 +1190,48 @@
b.append('}');
return b.toString();
}
+
+ /**
+ * Returns a stream of indices for which this {@code BitSet}
+ * contains a bit in the set state. The indices are returned
+ * in order, from lowest to highest. The size of the stream
+ * is the number of bits in the set state, equal to the value
+ * returned by the {@link #cardinality()} method.
+ *
+ * <p>The bit set must remain constant during the execution of the
+ * terminal stream operation. Otherwise, the result of the terminal
+ * stream operation is undefined.
+ *
+ * @return a stream of integers representing set indices
+ * @since 1.8
+ */
+ public IntStream stream() {
+ class BitSetIterator implements PrimitiveIterator.OfInt {
+ int next = nextSetBit(0);
+
+ @Override
+ public boolean hasNext() {
+ return next != -1;
+ }
+
+ @Override
+ public int nextInt() {
+ if (next != -1) {
+ int ret = next;
+ next = nextSetBit(next+1);
+ return ret;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ }
+
+ return StreamSupport.intStream(
+ () -> Spliterators.spliterator(
+ new BitSetIterator(), cardinality(),
+ Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
+ Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
+ false);
+ }
}
diff --git a/ojluni/src/main/java/java/util/Random.java b/ojluni/src/main/java/java/util/Random.java
index e56051c..fb4ecfd 100755
--- a/ojluni/src/main/java/java/util/Random.java
+++ b/ojluni/src/main/java/java/util/Random.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -26,6 +26,14 @@
package java.util;
import java.io.*;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
import sun.misc.Unsafe;
/**
@@ -81,6 +89,13 @@
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
+ private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+
+ // IllegalArgumentException messages
+ static final String BadBound = "bound must be positive";
+ static final String BadRange = "bound must be greater than origin";
+ static final String BadSize = "size must be non-negative";
+
/**
* Creates a new random number generator. This constructor sets
* the seed of the random number generator to a value very likely
@@ -218,6 +233,82 @@
}
/**
+ * The form of nextLong used by LongStream Spliterators. If
+ * origin is greater than bound, acts as unbounded form of
+ * nextLong, else as bounded form.
+ *
+ * @param origin the least value, unless greater than bound
+ * @param bound the upper bound (exclusive), must not equal origin
+ * @return a pseudorandom value
+ */
+ final long internalNextLong(long origin, long bound) {
+ long r = nextLong();
+ if (origin < bound) {
+ long n = bound - origin, m = n - 1;
+ if ((n & m) == 0L) // power of two
+ r = (r & m) + origin;
+ else if (n > 0L) { // reject over-represented candidates
+ for (long u = r >>> 1; // ensure nonnegative
+ u + m - (r = u % n) < 0L; // rejection check
+ u = nextLong() >>> 1) // retry
+ ;
+ r += origin;
+ }
+ else { // range not representable as long
+ while (r < origin || r >= bound)
+ r = nextLong();
+ }
+ }
+ return r;
+ }
+
+ /**
+ * The form of nextInt used by IntStream Spliterators.
+ * For the unbounded case: uses nextInt().
+ * For the bounded case with representable range: uses nextInt(int bound)
+ * For the bounded case with unrepresentable range: uses nextInt()
+ *
+ * @param origin the least value, unless greater than bound
+ * @param bound the upper bound (exclusive), must not equal origin
+ * @return a pseudorandom value
+ */
+ final int internalNextInt(int origin, int bound) {
+ if (origin < bound) {
+ int n = bound - origin;
+ if (n > 0) {
+ return nextInt(n) + origin;
+ }
+ else { // range not representable as int
+ int r;
+ do {
+ r = nextInt();
+ } while (r < origin || r >= bound);
+ return r;
+ }
+ }
+ else {
+ return nextInt();
+ }
+ }
+
+ /**
+ * The form of nextDouble used by DoubleStream Spliterators.
+ *
+ * @param origin the least value, unless greater than bound
+ * @param bound the upper bound (exclusive), must not equal origin
+ * @return a pseudorandom value
+ */
+ final double internalNextDouble(double origin, double bound) {
+ double r = nextDouble();
+ if (origin < bound) {
+ r = r * (bound - origin) + origin;
+ if (r >= bound) // correct for rounding
+ r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+ }
+ return r;
+ }
+
+ /**
* Returns the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence. The general
* contract of {@code nextInt} is that one {@code int} value is
@@ -512,6 +603,565 @@
}
}
+ // stream methods, coded in a way intended to better isolate for
+ // maintenance purposes the small differences across forms.
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code int} values.
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the method {@link #nextInt()}.
+ *
+ * @param streamSize the number of values to generate
+ * @return a stream of pseudorandom {@code int} values
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @since 1.8
+ */
+ public IntStream ints(long streamSize) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, streamSize, Integer.MAX_VALUE, 0),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code int}
+ * values.
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the method {@link #nextInt()}.
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * ints(Long.MAX_VALUE)}.
+ *
+ * @return a stream of pseudorandom {@code int} values
+ * @since 1.8
+ */
+ public IntStream ints() {
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number
+ * of pseudorandom {@code int} values, each conforming to the given
+ * origin (inclusive) and bound (exclusive).
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the following method with the origin and bound:
+ * <pre> {@code
+ * int nextInt(int origin, int bound) {
+ * int n = bound - origin;
+ * if (n > 0) {
+ * return nextInt(n) + origin;
+ * }
+ * else { // range not representable as int
+ * int r;
+ * do {
+ * r = nextInt();
+ * } while (r < origin || r >= bound);
+ * return r;
+ * }
+ * }}</pre>
+ *
+ * @param streamSize the number of values to generate
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code int} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero, or {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public IntStream ints(long streamSize, int randomNumberOrigin,
+ int randomNumberBound) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * int} values, each conforming to the given origin (inclusive) and bound
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the following method with the origin and bound:
+ * <pre> {@code
+ * int nextInt(int origin, int bound) {
+ * int n = bound - origin;
+ * if (n > 0) {
+ * return nextInt(n) + origin;
+ * }
+ * else { // range not representable as int
+ * int r;
+ * do {
+ * r = nextInt();
+ * } while (r < origin || r >= bound);
+ * return r;
+ * }
+ * }}</pre>
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+ *
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code int} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code long} values.
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the method {@link #nextLong()}.
+ *
+ * @param streamSize the number of values to generate
+ * @return a stream of pseudorandom {@code long} values
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @since 1.8
+ */
+ public LongStream longs(long streamSize) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, streamSize, Long.MAX_VALUE, 0L),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code long}
+ * values.
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the method {@link #nextLong()}.
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * longs(Long.MAX_VALUE)}.
+ *
+ * @return a stream of pseudorandom {@code long} values
+ * @since 1.8
+ */
+ public LongStream longs() {
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code long}, each conforming to the given origin
+ * (inclusive) and bound (exclusive).
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * long nextLong(long origin, long bound) {
+ * long r = nextLong();
+ * long n = bound - origin, m = n - 1;
+ * if ((n & m) == 0L) // power of two
+ * r = (r & m) + origin;
+ * else if (n > 0L) { // reject over-represented candidates
+ * for (long u = r >>> 1; // ensure nonnegative
+ * u + m - (r = u % n) < 0L; // rejection check
+ * u = nextLong() >>> 1) // retry
+ * ;
+ * r += origin;
+ * }
+ * else { // range not representable as long
+ * while (r < origin || r >= bound)
+ * r = nextLong();
+ * }
+ * return r;
+ * }}</pre>
+ *
+ * @param streamSize the number of values to generate
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code long} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero, or {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public LongStream longs(long streamSize, long randomNumberOrigin,
+ long randomNumberBound) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * long} values, each conforming to the given origin (inclusive) and bound
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * long nextLong(long origin, long bound) {
+ * long r = nextLong();
+ * long n = bound - origin, m = n - 1;
+ * if ((n & m) == 0L) // power of two
+ * r = (r & m) + origin;
+ * else if (n > 0L) { // reject over-represented candidates
+ * for (long u = r >>> 1; // ensure nonnegative
+ * u + m - (r = u % n) < 0L; // rejection check
+ * u = nextLong() >>> 1) // retry
+ * ;
+ * r += origin;
+ * }
+ * else { // range not representable as long
+ * while (r < origin || r >= bound)
+ * r = nextLong();
+ * }
+ * return r;
+ * }}</pre>
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+ *
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code long} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code double} values, each between zero
+ * (inclusive) and one (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the method {@link #nextDouble()}.
+ *
+ * @param streamSize the number of values to generate
+ * @return a stream of {@code double} values
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @since 1.8
+ */
+ public DoubleStream doubles(long streamSize) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * double} values, each between zero (inclusive) and one
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the method {@link #nextDouble()}.
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * doubles(Long.MAX_VALUE)}.
+ *
+ * @return a stream of pseudorandom {@code double} values
+ * @since 1.8
+ */
+ public DoubleStream doubles() {
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code double} values, each conforming to the given origin
+ * (inclusive) and bound (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * double nextDouble(double origin, double bound) {
+ * double r = nextDouble();
+ * r = r * (bound - origin) + origin;
+ * if (r >= bound) // correct for rounding
+ * r = Math.nextDown(bound);
+ * return r;
+ * }}</pre>
+ *
+ * @param streamSize the number of values to generate
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @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}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+ double randomNumberBound) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ if (!(randomNumberOrigin < randomNumberBound))
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * double} values, each conforming to the given origin (inclusive) and bound
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * double nextDouble(double origin, double bound) {
+ * double r = nextDouble();
+ * r = r * (bound - origin) + origin;
+ * if (r >= bound) // correct for rounding
+ * r = Math.nextDown(bound);
+ * return r;
+ * }}</pre>
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+ *
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code double} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+ if (!(randomNumberOrigin < randomNumberBound))
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Spliterator for int streams. We multiplex the four int
+ * versions into one class by treating a bound less than origin as
+ * unbounded, and also by treating "infinite" as equivalent to
+ * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+ * approach. The long and double versions of this class are
+ * identical except for types.
+ */
+ static final class RandomIntsSpliterator implements Spliterator.OfInt {
+ final Random rng;
+ long index;
+ final long fence;
+ final int origin;
+ final int bound;
+ RandomIntsSpliterator(Random rng, long index, long fence,
+ int origin, int bound) {
+ this.rng = rng; this.index = index; this.fence = fence;
+ this.origin = origin; this.bound = bound;
+ }
+
+ public RandomIntsSpliterator trySplit() {
+ long i = index, m = (i + fence) >>> 1;
+ return (m <= i) ? null :
+ new RandomIntsSpliterator(rng, i, index = m, origin, bound);
+ }
+
+ public long estimateSize() {
+ return fence - index;
+ }
+
+ public int characteristics() {
+ return (Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.NONNULL | Spliterator.IMMUTABLE);
+ }
+
+ public boolean tryAdvance(IntConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ consumer.accept(rng.internalNextInt(origin, bound));
+ index = i + 1;
+ return true;
+ }
+ return false;
+ }
+
+ public void forEachRemaining(IntConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ index = f;
+ Random r = rng;
+ int o = origin, b = bound;
+ do {
+ consumer.accept(r.internalNextInt(o, b));
+ } while (++i < f);
+ }
+ }
+ }
+
+ /**
+ * Spliterator for long streams.
+ */
+ static final class RandomLongsSpliterator implements Spliterator.OfLong {
+ final Random rng;
+ long index;
+ final long fence;
+ final long origin;
+ final long bound;
+ RandomLongsSpliterator(Random rng, long index, long fence,
+ long origin, long bound) {
+ this.rng = rng; this.index = index; this.fence = fence;
+ this.origin = origin; this.bound = bound;
+ }
+
+ public RandomLongsSpliterator trySplit() {
+ long i = index, m = (i + fence) >>> 1;
+ return (m <= i) ? null :
+ new RandomLongsSpliterator(rng, i, index = m, origin, bound);
+ }
+
+ public long estimateSize() {
+ return fence - index;
+ }
+
+ public int characteristics() {
+ return (Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.NONNULL | Spliterator.IMMUTABLE);
+ }
+
+ public boolean tryAdvance(LongConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ consumer.accept(rng.internalNextLong(origin, bound));
+ index = i + 1;
+ return true;
+ }
+ return false;
+ }
+
+ public void forEachRemaining(LongConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ index = f;
+ Random r = rng;
+ long o = origin, b = bound;
+ do {
+ consumer.accept(r.internalNextLong(o, b));
+ } while (++i < f);
+ }
+ }
+
+ }
+
+ /**
+ * Spliterator for double streams.
+ */
+ static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+ final Random rng;
+ long index;
+ final long fence;
+ final double origin;
+ final double bound;
+ RandomDoublesSpliterator(Random rng, long index, long fence,
+ double origin, double bound) {
+ this.rng = rng; this.index = index; this.fence = fence;
+ this.origin = origin; this.bound = bound;
+ }
+
+ public RandomDoublesSpliterator trySplit() {
+ long i = index, m = (i + fence) >>> 1;
+ return (m <= i) ? null :
+ new RandomDoublesSpliterator(rng, i, index = m, origin, bound);
+ }
+
+ public long estimateSize() {
+ return fence - index;
+ }
+
+ public int characteristics() {
+ return (Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.NONNULL | Spliterator.IMMUTABLE);
+ }
+
+ public boolean tryAdvance(DoubleConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ consumer.accept(rng.internalNextDouble(origin, bound));
+ index = i + 1;
+ return true;
+ }
+ return false;
+ }
+
+ public void forEachRemaining(DoubleConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ index = f;
+ Random r = rng;
+ double o = origin, b = bound;
+ do {
+ consumer.accept(r.internalNextDouble(o, b));
+ } while (++i < f);
+ }
+ }
+ }
+
/**
* Serializable fields for Random.
*
diff --git a/ojluni/src/main/java/java/util/regex/Pattern.java b/ojluni/src/main/java/java/util/regex/Pattern.java
index 8f6fe1f..376aea4 100755
--- a/ojluni/src/main/java/java/util/regex/Pattern.java
+++ b/ojluni/src/main/java/java/util/regex/Pattern.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -26,7 +26,14 @@
package java.util.regex;
+import java.util.Iterator;
import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
/**
@@ -1255,4 +1262,113 @@
private static native void closeImpl(long addr);
private static native long compileImpl(String regex, int flags);
+
+
+ /**
+ * Creates a predicate which can be used to match a string.
+ *
+ * @return The predicate which can be used for matching on a string
+ * @since 1.8
+ */
+ public Predicate<String> asPredicate() {
+ return s -> matcher(s).find();
+ }
+
+ /**
+ * Creates a stream from the given input sequence around matches of this
+ * pattern.
+ *
+ * <p> The stream returned by this method contains each substring of the
+ * input sequence that is terminated by another subsequence that matches
+ * this pattern or is terminated by the end of the input sequence. The
+ * substrings in the stream are in the order in which they occur in the
+ * input. Trailing empty strings will be discarded and not encountered in
+ * the stream.
+ *
+ * <p> If this pattern does not match any subsequence of the input then
+ * the resulting stream has just one element, namely the input sequence in
+ * string form.
+ *
+ * <p> When there is a positive-width match at the beginning of the input
+ * sequence then an empty leading substring is included at the beginning
+ * of the stream. A zero-width match at the beginning however never produces
+ * such empty leading substring.
+ *
+ * <p> If the input sequence is mutable, it must remain constant during the
+ * execution of the terminal stream operation. Otherwise, the result of the
+ * terminal stream operation is undefined.
+ *
+ * @param input
+ * The character sequence to be split
+ *
+ * @return The stream of strings computed by splitting the input
+ * around matches of this pattern
+ * @see #split(CharSequence)
+ * @since 1.8
+ */
+ public Stream<String> splitAsStream(final CharSequence input) {
+ class MatcherIterator implements Iterator<String> {
+ private final Matcher matcher;
+ // The start position of the next sub-sequence of input
+ // when current == input.length there are no more elements
+ private int current;
+ // null if the next element, if any, needs to obtained
+ private String nextElement;
+ // > 0 if there are N next empty elements
+ private int emptyElementCount;
+
+ MatcherIterator() {
+ this.matcher = matcher(input);
+ }
+
+ public String next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ if (emptyElementCount == 0) {
+ String n = nextElement;
+ nextElement = null;
+ return n;
+ } else {
+ emptyElementCount--;
+ return "";
+ }
+ }
+
+ public boolean hasNext() {
+ if (nextElement != null || emptyElementCount > 0)
+ return true;
+
+ if (current == input.length())
+ return false;
+
+ // Consume the next matching element
+ // Count sequence of matching empty elements
+ while (matcher.find()) {
+ nextElement = input.subSequence(current, matcher.start()).toString();
+ current = matcher.end();
+ if (!nextElement.isEmpty()) {
+ return true;
+ } else if (current > 0) { // no empty leading substring for zero-width
+ // match at the beginning of the input
+ emptyElementCount++;
+ }
+ }
+
+ // Consume last matching element
+ nextElement = input.subSequence(current, input.length()).toString();
+ current = input.length();
+ if (!nextElement.isEmpty()) {
+ return true;
+ } else {
+ // Ignore a terminal sequence of matching empty elements
+ emptyElementCount = 0;
+ nextElement = null;
+ return false;
+ }
+ }
+ }
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ new MatcherIterator(), Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
}
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index bb360cd..01f24d1 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -85,6 +85,7 @@
ojluni/src/main/java/java/io/StringReader.java \
ojluni/src/main/java/java/io/StringWriter.java \
ojluni/src/main/java/java/io/SyncFailedException.java \
+ ojluni/src/main/java/java/io/UncheckedIOException.java \
ojluni/src/main/java/java/io/UnixFileSystem.java \
ojluni/src/main/java/java/io/UnsupportedEncodingException.java \
ojluni/src/main/java/java/io/UTFDataFormatException.java \