提交 8de78556 编写于 作者: A alanb

8014854: (bf) CharBuffer.chars too slow with default implementation

Reviewed-by: erikj, briangoetz, henryjen, psandoz, mduigou
上级 f51218f1
...@@ -342,7 +342,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JOBJC,\ ...@@ -342,7 +342,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JOBJC,\
DISABLE_SJAVAC:=true,\ DISABLE_SJAVAC:=true,\
SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \ SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \
$(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \ $(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \
$(JDK_OUTPUTDIR)/gensrc, \ $(JDK_OUTPUTDIR)/gensrc_jobjc/src, \
INCLUDES := com/apple/jobjc,\ INCLUDES := com/apple/jobjc,\
EXCLUDES := tests/java/com/apple/jobjc,\ EXCLUDES := tests/java/com/apple/jobjc,\
BIN:=$(JDK_OUTPUTDIR)/jobjc_classes,\ BIN:=$(JDK_OUTPUTDIR)/jobjc_classes,\
...@@ -355,7 +355,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JOBJC_HEADERS,\ ...@@ -355,7 +355,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JOBJC_HEADERS,\
SETUP:=GENERATE_JDKBYTECODE,\ SETUP:=GENERATE_JDKBYTECODE,\
SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \ SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \
$(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \ $(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \
$(JDK_OUTPUTDIR)/gensrc, \ $(JDK_OUTPUTDIR)/gensrc_jobjc/src, \
INCLUDES := com/apple/jobjc,\ INCLUDES := com/apple/jobjc,\
EXCLUDES := tests/java/com/apple/jobjc,\ EXCLUDES := tests/java/com/apple/jobjc,\
BIN:=$(JDK_OUTPUTDIR)/jobjc_classes_headers,\ BIN:=$(JDK_OUTPUTDIR)/jobjc_classes_headers,\
......
...@@ -69,6 +69,9 @@ define typesAndBits ...@@ -69,6 +69,9 @@ define typesAndBits
$1_fulltype := character $1_fulltype := character
$1_Fulltype := Character $1_Fulltype := Character
$1_category := integralType $1_category := integralType
$1_streams := streamableType
$1_streamtype := int
$1_Streamtype := Int
$1_LBPV := 1 $1_LBPV := 1
endif endif
...@@ -97,7 +100,7 @@ define typesAndBits ...@@ -97,7 +100,7 @@ define typesAndBits
$1_Type := Long $1_Type := Long
$1_fulltype := long $1_fulltype := long
$1_Fulltype := Long $1_Fulltype := Long
$1_category := integralType $1_category := integralType
$1_LBPV := 3 $1_LBPV := 3
endif endif
...@@ -231,10 +234,13 @@ $$($1_DST) : $$($1_DEP) $(GENSRC_BUFFER_DST)/_the.buffer.dir ...@@ -231,10 +234,13 @@ $$($1_DST) : $$($1_DEP) $(GENSRC_BUFFER_DST)/_the.buffer.dir
$(TOOL_SPP) < $$($1_SRC) > $$($1_OUT).tmp \ $(TOOL_SPP) < $$($1_SRC) > $$($1_OUT).tmp \
-K$$($1_type) \ -K$$($1_type) \
-K$$($1_category) \ -K$$($1_category) \
-K$$($1_streams) \
-Dtype=$$($1_type) \ -Dtype=$$($1_type) \
-DType=$$($1_Type) \ -DType=$$($1_Type) \
-Dfulltype=$$($1_fulltype) \ -Dfulltype=$$($1_fulltype) \
-DFulltype=$$($1_Fulltype) \ -DFulltype=$$($1_Fulltype) \
-Dstreamtype=$$($1_streamtype) \
-DStreamtype=$$($1_Streamtype) \
-Dx=$$($1_x) \ -Dx=$$($1_x) \
-Dmemtype=$$($1_memtype) \ -Dmemtype=$$($1_memtype) \
-DMemtype=$$($1_Memtype) \ -DMemtype=$$($1_Memtype) \
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package java.nio; package java.nio;
import java.util.Spliterator;
/** /**
* A container for data of a specific primitive type. * A container for data of a specific primitive type.
...@@ -173,6 +174,13 @@ package java.nio; ...@@ -173,6 +174,13 @@ package java.nio;
public abstract class Buffer { 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 // Invariants: mark <= position <= limit <= capacity
private int mark = -1; private int mark = -1;
private int position = 0; private int position = 0;
......
...@@ -115,6 +115,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private ...@@ -115,6 +115,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
return Bits.get$Type$$BO$(bb, ix(checkIndex(i))); 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] #end[rw]
public $Type$Buffer put($type$ x) { public $Type$Buffer put($type$ x) {
......
/*
* 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;
}
}
...@@ -253,6 +253,12 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -253,6 +253,12 @@ class Direct$Type$Buffer$RW$$BO$
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i))))); 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) { public $Type$Buffer get($type$[] dst, int offset, int length) {
#if[rw] #if[rw]
if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
......
...@@ -139,6 +139,12 @@ class Heap$Type$Buffer$RW$ ...@@ -139,6 +139,12 @@ class Heap$Type$Buffer$RW$
return hb[ix(checkIndex(i))]; 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) { public $Type$Buffer get($type$[] dst, int offset, int length) {
checkBounds(offset, length, dst.length); checkBounds(offset, length, dst.length);
if (length > remaining()) if (length > remaining())
......
...@@ -77,6 +77,10 @@ class StringCharBuffer // package-private ...@@ -77,6 +77,10 @@ class StringCharBuffer // package-private
return str.charAt(checkIndex(index) + offset); return str.charAt(checkIndex(index) + offset);
} }
char getUnchecked(int index) {
return str.charAt(index + offset);
}
// ## Override bulk get methods for better performance // ## Override bulk get methods for better performance
public final CharBuffer put(char c) { public final CharBuffer put(char c) {
......
...@@ -30,6 +30,11 @@ package java.nio; ...@@ -30,6 +30,11 @@ package java.nio;
#if[char] #if[char]
import java.io.IOException; import java.io.IOException;
#end[char] #end[char]
#if[streamableType]
import java.util.Spliterator;
import java.util.stream.StreamSupport;
import java.util.stream.$Streamtype$Stream;
#end[streamableType]
/** /**
* $A$ $type$ buffer. * $A$ $type$ buffer.
...@@ -589,6 +594,19 @@ public abstract class $Type$Buffer ...@@ -589,6 +594,19 @@ public abstract class $Type$Buffer
*/ */
public abstract $type$ get(int index); public abstract $type$ get(int index);
#if[streamableType]
/**
* Absolute <i>get</i> 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 <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>. * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
* *
...@@ -1458,4 +1476,16 @@ public abstract class $Type$Buffer ...@@ -1458,4 +1476,16 @@ public abstract class $Type$Buffer
#end[byte] #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]
} }
/*
* 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<CharBuffer> 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<CharBuffer> 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);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册