Add a Buffer.writeBytes bulk transfer method

This simplifies some of the ByteToMessageDecoder example code.
This commit is contained in:
Chris Vest 2021-04-26 10:34:54 +02:00
parent d72982a5ef
commit 8c2987a824
4 changed files with 69 additions and 10 deletions

View File

@ -377,6 +377,23 @@ public interface Buffer extends Rc<Buffer>, BufferAccessors {
*/
void copyInto(int srcPos, Buffer dest, int destPos, int length);
/**
* Write into this buffer, all the readable bytes from the given buffer.
* This updates the {@linkplain #writerOffset() write offset} of this buffer, and the
* {@linkplain #readerOffset() reader offset} of the given buffer.
*
* @param source The buffer to read from.
* @return This buffer.
*/
default Buffer writeBytes(Buffer source) {
int size = source.readableBytes();
int woff = writerOffset();
writerOffset(woff + size);
source.copyInto(source.readerOffset(), this, woff, size);
source.readerOffset(source.readerOffset() + size);
return this;
}
/**
* Resets the {@linkplain #readerOffset() read offset} and the {@linkplain #writerOffset() write offset} on this
* buffer to their initial values.

View File

@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
import static java.nio.ByteOrder.BIG_ENDIAN;
import static java.nio.ByteOrder.LITTLE_ENDIAN;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
public class BufferBulkAccessTest extends BufferTestSupport {
@ -301,4 +302,50 @@ public class BufferBulkAccessTest extends BufferTestSupport {
assertThat(buf.nativeAddress()).isNotZero();
}
}
@ParameterizedTest
@MethodSource("allocators")
public void writeBytesMustTransferDataAndUpdateOffsets(Fixture fixture) {
try (BufferAllocator alloc1 = fixture.createAllocator()) {
for (Fixture otherFixture : allocators()) {
try (BufferAllocator alloc2 = otherFixture.createAllocator();
Buffer target = alloc1.allocate(37);
Buffer source = alloc2.allocate(35)) {
// BE to BE
target.order(BIG_ENDIAN);
source.order(BIG_ENDIAN);
verifyWriteBytes(target, source);
// LE to BE
target.fill((byte) 0).reset().order(BIG_ENDIAN);
source.fill((byte) 0).reset().order(LITTLE_ENDIAN);
verifyWriteBytes(target, source);
// BE to LE
target.fill((byte) 0).reset().order(LITTLE_ENDIAN);
source.fill((byte) 0).reset().order(BIG_ENDIAN);
verifyWriteBytes(target, source);
// LE to LE
target.fill((byte) 0).reset().order(LITTLE_ENDIAN);
source.fill((byte) 0).reset().order(BIG_ENDIAN);
verifyWriteBytes(target, source);
}
}
}
}
private static void verifyWriteBytes(Buffer target, Buffer source) {
for (int i = 0; i < 35; i++) {
source.writeByte((byte) (i + 1));
}
target.writeBytes(source);
assertThat(target.readerOffset()).isZero();
assertThat(target.writerOffset()).isEqualTo(35);
assertThat(source.readerOffset()).isEqualTo(35);
assertThat(source.writerOffset()).isEqualTo(35);
try (Buffer readableSlice = target.slice()) {
assertEquals(source, readableSlice);
}
}
}

View File

@ -96,12 +96,10 @@ public abstract class AlternativeMessageDecoder extends ChannelHandlerAdapter {
try (Buffer prev = collector) {
int requiredCapacity = input.capacity() + prev.readableBytes();
collector = allocator.allocate(Math.max(requiredCapacity, DEFAULT_CHUNK_SIZE), input.order());
prev.copyInto(prev.readerOffset(), collector, 0, prev.readableBytes());
collector.readerOffset(prev.readableBytes());
collector.writeBytes(prev);
}
}
input.copyInto(input.readerOffset(), collector, collector.writerOffset(), input.readableBytes());
collector.writerOffset(collector.writerOffset() + input.readableBytes());
collector.writeBytes(input);
drainCollector(ctx);
}

View File

@ -110,9 +110,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
// assumed to be shared (e.g. refCnt() > 1) and the reallocation may not be safe.
return expandCumulation(alloc, cumulation, in);
}
in.copyInto(in.readerOffset(), cumulation, cumulation.writerOffset(), required);
cumulation.writerOffset(cumulation.writerOffset() + required);
in.readerOffset(in.writerOffset());
cumulation.writeBytes(in);
return cumulation;
}
};
@ -480,9 +478,8 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
Buffer newCumulation = alloc.allocate(newSize, oldCumulation.order());
Buffer toRelease = newCumulation;
try {
oldCumulation.copyInto(oldCumulation.readerOffset(), newCumulation, 0, oldCumulation.readableBytes());
in.copyInto(in.readerOffset(), newCumulation, oldCumulation.readableBytes(), in.readableBytes());
newCumulation.writerOffset(oldCumulation.readableBytes() + in.readableBytes());
newCumulation.writeBytes(oldCumulation);
newCumulation.writeBytes(in);
toRelease = oldCumulation;
return newCumulation;
} finally {