8219014: (bf) Add absolute bulk put methods which accept a source Buffer
Reviewed-by: psandoz, alanb
This commit is contained in:
parent
3a02578b33
commit
a50fdd5484
@ -416,6 +416,16 @@ class Direct$Type$Buffer$RW$$BO$
|
|||||||
#end[rw]
|
#end[rw]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) {
|
||||||
|
#if[rw]
|
||||||
|
checkSegment();
|
||||||
|
super.put(index, src, offset, length);
|
||||||
|
return this;
|
||||||
|
#else[rw]
|
||||||
|
throw new ReadOnlyBufferException();
|
||||||
|
#end[rw]
|
||||||
|
}
|
||||||
|
|
||||||
public $Type$Buffer put($type$[] src, int offset, int length) {
|
public $Type$Buffer put($type$[] src, int offset, int length) {
|
||||||
#if[rw]
|
#if[rw]
|
||||||
checkSegment();
|
checkSegment();
|
||||||
|
@ -251,6 +251,16 @@ class Heap$Type$Buffer$RW$
|
|||||||
#end[rw]
|
#end[rw]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) {
|
||||||
|
#if[rw]
|
||||||
|
checkSegment();
|
||||||
|
super.put(index, src, offset, length);
|
||||||
|
return this;
|
||||||
|
#else[rw]
|
||||||
|
throw new ReadOnlyBufferException();
|
||||||
|
#end[rw]
|
||||||
|
}
|
||||||
|
|
||||||
public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
|
public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
|
||||||
#if[rw]
|
#if[rw]
|
||||||
checkSegment();
|
checkSegment();
|
||||||
|
@ -956,6 +956,76 @@ public abstract class $Type$Buffer
|
|||||||
if (n > limit() - pos)
|
if (n > limit() - pos)
|
||||||
throw new BufferOverflowException();
|
throw new BufferOverflowException();
|
||||||
|
|
||||||
|
putBuffer(pos, src, srcPos, n);
|
||||||
|
|
||||||
|
position(pos + n);
|
||||||
|
src.position(srcPos + n);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Absolute bulk <i>put</i> method <i>(optional operation)</i>.
|
||||||
|
*
|
||||||
|
* <p> This method transfers {@code length} $type$s into this buffer from
|
||||||
|
* the given source buffer, starting at the given {@code offset} in the
|
||||||
|
* source buffer and the given {@code index} in this buffer. The positions
|
||||||
|
* of both buffers are unchanged.
|
||||||
|
*
|
||||||
|
* <p> In other words, an invocation of this method of the form
|
||||||
|
* <code>dst.put(index, src, offset, length)</code>
|
||||||
|
* has exactly the same effect as the loop
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* for (int i = offset, j = index; i < offset + length; i++, j++)
|
||||||
|
* dst.put(j, src.get(i));
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* except that it first checks the consistency of the supplied parameters
|
||||||
|
* and it is potentially much more efficient. If this buffer and
|
||||||
|
* the source buffer share the same backing array or memory, then the
|
||||||
|
* result will be as if the source elements were first copied to an
|
||||||
|
* intermediate location before being written into this buffer.
|
||||||
|
*
|
||||||
|
* @param index
|
||||||
|
* The index in this buffer at which the first $type$ will be
|
||||||
|
* written; must be non-negative and less than {@code limit()}
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The buffer from which $type$s are to be read
|
||||||
|
*
|
||||||
|
* @param offset
|
||||||
|
* The index within the source buffer of the first $type$ to be
|
||||||
|
* read; must be non-negative and less than {@code src.limit()}
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* The number of $type$s to be read from the given buffer;
|
||||||
|
* must be non-negative and no larger than the smaller of
|
||||||
|
* {@code limit() - index} and {@code src.limit() - offset}
|
||||||
|
*
|
||||||
|
* @return This buffer
|
||||||
|
*
|
||||||
|
* @throws IndexOutOfBoundsException
|
||||||
|
* If the preconditions on the {@code index}, {@code offset}, and
|
||||||
|
* {@code length} parameters do not hold
|
||||||
|
*
|
||||||
|
* @throws ReadOnlyBufferException
|
||||||
|
* If this buffer is read-only
|
||||||
|
*
|
||||||
|
* @since 16
|
||||||
|
*/
|
||||||
|
public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) {
|
||||||
|
Objects.checkFromIndexSize(index, length, limit());
|
||||||
|
Objects.checkFromIndexSize(offset, length, src.limit());
|
||||||
|
if (isReadOnly())
|
||||||
|
throw new ReadOnlyBufferException();
|
||||||
|
|
||||||
|
putBuffer(index, src, offset, length);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void putBuffer(int pos, $Type$Buffer src, int srcPos, int n) {
|
||||||
Object srcBase = src.base();
|
Object srcBase = src.base();
|
||||||
|
|
||||||
#if[char]
|
#if[char]
|
||||||
@ -999,18 +1069,14 @@ public abstract class $Type$Buffer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#end[!byte]
|
#end[!byte]
|
||||||
|
|
||||||
position(pos + n);
|
|
||||||
src.position(srcPos + n);
|
|
||||||
#if[char]
|
#if[char]
|
||||||
} else { // src.isAddressable() == false
|
} else { // src.isAddressable() == false
|
||||||
assert StringCharBuffer.class.isInstance(src);
|
assert StringCharBuffer.class.isInstance(src);
|
||||||
for (int i = 0; i < n; i++)
|
int posMax = pos + n;
|
||||||
put(src.get());
|
for (int i = pos, j = srcPos; i < posMax; i++, j++)
|
||||||
|
put(i, src.get(j));
|
||||||
}
|
}
|
||||||
#end[char]
|
#end[char]
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +49,7 @@ import org.testng.annotations.Test;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8245121
|
* @bug 8219014 8245121
|
||||||
* @summary Ensure that a bulk put of a buffer into another is correct.
|
* @summary Ensure that a bulk put of a buffer into another is correct.
|
||||||
* @compile --enable-preview -source ${jdk.version} BulkPutBuffer.java
|
* @compile --enable-preview -source ${jdk.version} BulkPutBuffer.java
|
||||||
* @run testng/othervm --enable-preview BulkPutBuffer
|
* @run testng/othervm --enable-preview BulkPutBuffer
|
||||||
@ -142,9 +142,11 @@ public class BulkPutBuffer {
|
|||||||
MethodHandle alloc;
|
MethodHandle alloc;
|
||||||
MethodHandle allocBB;
|
MethodHandle allocBB;
|
||||||
MethodHandle allocDirect;
|
MethodHandle allocDirect;
|
||||||
|
MethodHandle asReadOnlyBuffer;
|
||||||
MethodHandle asTypeBuffer;
|
MethodHandle asTypeBuffer;
|
||||||
MethodHandle putAbs;
|
MethodHandle putAbs;
|
||||||
MethodHandle getAbs;
|
MethodHandle getAbs;
|
||||||
|
MethodHandle putBufAbs;
|
||||||
MethodHandle putBufRel;
|
MethodHandle putBufRel;
|
||||||
MethodHandle equals;
|
MethodHandle equals;
|
||||||
|
|
||||||
@ -168,6 +170,9 @@ public class BulkPutBuffer {
|
|||||||
MethodType.methodType(ByteBuffer.class, int.class));
|
MethodType.methodType(ByteBuffer.class, int.class));
|
||||||
allocDirect = lookup.findStatic(ByteBuffer.class, "allocateDirect",
|
allocDirect = lookup.findStatic(ByteBuffer.class, "allocateDirect",
|
||||||
MethodType.methodType(ByteBuffer.class, int.class));
|
MethodType.methodType(ByteBuffer.class, int.class));
|
||||||
|
|
||||||
|
asReadOnlyBuffer = lookup.findVirtual(bufferType,
|
||||||
|
"asReadOnlyBuffer", MethodType.methodType(bufferType));
|
||||||
if (elementType != byte.class) {
|
if (elementType != byte.class) {
|
||||||
asTypeBuffer = lookup.findVirtual(ByteBuffer.class,
|
asTypeBuffer = lookup.findVirtual(ByteBuffer.class,
|
||||||
"as" + name + "Buffer", MethodType.methodType(bufferType));
|
"as" + name + "Buffer", MethodType.methodType(bufferType));
|
||||||
@ -177,8 +182,13 @@ public class BulkPutBuffer {
|
|||||||
MethodType.methodType(bufferType, int.class, elementType));
|
MethodType.methodType(bufferType, int.class, elementType));
|
||||||
getAbs = lookup.findVirtual(bufferType, "get",
|
getAbs = lookup.findVirtual(bufferType, "get",
|
||||||
MethodType.methodType(elementType, int.class));
|
MethodType.methodType(elementType, int.class));
|
||||||
|
|
||||||
|
putBufAbs = lookup.findVirtual(bufferType, "put",
|
||||||
|
MethodType.methodType(bufferType, int.class, bufferType,
|
||||||
|
int.class, int.class));
|
||||||
putBufRel = lookup.findVirtual(bufferType, "put",
|
putBufRel = lookup.findVirtual(bufferType, "put",
|
||||||
MethodType.methodType(bufferType, bufferType));
|
MethodType.methodType(bufferType, bufferType));
|
||||||
|
|
||||||
equals = lookup.findVirtual(bufferType, "equals",
|
equals = lookup.findVirtual(bufferType, "equals",
|
||||||
MethodType.methodType(boolean.class, Object.class));
|
MethodType.methodType(boolean.class, Object.class));
|
||||||
|
|
||||||
@ -239,6 +249,25 @@ public class BulkPutBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer asReadOnlyBuffer(Buffer buf) throws Throwable {
|
||||||
|
try {
|
||||||
|
return (Buffer)asReadOnlyBuffer.invoke(buf);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void put(Buffer src, int srcOff, Buffer dst, int dstOff, int length)
|
||||||
|
throws Throwable {
|
||||||
|
try {
|
||||||
|
putBufAbs.invoke(dst, dstOff, src, srcOff, length);
|
||||||
|
} catch (ReadOnlyBufferException ro) {
|
||||||
|
throw ro;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void put(Buffer src, Buffer dst) throws Throwable {
|
void put(Buffer src, Buffer dst) throws Throwable {
|
||||||
try {
|
try {
|
||||||
putBufRel.invoke(dst, src);
|
putBufRel.invoke(dst, src);
|
||||||
@ -294,6 +323,40 @@ public class BulkPutBuffer {
|
|||||||
return args.toArray(Object[][]::new);
|
return args.toArray(Object[][]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void expectThrows(Class<?> exClass, Assert.ThrowingRunnable r) {
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} catch(Throwable e) {
|
||||||
|
if (e.getClass() != exClass && e.getCause().getClass() != exClass) {
|
||||||
|
throw new RuntimeException("Expected " + exClass +
|
||||||
|
"; got " + e.getCause().getClass(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "proxies")
|
||||||
|
public static void testExceptions(BufferProxy bp) throws Throwable {
|
||||||
|
int cap = 27;
|
||||||
|
Buffer buf = bp.create(cap);
|
||||||
|
|
||||||
|
expectThrows(IndexOutOfBoundsException.class,
|
||||||
|
() -> bp.put(buf, -1, buf, 0, 1));
|
||||||
|
expectThrows(IndexOutOfBoundsException.class,
|
||||||
|
() -> bp.put(buf, 0, buf, -1, 1));
|
||||||
|
expectThrows(IndexOutOfBoundsException.class,
|
||||||
|
() -> bp.put(buf, 1, buf, 0, cap));
|
||||||
|
expectThrows(IndexOutOfBoundsException.class,
|
||||||
|
() -> bp.put(buf, 0, buf, 1, cap));
|
||||||
|
expectThrows(IndexOutOfBoundsException.class,
|
||||||
|
() -> bp.put(buf, 0, buf, 0, cap + 1));
|
||||||
|
expectThrows(IndexOutOfBoundsException.class,
|
||||||
|
() -> bp.put(buf, 0, buf, 0, Integer.MAX_VALUE));
|
||||||
|
|
||||||
|
Buffer rob = buf.isReadOnly() ? buf : bp.asReadOnlyBuffer(buf);
|
||||||
|
expectThrows(ReadOnlyBufferException.class,
|
||||||
|
() -> bp.put(buf, 0, rob, 0, cap));
|
||||||
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "proxies")
|
@Test(dataProvider = "proxies")
|
||||||
public static void testSelf(BufferProxy bp) throws Throwable {
|
public static void testSelf(BufferProxy bp) throws Throwable {
|
||||||
for (int i = 0; i < ITERATIONS; i++) {
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
@ -311,22 +374,27 @@ public class BulkPutBuffer {
|
|||||||
Assert.expectThrows(ReadOnlyBufferException.class,
|
Assert.expectThrows(ReadOnlyBufferException.class,
|
||||||
() -> bp.copy(lower, 0, lowerCopy, 0, lowerLength));
|
() -> bp.copy(lower, 0, lowerCopy, 0, lowerLength));
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
bp.copy(lower, 0, lowerCopy, 0, lowerLength);
|
|
||||||
}
|
}
|
||||||
|
bp.copy(lower, 0, lowerCopy, 0, lowerLength);
|
||||||
|
|
||||||
int middleOffset = RND.nextInt(1 + cap/2);
|
int middleOffset = RND.nextInt(1 + cap/2);
|
||||||
Buffer middle = buf.slice(middleOffset, lowerLength);
|
Buffer middle = buf.slice(middleOffset, lowerLength);
|
||||||
|
Buffer middleCopy = bp.create(lowerLength);
|
||||||
|
bp.copy(middle, 0, middleCopy, 0, lowerLength);
|
||||||
|
|
||||||
if (middle.isReadOnly()) {
|
bp.put(lower, middle);
|
||||||
Assert.expectThrows(ReadOnlyBufferException.class,
|
|
||||||
() -> bp.put(lower, middle));
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
bp.put(lower, middle);
|
|
||||||
}
|
|
||||||
middle.flip();
|
middle.flip();
|
||||||
|
|
||||||
|
Assert.assertTrue(bp.equals(lowerCopy, middle),
|
||||||
|
String.format("%d %s %d %d %d %d%n", SEED,
|
||||||
|
buf.getClass().getName(), cap,
|
||||||
|
lowerOffset, lowerLength, middleOffset));
|
||||||
|
|
||||||
|
bp.copy(lowerCopy, 0, buf, lowerOffset, lowerLength);
|
||||||
|
bp.copy(middleCopy, 0, buf, middleOffset, lowerLength);
|
||||||
|
|
||||||
|
bp.put(buf, lowerOffset, buf, middleOffset, lowerLength);
|
||||||
|
|
||||||
Assert.assertTrue(bp.equals(lowerCopy, middle),
|
Assert.assertTrue(bp.equals(lowerCopy, middle),
|
||||||
String.format("%d %s %d %d %d %d%n", SEED,
|
String.format("%d %s %d %d %d %d%n", SEED,
|
||||||
buf.getClass().getName(), cap,
|
buf.getClass().getName(), cap,
|
||||||
@ -361,13 +429,29 @@ public class BulkPutBuffer {
|
|||||||
Assert.expectThrows(ReadOnlyBufferException.class,
|
Assert.expectThrows(ReadOnlyBufferException.class,
|
||||||
() -> bp.put(src, buf));
|
() -> bp.put(src, buf));
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
bp.put(src, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer backup = bp.create(slim - spos);
|
||||||
|
bp.copy(buf, pos, backup, 0, backup.capacity());
|
||||||
|
bp.put(src, buf);
|
||||||
|
|
||||||
buf.reset();
|
buf.reset();
|
||||||
src.reset();
|
src.reset();
|
||||||
|
|
||||||
|
Assert.assertTrue(bp.equals(src, buf),
|
||||||
|
String.format("%d %s %d %d %d %s %d %d %d%n", SEED,
|
||||||
|
buf.getClass().getName(), cap, pos, lim,
|
||||||
|
src.getClass().getName(), scap, spos, slim));
|
||||||
|
|
||||||
|
src.clear();
|
||||||
|
buf.clear();
|
||||||
|
bp.copy(backup, 0, buf, pos, backup.capacity());
|
||||||
|
bp.put(src, spos, buf, pos, backup.capacity());
|
||||||
|
src.position(spos);
|
||||||
|
src.limit(slim);
|
||||||
|
buf.position(pos);
|
||||||
|
buf.limit(lim);
|
||||||
|
|
||||||
Assert.assertTrue(bp.equals(src, buf),
|
Assert.assertTrue(bp.equals(src, buf),
|
||||||
String.format("%d %s %d %d %d %s %d %d %d%n", SEED,
|
String.format("%d %s %d %d %d %s %d %d %d%n", SEED,
|
||||||
buf.getClass().getName(), cap, pos, lim,
|
buf.getClass().getName(), cap, pos, lim,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user