diff --git a/makefiles/CompileJavaClasses.gmk b/makefiles/CompileJavaClasses.gmk index 24ce0d922f03699330f6fb6c0d51993b57b4b163..0b3e70dd9146f77602de18164c040a742a8e92c7 100644 --- a/makefiles/CompileJavaClasses.gmk +++ b/makefiles/CompileJavaClasses.gmk @@ -342,7 +342,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JOBJC,\ DISABLE_SJAVAC:=true,\ SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \ $(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \ - $(JDK_OUTPUTDIR)/gensrc, \ + $(JDK_OUTPUTDIR)/gensrc_jobjc/src, \ INCLUDES := com/apple/jobjc,\ EXCLUDES := tests/java/com/apple/jobjc,\ BIN:=$(JDK_OUTPUTDIR)/jobjc_classes,\ @@ -355,7 +355,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JOBJC_HEADERS,\ SETUP:=GENERATE_JDKBYTECODE,\ SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \ $(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \ - $(JDK_OUTPUTDIR)/gensrc, \ + $(JDK_OUTPUTDIR)/gensrc_jobjc/src, \ INCLUDES := com/apple/jobjc,\ EXCLUDES := tests/java/com/apple/jobjc,\ BIN:=$(JDK_OUTPUTDIR)/jobjc_classes_headers,\ diff --git a/makefiles/GensrcBuffer.gmk b/makefiles/GensrcBuffer.gmk index 3e55b1c14a45102a70bb0733c5013878ada24c63..55b51d050d8092658e831eb280b424ed55d28f06 100644 --- a/makefiles/GensrcBuffer.gmk +++ b/makefiles/GensrcBuffer.gmk @@ -69,6 +69,9 @@ define typesAndBits $1_fulltype := character $1_Fulltype := Character $1_category := integralType + $1_streams := streamableType + $1_streamtype := int + $1_Streamtype := Int $1_LBPV := 1 endif @@ -97,7 +100,7 @@ define typesAndBits $1_Type := Long $1_fulltype := long $1_Fulltype := Long - $1_category := integralType + $1_category := integralType $1_LBPV := 3 endif @@ -231,10 +234,13 @@ $$($1_DST) : $$($1_DEP) $(GENSRC_BUFFER_DST)/_the.buffer.dir $(TOOL_SPP) < $$($1_SRC) > $$($1_OUT).tmp \ -K$$($1_type) \ -K$$($1_category) \ + -K$$($1_streams) \ -Dtype=$$($1_type) \ -DType=$$($1_Type) \ -Dfulltype=$$($1_fulltype) \ -DFulltype=$$($1_Fulltype) \ + -Dstreamtype=$$($1_streamtype) \ + -DStreamtype=$$($1_Streamtype) \ -Dx=$$($1_x) \ -Dmemtype=$$($1_memtype) \ -DMemtype=$$($1_Memtype) \ diff --git a/src/share/classes/java/nio/Buffer.java b/src/share/classes/java/nio/Buffer.java index 1c0591fb28f98dc05b6467250037e1f39cc0cfd9..24d3cf8c56ab678a33e255ab3fd849f183a10adf 100644 --- a/src/share/classes/java/nio/Buffer.java +++ b/src/share/classes/java/nio/Buffer.java @@ -25,6 +25,7 @@ package java.nio; +import java.util.Spliterator; /** * A container for data of a specific primitive type. @@ -173,6 +174,13 @@ package java.nio; public abstract class Buffer { + /** + * The characteristics of Spliterators that traverse and split elements + * maintained in Buffers. + */ + static final int SPLITERATOR_CHARACTERISTICS = + Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED; + // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; diff --git a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template index 1673da2bf45c349b74b872cb5c1f9045c875d161..d5be9669fb8e27ae68ce03ac37d1a75e0727e2f1 100644 --- a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template +++ b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template @@ -115,6 +115,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private return Bits.get$Type$$BO$(bb, ix(checkIndex(i))); } +#if[streamableType] + $type$ getUnchecked(int i) { + return Bits.get$Type$$BO$(bb, ix(i)); + } +#end[streamableType] + #end[rw] public $Type$Buffer put($type$ x) { diff --git a/src/share/classes/java/nio/CharBufferSpliterator.java b/src/share/classes/java/nio/CharBufferSpliterator.java new file mode 100644 index 0000000000000000000000000000000000000000..19fd8a8f0ba8b858239f107d56769fc12b535b07 --- /dev/null +++ b/src/share/classes/java/nio/CharBufferSpliterator.java @@ -0,0 +1,96 @@ +/* + * 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 java.nio; + +import java.util.Comparator; +import java.util.Spliterator; +import java.util.function.IntConsumer; + +/** + * A Spliterator.OfInt for sources that traverse and split elements + * maintained in a CharBuffer. + * + * @implNote + * The implementation is based on the code for the Array-based spliterators. + */ +class CharBufferSpliterator implements Spliterator.OfInt { + private final CharBuffer buffer; + private int index; // current index, modified on advance/split + private final int limit; + + CharBufferSpliterator(CharBuffer buffer) { + this(buffer, buffer.position(), buffer.limit()); + } + + CharBufferSpliterator(CharBuffer buffer, int origin, int limit) { + assert origin <= limit; + this.buffer = buffer; + this.index = (origin <= limit) ? origin : limit; + this.limit = limit; + } + + @Override + public OfInt trySplit() { + int lo = index, mid = (lo + limit) >>> 1; + return (lo >= mid) + ? null + : new CharBufferSpliterator(buffer, lo, index = mid); + } + + @Override + public void forEachRemaining(IntConsumer action) { + if (action == null) + throw new NullPointerException(); + CharBuffer cb = buffer; + int i = index; + int hi = limit; + index = hi; + while (i < hi) { + action.accept(cb.getUnchecked(i++)); + } + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < limit) { + action.accept(buffer.getUnchecked(index++)); + return true; + } + return false; + } + + @Override + public long estimateSize() { + return (long)(limit - index); + } + + @Override + public int characteristics() { + return Buffer.SPLITERATOR_CHARACTERISTICS; + } +} diff --git a/src/share/classes/java/nio/Direct-X-Buffer.java.template b/src/share/classes/java/nio/Direct-X-Buffer.java.template index d01e873697d658b499629e293c1fb60a354421d3..0523e2a2cd68cffad99ae3fc450181d4c2ba08a9 100644 --- a/src/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/src/share/classes/java/nio/Direct-X-Buffer.java.template @@ -253,6 +253,12 @@ class Direct$Type$Buffer$RW$$BO$ return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i))))); } +#if[streamableType] + $type$ getUnchecked(int i) { + return $fromBits$($swap$(unsafe.get$Swaptype$(ix(i)))); + } +#end[streamableType] + public $Type$Buffer get($type$[] dst, int offset, int length) { #if[rw] if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { diff --git a/src/share/classes/java/nio/Heap-X-Buffer.java.template b/src/share/classes/java/nio/Heap-X-Buffer.java.template index cecc1bacf9a869eec0f19cd226258cebcd66d162..54f7164b24cb1494f331362acb447c56a8c8e4ee 100644 --- a/src/share/classes/java/nio/Heap-X-Buffer.java.template +++ b/src/share/classes/java/nio/Heap-X-Buffer.java.template @@ -139,6 +139,12 @@ class Heap$Type$Buffer$RW$ return hb[ix(checkIndex(i))]; } +#if[streamableType] + $type$ getUnchecked(int i) { + return hb[ix(i)]; + } +#end[streamableType] + public $Type$Buffer get($type$[] dst, int offset, int length) { checkBounds(offset, length, dst.length); if (length > remaining()) diff --git a/src/share/classes/java/nio/StringCharBuffer.java b/src/share/classes/java/nio/StringCharBuffer.java index 47b6bae32289e4b46b66c19e7fc76a2a944b44f8..a277ef559bda7d696e1744bb956481540a690f1c 100644 --- a/src/share/classes/java/nio/StringCharBuffer.java +++ b/src/share/classes/java/nio/StringCharBuffer.java @@ -77,6 +77,10 @@ class StringCharBuffer // package-private return str.charAt(checkIndex(index) + offset); } + char getUnchecked(int index) { + return str.charAt(index + offset); + } + // ## Override bulk get methods for better performance public final CharBuffer put(char c) { diff --git a/src/share/classes/java/nio/X-Buffer.java.template b/src/share/classes/java/nio/X-Buffer.java.template index a727b000bf1ff08a1469d26a6f751cbc94ab9e25..475818d300db8fc74e50255b3ef6f716fe9695f8 100644 --- a/src/share/classes/java/nio/X-Buffer.java.template +++ b/src/share/classes/java/nio/X-Buffer.java.template @@ -30,6 +30,11 @@ package java.nio; #if[char] import java.io.IOException; #end[char] +#if[streamableType] +import java.util.Spliterator; +import java.util.stream.StreamSupport; +import java.util.stream.$Streamtype$Stream; +#end[streamableType] /** * $A$ $type$ buffer. @@ -589,6 +594,19 @@ public abstract class $Type$Buffer */ public abstract $type$ get(int index); +#if[streamableType] + /** + * Absolute get method. Reads the $type$ at the given + * index without any validation of the index. + * + * @param index + * The index from which the $type$ will be read + * + * @return The $type$ at the given index + */ + abstract $type$ getUnchecked(int index); // package-private +#end[streamableType] + /** * Absolute put method  (optional operation). * @@ -1458,4 +1476,16 @@ public abstract class $Type$Buffer #end[byte] +#if[streamableType] + +#if[char] + @Override +#end[char] + public $Streamtype$Stream $type$s() { + return StreamSupport.$streamtype$Stream(() -> new $Type$BufferSpliterator(this), + Buffer.SPLITERATOR_CHARACTERISTICS); + } + +#end[streamableType] + } diff --git a/test/java/nio/Buffer/Chars.java b/test/java/nio/Buffer/Chars.java new file mode 100644 index 0000000000000000000000000000000000000000..e91b6a73883fcb9a2acdd594fe0e7970edd277aa --- /dev/null +++ b/test/java/nio/Buffer/Chars.java @@ -0,0 +1,137 @@ +/* + * 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. + * + * 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 8014854 + * @summary Exercises CharBuffer#chars on each of the CharBuffer types + * @run testng Chars + */ + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +public class Chars { + + static final Random RAND = new Random(); + + static final int SIZE = 128 + RAND.nextInt(1024); + + /** + * Randomize the char buffer's position and limit. + */ + static CharBuffer randomizeRange(CharBuffer cb) { + int mid = cb.capacity() >>> 1; + int start = RAND.nextInt(mid); + int end = mid + RAND.nextInt(mid); + cb.position(start); + cb.limit(end); + return cb; + } + + /** + * Randomize the char buffer's contents, position and limit. + */ + static CharBuffer randomize(CharBuffer cb) { + while (cb.hasRemaining()) { + cb.put((char)RAND.nextInt()); + } + return randomizeRange(cb); + } + + /** + * Sums the remaining chars in the char buffer. + */ + static int intSum(CharBuffer cb) { + int sum = 0; + cb.mark(); + while (cb.hasRemaining()) { + sum += cb.get(); + } + cb.reset(); + return sum; + } + + /** + * Creates char buffers to test, adding them to the given list. + */ + static void addCases(CharBuffer cb, List buffers) { + randomize(cb); + buffers.add(cb); + + buffers.add(cb.slice()); + buffers.add(cb.duplicate()); + buffers.add(cb.asReadOnlyBuffer()); + + buffers.add(randomizeRange(cb.slice())); + buffers.add(randomizeRange(cb.duplicate())); + buffers.add(randomizeRange(cb.asReadOnlyBuffer())); + } + + @DataProvider(name = "charbuffers") + public Object[][] createCharBuffers() { + List buffers = new ArrayList<>(); + + // heap + addCases(CharBuffer.allocate(SIZE), buffers); + addCases(CharBuffer.wrap(new char[SIZE]), buffers); + addCases(ByteBuffer.allocate(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), + buffers); + addCases(ByteBuffer.allocate(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), + buffers); + + // direct + addCases(ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), + buffers); + addCases(ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), + buffers); + + // read-only buffer backed by a CharSequence + buffers.add(CharBuffer.wrap(randomize(CharBuffer.allocate(SIZE)))); + + Object[][] params = new Object[buffers.size()][]; + for (int i = 0; i < buffers.size(); i++) { + CharBuffer cb = buffers.get(i); + params[i] = new Object[] { cb.getClass().getName(), cb }; + } + + return params; + } + + @Test(dataProvider = "charbuffers") + public void testChars(String type, CharBuffer cb) { + System.out.format("%s position=%d, limit=%d%n", type, cb.position(), cb.limit()); + int expected = intSum(cb); + assertEquals(cb.chars().sum(), expected); + assertEquals(cb.chars().parallel().sum(), expected); + } +}