8014854: (bf) CharBuffer.chars too slow with default implementation
Reviewed-by: erikj, briangoetz, henryjen, psandoz, mduigou
This commit is contained in:
parent
608c513883
commit
f3d7029319
jdk
makefiles
src/share/classes/java/nio
Buffer.javaByteBufferAs-X-Buffer.java.templateCharBufferSpliterator.javaDirect-X-Buffer.java.templateHeap-X-Buffer.java.templateStringCharBuffer.javaX-Buffer.java.template
test/java/nio/Buffer
@ -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,\
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
96
jdk/src/share/classes/java/nio/CharBufferSpliterator.java
Normal file
96
jdk/src/share/classes/java/nio/CharBufferSpliterator.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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())
|
||||
|
@ -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) {
|
||||
|
@ -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 <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 <i>(optional operation)</i>.
|
||||
*
|
||||
@ -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]
|
||||
|
||||
}
|
||||
|
137
jdk/test/java/nio/Buffer/Chars.java
Normal file
137
jdk/test/java/nio/Buffer/Chars.java
Normal file
@ -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<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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user