Add a Buf.compact method
Motivation: Compaction makes more space available at the end of a buffer, by discarding bytes at the beginning that have already been processed. Modification: Add a copying compact method to Buf. Result: It is now possible to discard read bytes by calling `compact()`.
This commit is contained in:
parent
cc685c0516
commit
0f303c7971
@ -417,4 +417,11 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
||||
* @return A new buffer with independent and exclusive ownership over the read and readable bytes from this buffer.
|
||||
*/
|
||||
Buf bifurcate();
|
||||
|
||||
/**
|
||||
* Discards the read bytes, and moves the buffer contents to the beginning of the buffer.
|
||||
*
|
||||
* The buffer must be {@linkplain #isOwned() owned}, or an exception will be thrown.
|
||||
*/
|
||||
void compact();
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static jdk.incubator.foreign.MemoryAccess.setByteAtOffset;
|
||||
import static jdk.incubator.foreign.MemoryAccess.setLongAtOffset;
|
||||
|
||||
final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
||||
/**
|
||||
* The max array size is JVM implementation dependant, but most seem to settle on {@code Integer.MAX_VALUE - 8}.
|
||||
@ -600,6 +603,35 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compact() {
|
||||
if (!isOwned()) {
|
||||
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
||||
}
|
||||
int distance = roff;
|
||||
if (distance == 0) {
|
||||
return;
|
||||
}
|
||||
int pos = 0;
|
||||
var oldOrder = order;
|
||||
order = ByteOrder.BIG_ENDIAN;
|
||||
try {
|
||||
var cursor = openCursor();
|
||||
while (cursor.readLong()) {
|
||||
setLong(pos, cursor.getLong());
|
||||
pos += Long.BYTES;
|
||||
}
|
||||
while (cursor.readByte()) {
|
||||
setByte(pos, cursor.getByte());
|
||||
pos++;
|
||||
}
|
||||
} finally {
|
||||
order = oldOrder;
|
||||
}
|
||||
readerOffset(0);
|
||||
writerOffset(woff - distance);
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Primitive accessors.">
|
||||
@Override
|
||||
public byte readByte() {
|
||||
|
@ -384,6 +384,29 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
||||
return bifurcatedBuf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compact() {
|
||||
if (!isOwned()) {
|
||||
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
||||
}
|
||||
int distance = roff;
|
||||
if (distance == 0) {
|
||||
return;
|
||||
}
|
||||
int pos = 0;
|
||||
var cursor = openCursor();
|
||||
while (cursor.readLong()) {
|
||||
setLongAtOffset(seg, pos, ByteOrder.BIG_ENDIAN, cursor.getLong());
|
||||
pos += Long.BYTES;
|
||||
}
|
||||
while (cursor.readByte()) {
|
||||
setByteAtOffset(seg, pos, cursor.getByte());
|
||||
pos++;
|
||||
}
|
||||
roff -= distance;
|
||||
woff -= distance;
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Primitive accessors implementation.">
|
||||
@Override
|
||||
public byte readByte() {
|
||||
|
@ -2195,6 +2195,43 @@ public class BufTest {
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonSliceAllocators")
|
||||
public void compactMustDiscardReadBytes(Fixture fixture) {
|
||||
try (Allocator allocator = fixture.createAllocator();
|
||||
Buf buf = allocator.allocate(16, ByteOrder.BIG_ENDIAN)) {
|
||||
buf.writeLong(0x0102030405060708L).writeInt(0x090A0B0C);
|
||||
assertEquals(0x01020304, buf.readInt());
|
||||
assertEquals(12, buf.writerOffset());
|
||||
assertEquals(4, buf.readerOffset());
|
||||
assertEquals(4, buf.writableBytes());
|
||||
assertEquals(8, buf.readableBytes());
|
||||
assertEquals(16, buf.capacity());
|
||||
buf.compact();
|
||||
assertEquals(8, buf.writerOffset());
|
||||
assertEquals(0, buf.readerOffset());
|
||||
assertEquals(8, buf.writableBytes());
|
||||
assertEquals(8, buf.readableBytes());
|
||||
assertEquals(16, buf.capacity());
|
||||
assertEquals(0x05060708090A0B0CL, buf.readLong());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonSliceAllocators")
|
||||
public void compactMustThrowForUnownedBuffer(Fixture fixture) {
|
||||
try (Allocator allocator = fixture.createAllocator();
|
||||
Buf buf = allocator.allocate(8, ByteOrder.BIG_ENDIAN)) {
|
||||
buf.writeLong(0x0102030405060708L);
|
||||
assertEquals((byte) 0x01, buf.readByte());
|
||||
try (Buf ignore = buf.acquire()) {
|
||||
assertThrows(IllegalStateException.class, () -> buf.compact());
|
||||
assertEquals(1, buf.readerOffset());
|
||||
}
|
||||
assertEquals((byte) 0x02, buf.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Primitive accessors tests.">
|
||||
@ParameterizedTest
|
||||
@MethodSource("allocators")
|
||||
|
Loading…
Reference in New Issue
Block a user