8012665: add CharSequence.chars, CharSequence.codePoints
Reviewed-by: martin, alanb, ulfzibis, mduigou
Contributed-by: Stuart Marks <stuart.marks@oracle.com>, Henry Jen <henry.jen@oracle.com>
--- a/jdk/src/share/classes/java/lang/CharSequence.java Wed May 01 21:05:10 2013 +0800
+++ b/jdk/src/share/classes/java/lang/CharSequence.java Wed May 01 08:35:09 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -25,6 +25,13 @@
package java.lang;
+import java.util.NoSuchElementException;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.IntConsumer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
/**
* A <tt>CharSequence</tt> is a readable sequence of <code>char</code> values. This
@@ -108,4 +115,95 @@
*/
public String toString();
+ /**
+ * Returns a stream of {@code int} zero-extending the {@code char} values
+ * from this sequence. Any char which maps to a <a
+ * href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
+ * point</a> is passed through uninterpreted.
+ *
+ * <p>If the sequence is mutated while the stream is being read, the
+ * result is undefined.
+ *
+ * @return an IntStream of char values from this sequence
+ * @since 1.8
+ */
+ public default IntStream chars() {
+ class CharIterator implements PrimitiveIterator.OfInt {
+ int cur = 0;
+
+ public boolean hasNext() {
+ return cur < length();
+ }
+
+ public int nextInt() {
+ if (hasNext()) {
+ return charAt(cur++);
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ @Override
+ public void forEachRemaining(IntConsumer block) {
+ for (; cur < length(); cur++) {
+ block.accept(charAt(cur));
+ }
+ }
+ }
+
+ return StreamSupport.intStream(() ->
+ Spliterators.spliterator(
+ new CharIterator(),
+ length(),
+ Spliterator.ORDERED),
+ Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED);
+ }
+
+ /**
+ * Returns a stream of code point values from this sequence. Any surrogate
+ * pairs encountered in the sequence are combined as if by {@linkplain
+ * Character#toCodePoint Character.toCodePoint} and the result is passed
+ * to the stream. Any other code units, including ordinary BMP characters,
+ * unpaired surrogates, and undefined code units, are zero-extended to
+ * {@code int} values which are then passed to the stream.
+ *
+ * <p>If the sequence is mutated while the stream is being read, the result
+ * is undefined.
+ *
+ * @return an IntStream of Unicode code points from this sequence
+ * @since 1.8
+ */
+ public default IntStream codePoints() {
+ class CodePointIterator implements PrimitiveIterator.OfInt {
+ int cur = 0;
+
+ @Override
+ public void forEachRemaining(IntConsumer block) {
+ while (cur < length()) {
+ int cp = Character.codePointAt(CharSequence.this, cur);
+ cur += Character.charCount(cp);
+ block.accept(cp);
+ }
+ }
+
+ public boolean hasNext() {
+ return cur < length();
+ }
+
+ public int nextInt() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ int cp = Character.codePointAt(CharSequence.this, cur);
+ cur += Character.charCount(cp);
+ return cp;
+ }
+ }
+
+ return StreamSupport.intStream(() ->
+ Spliterators.spliteratorUnknownSize(
+ new CodePointIterator(),
+ Spliterator.ORDERED),
+ Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/CharSequence/DefaultTest.java Wed May 01 08:35:09 2013 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.PrimitiveIterator;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @summary Unit test for CharSequence default methods
+ * @bug 8012665
+ * @run testng DefaultTest
+ */
+
+@Test(groups = "lib")
+public class DefaultTest {
+
+ @Test(expectedExceptions = NoSuchElementException.class)
+ public void testEmptyChars() {
+ PrimitiveIterator.OfInt s = "".chars().iterator();
+ assertFalse(s.hasNext());
+ int ch = s.nextInt();
+ }
+
+ public void testSimpleChars() {
+ List<Integer> list = "abc".chars().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList((int) 'a', (int) 'b', (int) 'c'));
+ }
+
+ @Test(expectedExceptions = NoSuchElementException.class)
+ public void testEmptyCodePoints() {
+ PrimitiveIterator.OfInt s = "".codePoints().iterator();
+ assertFalse(s.hasNext());
+ int cp = s.nextInt();
+ }
+
+ public void testSimpleCodePoints() {
+ List<Integer> list = "abc".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList((int)'a', (int)'b', (int)'c'));
+ }
+
+ public void testUndefCodePoints() {
+ List<Integer> list = "X\ufffeY".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList((int)'X', 0xFFFE, (int)'Y'));
+ }
+
+ public void testSurrogatePairing() {
+ // U+1D11E = MUSICAL SYMBOL G CLEF
+ // equivalent to surrogate pair U+D834 U+DD1E
+ List<Integer> list;
+ final int GCLEF = 0x1d11e;
+
+ list = "\ud834\udd1e".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList(GCLEF));
+ list = "A\ud834\udd1e".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList((int)'A', GCLEF));
+ list = "\ud834\udd1eB".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList(GCLEF, (int)'B'));
+ list = "X\ud834\udd1eY".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList((int)'X', GCLEF, (int)'Y'));
+ }
+
+ public void testUndefUnpaired() {
+ List<Integer> list = "W\udd1eX\ud834Y\ufffeZ".codePoints().boxed().collect(Collectors.toList());
+ assertEquals(list, Arrays.asList(
+ (int)'W', 0xdd1e, (int)'X', 0xd834, (int)'Y', 0xfffe, (int)'Z'));
+ }
+}
--- a/jdk/test/java/lang/StringBuffer/TestSynchronization.java Wed May 01 21:05:10 2013 +0800
+++ b/jdk/test/java/lang/StringBuffer/TestSynchronization.java Wed May 01 08:35:09 2013 -0700
@@ -96,6 +96,10 @@
// the right thing.
List<Method> methods = Arrays.asList(aClass.getDeclaredMethods());
for (Method m : methods) {
+ // skip synthetic methods, like default interface methods and lambdas
+ if (m.isSynthetic()) {
+ continue;
+ }
int modifiers = m.getModifiers();
if (Modifier.isPublic(modifiers)
&& !Modifier.isSynchronized(modifiers)) {