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.
|
* @return A new buffer with independent and exclusive ownership over the read and readable bytes from this buffer.
|
||||||
*/
|
*/
|
||||||
Buf bifurcate();
|
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.Arrays;
|
||||||
import java.util.Objects;
|
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 {
|
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}.
|
* 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.">
|
// <editor-fold defaultstate="collapsed" desc="Primitive accessors.">
|
||||||
@Override
|
@Override
|
||||||
public byte readByte() {
|
public byte readByte() {
|
||||||
|
@ -384,6 +384,29 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
return bifurcatedBuf;
|
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.">
|
// <editor-fold defaultstate="collapsed" desc="Primitive accessors implementation.">
|
||||||
@Override
|
@Override
|
||||||
public byte readByte() {
|
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.">
|
// <editor-fold defaultstate="collapsed" desc="Primitive accessors tests.">
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("allocators")
|
@MethodSource("allocators")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user