Merge pull request #23 from netty/read-only
Add support for read-only buffers
This commit is contained in:
commit
8cdcfd53c9
@ -70,7 +70,7 @@ public interface Allocator extends AutoCloseable {
|
|||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* try (Buf a = allocator.allocate(size);
|
* try (Buf a = allocator.allocate(size);
|
||||||
* Buf b = allocator.allocate(size)) {
|
* Buf b = allocator.allocate(size)) {
|
||||||
* return Buf.compose(a, b); // Reference counts for 'a' and 'b' incremented here.
|
* return allocator.compose(a, b); // Reference counts for 'a' and 'b' incremented here.
|
||||||
* } // Reference count for 'a' and 'b' decremented here; composite buffer now holds the last references.
|
* } // Reference count for 'a' and 'b' decremented here; composite buffer now holds the last references.
|
||||||
* }</pre>
|
* }</pre>
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -154,6 +154,7 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
|||||||
* @return This Buf.
|
* @return This Buf.
|
||||||
* @throws IndexOutOfBoundsException if the specified {@code offset} is less than the current
|
* @throws IndexOutOfBoundsException if the specified {@code offset} is less than the current
|
||||||
* {@link #readerOffset()} or greater than {@link #capacity()}.
|
* {@link #readerOffset()} or greater than {@link #capacity()}.
|
||||||
|
* @throws IllegalStateException if this buffer is {@linkplain #readOnly() read-only}.
|
||||||
*/
|
*/
|
||||||
Buf writerOffset(int offset);
|
Buf writerOffset(int offset);
|
||||||
|
|
||||||
@ -178,6 +179,7 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
|||||||
*
|
*
|
||||||
* @param value The byte value to write at every position in the buffer.
|
* @param value The byte value to write at every position in the buffer.
|
||||||
* @return This Buf.
|
* @return This Buf.
|
||||||
|
* @throws IllegalStateException if this buffer is {@linkplain #readOnly() read-only}.
|
||||||
*/
|
*/
|
||||||
Buf fill(byte value);
|
Buf fill(byte value);
|
||||||
|
|
||||||
@ -187,6 +189,20 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
|||||||
*/
|
*/
|
||||||
long getNativeAddress();
|
long getNativeAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the read-only state of this buffer.
|
||||||
|
*
|
||||||
|
* @return this buffer.
|
||||||
|
*/
|
||||||
|
Buf readOnly(boolean readOnly);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query if this buffer is read-only or not.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this buffer is read-only, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
boolean readOnly();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a slice of this buffer's readable bytes.
|
* Returns a slice of this buffer's readable bytes.
|
||||||
* Modifying the content of the returned buffer or this buffer affects each other's content,
|
* Modifying the content of the returned buffer or this buffer affects each other's content,
|
||||||
@ -371,8 +387,8 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
|||||||
* {@code false}.
|
* {@code false}.
|
||||||
*
|
*
|
||||||
* @param size The requested number of bytes of space that should be available for writing.
|
* @param size The requested number of bytes of space that should be available for writing.
|
||||||
* @throws IllegalStateException if this buffer is not in an owned state.
|
* @throws IllegalStateException if this buffer is not in an {@linkplain #isOwned() owned} state,
|
||||||
* That is, if {@link #isOwned()} is {@code false}.
|
* or is {@linkplain #readOnly() read-only}.
|
||||||
*/
|
*/
|
||||||
default void ensureWritable(int size) {
|
default void ensureWritable(int size) {
|
||||||
ensureWritable(size, true);
|
ensureWritable(size, true);
|
||||||
@ -410,8 +426,8 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
|||||||
* @param allowCompaction {@code true} if the method is allowed to modify the
|
* @param allowCompaction {@code true} if the method is allowed to modify the
|
||||||
* {@linkplain #readerOffset() reader offset} and
|
* {@linkplain #readerOffset() reader offset} and
|
||||||
* {@linkplain #writerOffset() writer offset}, otherwise {@code false}.
|
* {@linkplain #writerOffset() writer offset}, otherwise {@code false}.
|
||||||
* @throws IllegalStateException if this buffer is not in an owned state.
|
* @throws IllegalStateException if this buffer is not in an {@linkplain #isOwned() owned} state,
|
||||||
* That is, if {@link #isOwned()} is {@code false}.
|
* * or is {@linkplain #readOnly() read-only}.
|
||||||
*/
|
*/
|
||||||
void ensureWritable(int size, boolean allowCompaction);
|
void ensureWritable(int size, boolean allowCompaction);
|
||||||
|
|
||||||
@ -462,7 +478,8 @@ public interface Buf extends Rc<Buf>, BufAccessors {
|
|||||||
/**
|
/**
|
||||||
* Discards the read bytes, and moves the buffer contents to the beginning of the buffer.
|
* 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.
|
* @throws IllegalStateException if this buffer is not in an {@linkplain #isOwned() owned} state,
|
||||||
|
* or is {@linkplain #readOnly() read-only}.
|
||||||
*/
|
*/
|
||||||
void compact();
|
void compact();
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,6 @@ 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}.
|
||||||
@ -48,6 +45,7 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
private int subOffset; // The next offset *within* a consituent buffer to read from or write to.
|
private int subOffset; // The next offset *within* a consituent buffer to read from or write to.
|
||||||
private ByteOrder order;
|
private ByteOrder order;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
private boolean readOnly;
|
||||||
|
|
||||||
CompositeBuf(Allocator allocator, Buf[] bufs) {
|
CompositeBuf(Allocator allocator, Buf[] bufs) {
|
||||||
this(allocator, true, bufs.clone(), COMPOSITE_DROP); // Clone prevents external modification of array.
|
this(allocator, true, bufs.clone(), COMPOSITE_DROP); // Clone prevents external modification of array.
|
||||||
@ -68,6 +66,14 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
order = bufs[0].order();
|
order = bufs[0].order();
|
||||||
|
|
||||||
|
boolean targetReadOnly = bufs[0].readOnly();
|
||||||
|
for (Buf buf : bufs) {
|
||||||
|
if (buf.readOnly() != targetReadOnly) {
|
||||||
|
throw new IllegalArgumentException("Constituent buffers have inconsistent read-only state.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readOnly = targetReadOnly;
|
||||||
} else {
|
} else {
|
||||||
order = ByteOrder.nativeOrder();
|
order = ByteOrder.nativeOrder();
|
||||||
}
|
}
|
||||||
@ -201,6 +207,20 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Buf readOnly(boolean readOnly) {
|
||||||
|
for (Buf buf : bufs) {
|
||||||
|
buf.readOnly(readOnly);
|
||||||
|
}
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readOnly() {
|
||||||
|
return readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buf slice(int offset, int length) {
|
public Buf slice(int offset, int length) {
|
||||||
checkWriteBounds(offset, length);
|
checkWriteBounds(offset, length);
|
||||||
@ -236,7 +256,7 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
slices = new Buf[] { choice.slice(subOffset, 0) };
|
slices = new Buf[] { choice.slice(subOffset, 0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CompositeBuf(allocator, false, slices, drop).writerOffset(length);
|
return new CompositeBuf(allocator, false, slices, drop);
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
// We called acquire prior to the try-clause. We need to undo that if we're not creating a composite buffer:
|
// We called acquire prior to the try-clause. We need to undo that if we're not creating a composite buffer:
|
||||||
close();
|
close();
|
||||||
@ -267,10 +287,10 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
|
throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
|
||||||
}
|
}
|
||||||
if (srcPos < 0) {
|
if (srcPos < 0) {
|
||||||
throw indexOutOfBounds(srcPos);
|
throw indexOutOfBounds(srcPos, false);
|
||||||
}
|
}
|
||||||
if (srcPos + length > capacity) {
|
if (srcPos + length > capacity) {
|
||||||
throw indexOutOfBounds(srcPos + length);
|
throw indexOutOfBounds(srcPos + length, false);
|
||||||
}
|
}
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
var buf = (Buf) chooseBuffer(srcPos, 0);
|
var buf = (Buf) chooseBuffer(srcPos, 0);
|
||||||
@ -293,10 +313,10 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
|
throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
|
||||||
}
|
}
|
||||||
if (srcPos < 0) {
|
if (srcPos < 0) {
|
||||||
throw indexOutOfBounds(srcPos);
|
throw indexOutOfBounds(srcPos, false);
|
||||||
}
|
}
|
||||||
if (srcPos + length > capacity) {
|
if (srcPos + length > capacity) {
|
||||||
throw indexOutOfBounds(srcPos + length);
|
throw indexOutOfBounds(srcPos + length, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate in reverse to account for src and dest buffer overlap.
|
// Iterate in reverse to account for src and dest buffer overlap.
|
||||||
@ -530,6 +550,9 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
||||||
}
|
}
|
||||||
|
if (readOnly) {
|
||||||
|
throw bufferIsReadOnly();
|
||||||
|
}
|
||||||
if (writableBytes() >= size) {
|
if (writableBytes() >= size) {
|
||||||
// We already have enough space.
|
// We already have enough space.
|
||||||
return;
|
return;
|
||||||
@ -586,15 +609,23 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
"This buffer uses " + order() + " byte order, and cannot be extended with " +
|
"This buffer uses " + order() + " byte order, and cannot be extended with " +
|
||||||
"a buffer that uses " + extension.order() + " byte order.");
|
"a buffer that uses " + extension.order() + " byte order.");
|
||||||
}
|
}
|
||||||
if (bufs.length == 0) {
|
if (bufs.length > 0 && extension.readOnly() != readOnly()) {
|
||||||
order = extension.order();
|
throw new IllegalArgumentException(
|
||||||
|
"This buffer is " + (readOnly? "read-only" : "writable") + ", " +
|
||||||
|
"and cannot be extended with a buffer that is " +
|
||||||
|
(extension.readOnly()? "read-only." : "writable."));
|
||||||
}
|
}
|
||||||
|
|
||||||
long newSize = capacity() + (long) extension.capacity();
|
long newSize = capacity() + (long) extension.capacity();
|
||||||
Allocator.checkSize(newSize);
|
Allocator.checkSize(newSize);
|
||||||
|
|
||||||
Buf[] restoreTemp = bufs; // We need this to restore our buffer array, in case offset computations fail.
|
Buf[] restoreTemp = bufs; // We need this to restore our buffer array, in case offset computations fail.
|
||||||
try {
|
try {
|
||||||
unsafeExtendWith(extension.acquire());
|
unsafeExtendWith(extension.acquire());
|
||||||
|
if (restoreTemp.length == 0) {
|
||||||
|
order = extension.order();
|
||||||
|
readOnly = extension.readOnly();
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
bufs = restoreTemp;
|
bufs = restoreTemp;
|
||||||
throw e;
|
throw e;
|
||||||
@ -642,6 +673,9 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
if (!isOwned()) {
|
if (!isOwned()) {
|
||||||
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
||||||
}
|
}
|
||||||
|
if (readOnly()) {
|
||||||
|
throw new IllegalStateException("Buffer must be writable in order to compact, but was read-only.");
|
||||||
|
}
|
||||||
int distance = roff;
|
int distance = roff;
|
||||||
if (distance == 0) {
|
if (distance == 0) {
|
||||||
return;
|
return;
|
||||||
@ -962,6 +996,7 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
received[i] = sends[i].receive();
|
received[i] = sends[i].receive();
|
||||||
}
|
}
|
||||||
var composite = new CompositeBuf(allocator, true, received, drop);
|
var composite = new CompositeBuf(allocator, true, received, drop);
|
||||||
|
composite.readOnly = readOnly;
|
||||||
drop.attach(composite);
|
drop.attach(composite);
|
||||||
return composite;
|
return composite;
|
||||||
}
|
}
|
||||||
@ -1034,7 +1069,7 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
|
|
||||||
private void checkReadBounds(int index, int size) {
|
private void checkReadBounds(int index, int size) {
|
||||||
if (index < 0 || woff < index + size) {
|
if (index < 0 || woff < index + size) {
|
||||||
throw indexOutOfBounds(index);
|
throw indexOutOfBounds(index, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1051,19 +1086,30 @@ final class CompositeBuf extends RcSupport<Buf, CompositeBuf> implements Buf {
|
|||||||
|
|
||||||
private void checkWriteBounds(int index, int size) {
|
private void checkWriteBounds(int index, int size) {
|
||||||
if (index < 0 || capacity < index + size) {
|
if (index < 0 || capacity < index + size) {
|
||||||
throw indexOutOfBounds(index);
|
throw indexOutOfBounds(index, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RuntimeException indexOutOfBounds(int index) {
|
private RuntimeException indexOutOfBounds(int index, boolean write) {
|
||||||
if (closed) {
|
if (closed) {
|
||||||
return new IllegalStateException("This buffer is closed.");
|
return bufferIsClosed();
|
||||||
|
}
|
||||||
|
if (write && readOnly) {
|
||||||
|
return bufferIsReadOnly();
|
||||||
}
|
}
|
||||||
return new IndexOutOfBoundsException(
|
return new IndexOutOfBoundsException(
|
||||||
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
||||||
(capacity - 1) + "].");
|
(capacity - 1) + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IllegalStateException bufferIsClosed() {
|
||||||
|
return new IllegalStateException("This buffer is closed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IllegalStateException bufferIsReadOnly() {
|
||||||
|
return new IllegalStateException("This buffer is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
private BufAccessors chooseBuffer(int index, int size) {
|
private BufAccessors chooseBuffer(int index, int size) {
|
||||||
int i = searchOffsets(index);
|
int i = searchOffsets(index);
|
||||||
if (i == bufs.length) {
|
if (i == bufs.length) {
|
||||||
|
@ -43,7 +43,11 @@ class SizeClassedMemoryPool implements Allocator, AllocatorControl, Drop<Buf> {
|
|||||||
var sizeClassPool = getSizeClassPool(size);
|
var sizeClassPool = getSizeClassPool(size);
|
||||||
Send<Buf> send = sizeClassPool.poll();
|
Send<Buf> send = sizeClassPool.poll();
|
||||||
if (send != null) {
|
if (send != null) {
|
||||||
return send.receive().reset().fill((byte) 0).order(ByteOrder.nativeOrder());
|
return send.receive()
|
||||||
|
.reset()
|
||||||
|
.readOnly(false)
|
||||||
|
.fill((byte) 0)
|
||||||
|
.order(ByteOrder.nativeOrder());
|
||||||
}
|
}
|
||||||
return createBuf(size, getDrop());
|
return createBuf(size, getDrop());
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
private final AllocatorControl alloc;
|
private final AllocatorControl alloc;
|
||||||
private final boolean isSendable;
|
private final boolean isSendable;
|
||||||
private MemorySegment seg;
|
private MemorySegment seg;
|
||||||
|
private MemorySegment wseg;
|
||||||
private ByteOrder order;
|
private ByteOrder order;
|
||||||
private int roff;
|
private int roff;
|
||||||
private int woff;
|
private int woff;
|
||||||
@ -71,6 +72,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
super(drop);
|
super(drop);
|
||||||
this.alloc = alloc;
|
this.alloc = alloc;
|
||||||
seg = segment;
|
seg = segment;
|
||||||
|
wseg = segment;
|
||||||
this.isSendable = isSendable;
|
this.isSendable = isSendable;
|
||||||
order = ByteOrder.nativeOrder();
|
order = ByteOrder.nativeOrder();
|
||||||
}
|
}
|
||||||
@ -122,6 +124,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buf fill(byte value) {
|
public Buf fill(byte value) {
|
||||||
|
checkWrite(0, capacity());
|
||||||
seg.fill(value);
|
seg.fill(value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -135,6 +138,17 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Buf readOnly(boolean readOnly) {
|
||||||
|
wseg = readOnly? CLOSED_SEGMENT : seg;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readOnly() {
|
||||||
|
return wseg == CLOSED_SEGMENT && seg != CLOSED_SEGMENT;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buf slice(int offset, int length) {
|
public Buf slice(int offset, int length) {
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
@ -147,7 +161,10 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
b.makeInaccessible();
|
b.makeInaccessible();
|
||||||
};
|
};
|
||||||
var sendable = false; // Sending implies ownership change, which we can't do for slices.
|
var sendable = false; // Sending implies ownership change, which we can't do for slices.
|
||||||
return new MemSegBuf(slice, drop, alloc, sendable).writerOffset(length).order(order());
|
return new MemSegBuf(slice, drop, alloc, sendable)
|
||||||
|
.writerOffset(length)
|
||||||
|
.order(order())
|
||||||
|
.readOnly(readOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -165,12 +182,31 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void copyInto(int srcPos, MemorySegment dest, int destPos, int length) {
|
private void copyInto(int srcPos, MemorySegment dest, int destPos, int length) {
|
||||||
|
if (seg == CLOSED_SEGMENT) {
|
||||||
|
throw bufferIsClosed();
|
||||||
|
}
|
||||||
|
if (srcPos < 0) {
|
||||||
|
throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.');
|
||||||
|
}
|
||||||
|
if (length < 0) {
|
||||||
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
||||||
|
}
|
||||||
|
if (seg.byteSize() < srcPos + length) {
|
||||||
|
throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " +
|
||||||
|
"srcPos = " + srcPos + ", length = " + length + '.');
|
||||||
|
}
|
||||||
dest.asSlice(destPos, length).copyFrom(seg.asSlice(srcPos, length));
|
dest.asSlice(destPos, length).copyFrom(seg.asSlice(srcPos, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyInto(int srcPos, Buf dest, int destPos, int length) {
|
public void copyInto(int srcPos, Buf dest, int destPos, int length) {
|
||||||
// todo optimise: specialise for MemSegBuf.
|
if (dest instanceof MemSegBuf) {
|
||||||
|
var memSegBuf = (MemSegBuf) dest;
|
||||||
|
memSegBuf.checkWrite(destPos, length);
|
||||||
|
copyInto(srcPos, memSegBuf.seg, destPos, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate in reverse to account for src and dest buffer overlap.
|
// Iterate in reverse to account for src and dest buffer overlap.
|
||||||
var itr = openReverseCursor(srcPos + length - 1, length);
|
var itr = openReverseCursor(srcPos + length - 1, length);
|
||||||
ByteOrder prevOrder = dest.order();
|
ByteOrder prevOrder = dest.order();
|
||||||
@ -202,8 +238,8 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
||||||
}
|
}
|
||||||
if (seg.byteSize() < fromOffset + length) {
|
if (seg.byteSize() < fromOffset + length) {
|
||||||
throw new IllegalArgumentException("The fromOffset+length is beyond the end of the buffer: " +
|
throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " +
|
||||||
"fromOffset=" + fromOffset + ", length=" + length + '.');
|
"fromOffset = " + fromOffset + ", length = " + length + '.');
|
||||||
}
|
}
|
||||||
return new ByteCursor() {
|
return new ByteCursor() {
|
||||||
final MemorySegment segment = seg;
|
final MemorySegment segment = seg;
|
||||||
@ -269,8 +305,8 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
|
throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
|
||||||
}
|
}
|
||||||
if (fromOffset - length < -1) {
|
if (fromOffset - length < -1) {
|
||||||
throw new IllegalArgumentException("The fromOffset-length would underflow the buffer: " +
|
throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " +
|
||||||
"fromOffset=" + fromOffset + ", length=" + length + '.');
|
"fromOffset = " + fromOffset + ", length = " + length + '.');
|
||||||
}
|
}
|
||||||
return new ByteCursor() {
|
return new ByteCursor() {
|
||||||
final MemorySegment segment = seg;
|
final MemorySegment segment = seg;
|
||||||
@ -330,6 +366,9 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
||||||
}
|
}
|
||||||
|
if (seg != wseg) {
|
||||||
|
throw bufferIsReadOnly();
|
||||||
|
}
|
||||||
if (writableBytes() >= size) {
|
if (writableBytes() >= size) {
|
||||||
// We already have enough space.
|
// We already have enough space.
|
||||||
return;
|
return;
|
||||||
@ -366,6 +405,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg = newSegment;
|
seg = newSegment;
|
||||||
|
wseg = newSegment;
|
||||||
drop.attach(this);
|
drop.attach(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +430,12 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
bifurcatedBuf.woff = woff;
|
bifurcatedBuf.woff = woff;
|
||||||
bifurcatedBuf.roff = roff;
|
bifurcatedBuf.roff = roff;
|
||||||
bifurcatedBuf.order(order);
|
bifurcatedBuf.order(order);
|
||||||
|
boolean readOnly = readOnly();
|
||||||
|
bifurcatedBuf.readOnly(readOnly);
|
||||||
seg = seg.asSlice(woff, seg.byteSize() - woff);
|
seg = seg.asSlice(woff, seg.byteSize() - woff);
|
||||||
|
if (!readOnly) {
|
||||||
|
wseg = seg;
|
||||||
|
}
|
||||||
woff = 0;
|
woff = 0;
|
||||||
roff = 0;
|
roff = 0;
|
||||||
return bifurcatedBuf;
|
return bifurcatedBuf;
|
||||||
@ -401,6 +446,9 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
if (!isOwned()) {
|
if (!isOwned()) {
|
||||||
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
||||||
}
|
}
|
||||||
|
if (readOnly()) {
|
||||||
|
throw new IllegalStateException("Buffer must be writable in order to compact, but was read-only.");
|
||||||
|
}
|
||||||
int distance = roff;
|
int distance = roff;
|
||||||
if (distance == 0) {
|
if (distance == 0) {
|
||||||
return;
|
return;
|
||||||
@ -442,7 +490,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeByte(byte value) {
|
public Buf writeByte(byte value) {
|
||||||
try {
|
try {
|
||||||
setByteAtOffset(seg, woff, value);
|
setByteAtOffset(wseg, woff, value);
|
||||||
woff += Byte.BYTES;
|
woff += Byte.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -453,7 +501,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setByte(int woff, byte value) {
|
public Buf setByte(int woff, byte value) {
|
||||||
try {
|
try {
|
||||||
setByteAtOffset(seg, woff, value);
|
setByteAtOffset(wseg, woff, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -463,7 +511,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeUnsignedByte(int value) {
|
public Buf writeUnsignedByte(int value) {
|
||||||
try {
|
try {
|
||||||
setByteAtOffset(seg, woff, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
||||||
woff += Byte.BYTES;
|
woff += Byte.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -474,7 +522,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setUnsignedByte(int woff, int value) {
|
public Buf setUnsignedByte(int woff, int value) {
|
||||||
try {
|
try {
|
||||||
setByteAtOffset(seg, woff, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -498,7 +546,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeChar(char value) {
|
public Buf writeChar(char value) {
|
||||||
try {
|
try {
|
||||||
setCharAtOffset(seg, woff, order, value);
|
setCharAtOffset(wseg, woff, order, value);
|
||||||
woff += 2;
|
woff += 2;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -509,7 +557,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setChar(int woff, char value) {
|
public Buf setChar(int woff, char value) {
|
||||||
try {
|
try {
|
||||||
setCharAtOffset(seg, woff, order, value);
|
setCharAtOffset(wseg, woff, order, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -547,7 +595,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeShort(short value) {
|
public Buf writeShort(short value) {
|
||||||
try {
|
try {
|
||||||
setShortAtOffset(seg, woff, order, value);
|
setShortAtOffset(wseg, woff, order, value);
|
||||||
woff += Short.BYTES;
|
woff += Short.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -558,7 +606,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setShort(int woff, short value) {
|
public Buf setShort(int woff, short value) {
|
||||||
try {
|
try {
|
||||||
setShortAtOffset(seg, woff, order, value);
|
setShortAtOffset(wseg, woff, order, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -568,7 +616,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeUnsignedShort(int value) {
|
public Buf writeUnsignedShort(int value) {
|
||||||
try {
|
try {
|
||||||
setShortAtOffset(seg, woff, order, (short) (value & 0xFFFF));
|
setShortAtOffset(wseg, woff, order, (short) (value & 0xFFFF));
|
||||||
woff += Short.BYTES;
|
woff += Short.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -579,7 +627,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setUnsignedShort(int woff, int value) {
|
public Buf setUnsignedShort(int woff, int value) {
|
||||||
try {
|
try {
|
||||||
setShortAtOffset(seg, woff, order, (short) (value & 0xFFFF));
|
setShortAtOffset(wseg, woff, order, (short) (value & 0xFFFF));
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -642,13 +690,13 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
public Buf writeMedium(int value) {
|
public Buf writeMedium(int value) {
|
||||||
checkWrite(woff, 3);
|
checkWrite(woff, 3);
|
||||||
if (order == ByteOrder.BIG_ENDIAN) {
|
if (order == ByteOrder.BIG_ENDIAN) {
|
||||||
setByteAtOffset(seg, woff, (byte) (value >> 16));
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
||||||
} else {
|
} else {
|
||||||
setByteAtOffset(seg, woff, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value >> 16 & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
||||||
}
|
}
|
||||||
woff += 3;
|
woff += 3;
|
||||||
return this;
|
return this;
|
||||||
@ -658,13 +706,13 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
public Buf setMedium(int woff, int value) {
|
public Buf setMedium(int woff, int value) {
|
||||||
checkWrite(woff, 3);
|
checkWrite(woff, 3);
|
||||||
if (order == ByteOrder.BIG_ENDIAN) {
|
if (order == ByteOrder.BIG_ENDIAN) {
|
||||||
setByteAtOffset(seg, woff, (byte) (value >> 16));
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
||||||
} else {
|
} else {
|
||||||
setByteAtOffset(seg, woff, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value >> 16 & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -673,13 +721,13 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
public Buf writeUnsignedMedium(int value) {
|
public Buf writeUnsignedMedium(int value) {
|
||||||
checkWrite(woff, 3);
|
checkWrite(woff, 3);
|
||||||
if (order == ByteOrder.BIG_ENDIAN) {
|
if (order == ByteOrder.BIG_ENDIAN) {
|
||||||
setByteAtOffset(seg, woff, (byte) (value >> 16));
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
||||||
} else {
|
} else {
|
||||||
setByteAtOffset(seg, woff, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value >> 16 & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
||||||
}
|
}
|
||||||
woff += 3;
|
woff += 3;
|
||||||
return this;
|
return this;
|
||||||
@ -689,13 +737,13 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
public Buf setUnsignedMedium(int woff, int value) {
|
public Buf setUnsignedMedium(int woff, int value) {
|
||||||
checkWrite(woff, 3);
|
checkWrite(woff, 3);
|
||||||
if (order == ByteOrder.BIG_ENDIAN) {
|
if (order == ByteOrder.BIG_ENDIAN) {
|
||||||
setByteAtOffset(seg, woff, (byte) (value >> 16));
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
||||||
} else {
|
} else {
|
||||||
setByteAtOffset(seg, woff, (byte) (value & 0xFF));
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
setByteAtOffset(seg, woff + 2, (byte) (value >> 16 & 0xFF));
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -731,7 +779,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeInt(int value) {
|
public Buf writeInt(int value) {
|
||||||
try {
|
try {
|
||||||
setIntAtOffset(seg, woff, order, value);
|
setIntAtOffset(wseg, woff, order, value);
|
||||||
woff += Integer.BYTES;
|
woff += Integer.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -742,7 +790,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setInt(int woff, int value) {
|
public Buf setInt(int woff, int value) {
|
||||||
try {
|
try {
|
||||||
setIntAtOffset(seg, woff, order, value);
|
setIntAtOffset(wseg, woff, order, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -752,7 +800,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeUnsignedInt(long value) {
|
public Buf writeUnsignedInt(long value) {
|
||||||
try {
|
try {
|
||||||
setIntAtOffset(seg, woff, order, (int) (value & 0xFFFFFFFFL));
|
setIntAtOffset(wseg, woff, order, (int) (value & 0xFFFFFFFFL));
|
||||||
woff += Integer.BYTES;
|
woff += Integer.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -763,7 +811,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setUnsignedInt(int woff, long value) {
|
public Buf setUnsignedInt(int woff, long value) {
|
||||||
try {
|
try {
|
||||||
setIntAtOffset(seg, woff, order, (int) (value & 0xFFFFFFFFL));
|
setIntAtOffset(wseg, woff, order, (int) (value & 0xFFFFFFFFL));
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -787,7 +835,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeFloat(float value) {
|
public Buf writeFloat(float value) {
|
||||||
try {
|
try {
|
||||||
setFloatAtOffset(seg, woff, order, value);
|
setFloatAtOffset(wseg, woff, order, value);
|
||||||
woff += Float.BYTES;
|
woff += Float.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -798,7 +846,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setFloat(int woff, float value) {
|
public Buf setFloat(int woff, float value) {
|
||||||
try {
|
try {
|
||||||
setFloatAtOffset(seg, woff, order, value);
|
setFloatAtOffset(wseg, woff, order, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -822,7 +870,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeLong(long value) {
|
public Buf writeLong(long value) {
|
||||||
try {
|
try {
|
||||||
setLongAtOffset(seg, woff, order, value);
|
setLongAtOffset(wseg, woff, order, value);
|
||||||
woff += Long.BYTES;
|
woff += Long.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -833,7 +881,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setLong(int woff, long value) {
|
public Buf setLong(int woff, long value) {
|
||||||
try {
|
try {
|
||||||
setLongAtOffset(seg, woff, order, value);
|
setLongAtOffset(wseg, woff, order, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -857,7 +905,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf writeDouble(double value) {
|
public Buf writeDouble(double value) {
|
||||||
try {
|
try {
|
||||||
setDoubleAtOffset(seg, woff, order, value);
|
setDoubleAtOffset(wseg, woff, order, value);
|
||||||
woff += Double.BYTES;
|
woff += Double.BYTES;
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
@ -868,7 +916,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
@Override
|
@Override
|
||||||
public Buf setDouble(int woff, double value) {
|
public Buf setDouble(int woff, double value) {
|
||||||
try {
|
try {
|
||||||
setDoubleAtOffset(seg, woff, order, value);
|
setDoubleAtOffset(wseg, woff, order, value);
|
||||||
return this;
|
return this;
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw checkWriteState(e);
|
throw checkWriteState(e);
|
||||||
@ -881,6 +929,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
var order = this.order;
|
var order = this.order;
|
||||||
var roff = this.roff;
|
var roff = this.roff;
|
||||||
var woff = this.woff;
|
var woff = this.woff;
|
||||||
|
var readOnly = readOnly();
|
||||||
boolean isConfined = seg.ownerThread() == null;
|
boolean isConfined = seg.ownerThread() == null;
|
||||||
MemorySegment transferSegment = isConfined? seg : seg.share();
|
MemorySegment transferSegment = isConfined? seg : seg.share();
|
||||||
makeInaccessible();
|
makeInaccessible();
|
||||||
@ -891,6 +940,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
copy.order = order;
|
copy.order = order;
|
||||||
copy.roff = roff;
|
copy.roff = roff;
|
||||||
copy.woff = woff;
|
copy.woff = woff;
|
||||||
|
copy.readOnly(readOnly);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -898,6 +948,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
|
|
||||||
void makeInaccessible() {
|
void makeInaccessible() {
|
||||||
seg = CLOSED_SEGMENT;
|
seg = CLOSED_SEGMENT;
|
||||||
|
wseg = CLOSED_SEGMENT;
|
||||||
roff = 0;
|
roff = 0;
|
||||||
woff = 0;
|
woff = 0;
|
||||||
}
|
}
|
||||||
@ -923,7 +974,7 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkWrite(int index, int size) {
|
private void checkWrite(int index, int size) {
|
||||||
if (index < 0 || seg.byteSize() < index + size) {
|
if (index < 0 || wseg.byteSize() < index + size) {
|
||||||
throw accessCheckException(index);
|
throw accessCheckException(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -932,6 +983,9 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
if (seg == CLOSED_SEGMENT) {
|
if (seg == CLOSED_SEGMENT) {
|
||||||
return bufferIsClosed();
|
return bufferIsClosed();
|
||||||
}
|
}
|
||||||
|
if (wseg != seg) {
|
||||||
|
return bufferIsReadOnly();
|
||||||
|
}
|
||||||
return ioobe;
|
return ioobe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -939,15 +993,22 @@ class MemSegBuf extends RcSupport<Buf, MemSegBuf> implements Buf {
|
|||||||
if (seg == CLOSED_SEGMENT) {
|
if (seg == CLOSED_SEGMENT) {
|
||||||
throw bufferIsClosed();
|
throw bufferIsClosed();
|
||||||
}
|
}
|
||||||
|
if (wseg != seg) {
|
||||||
|
return bufferIsReadOnly();
|
||||||
|
}
|
||||||
return new IndexOutOfBoundsException(
|
return new IndexOutOfBoundsException(
|
||||||
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
||||||
(seg.byteSize() - 1) + "].");
|
(seg.byteSize() - 1) + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
private IllegalStateException bufferIsClosed() {
|
private static IllegalStateException bufferIsClosed() {
|
||||||
return new IllegalStateException("This buffer is closed.");
|
return new IllegalStateException("This buffer is closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IllegalStateException bufferIsReadOnly() {
|
||||||
|
return new IllegalStateException("This buffer is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
Object recoverableMemory() {
|
Object recoverableMemory() {
|
||||||
return new RecoverableMemory(seg, alloc);
|
return new RecoverableMemory(seg, alloc);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ import java.text.ParseException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -90,6 +89,10 @@ public class BufTest {
|
|||||||
return fixtureCombinations().filter(f -> f.isDirect() && f.isCleaner() && f.isPooled());
|
return fixtureCombinations().filter(f -> f.isDirect() && f.isCleaner() && f.isPooled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Stream<Fixture> pooledAllocators() {
|
||||||
|
return fixtureCombinations().filter(Fixture::isPooled);
|
||||||
|
}
|
||||||
|
|
||||||
private static Stream<Fixture> fixtureCombinations() {
|
private static Stream<Fixture> fixtureCombinations() {
|
||||||
Fixture[] fxs = fixtures;
|
Fixture[] fxs = fixtures;
|
||||||
if (fxs != null) {
|
if (fxs != null) {
|
||||||
@ -187,7 +190,10 @@ public class BufTest {
|
|||||||
}, COMPOSITE));
|
}, COMPOSITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build().flatMap(BufTest::injectBifurcations).flatMap(BufTest::injectSlices);
|
var stream = builder.build();
|
||||||
|
return stream.flatMap(BufTest::injectBifurcations)
|
||||||
|
.flatMap(BufTest::injectSlices)
|
||||||
|
.flatMap(BufTest::injectReadOnlyToggling);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<Fixture> injectBifurcations(Fixture f) {
|
private static Stream<Fixture> injectBifurcations(Fixture f) {
|
||||||
@ -251,6 +257,26 @@ public class BufTest {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Stream<Fixture> injectReadOnlyToggling(Fixture f) {
|
||||||
|
Builder<Fixture> builder = Stream.builder();
|
||||||
|
builder.add(f);
|
||||||
|
builder.add(new Fixture(f + ".readOnly(true/false)", () -> {
|
||||||
|
var allocatorBase = f.get();
|
||||||
|
return new Allocator() {
|
||||||
|
@Override
|
||||||
|
public Buf allocate(int size) {
|
||||||
|
return allocatorBase.allocate(size).readOnly(true).readOnly(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
allocatorBase.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, f.getProperties()));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void startExecutor() throws IOException, ParseException {
|
static void startExecutor() throws IOException, ParseException {
|
||||||
executor = Executors.newSingleThreadExecutor();
|
executor = Executors.newSingleThreadExecutor();
|
||||||
@ -375,6 +401,31 @@ public class BufTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyInaccessible(Buf buf) {
|
private static void verifyInaccessible(Buf buf) {
|
||||||
|
verifyReadInaccessible(buf);
|
||||||
|
|
||||||
|
verifyWriteInaccessible(buf);
|
||||||
|
|
||||||
|
try (Allocator allocator = Allocator.heap();
|
||||||
|
Buf target = allocator.allocate(24)) {
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.copyInto(0, target, 0, 1));
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.copyInto(0, new byte[1], 0, 1));
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.copyInto(0, ByteBuffer.allocate(1), 0, 1));
|
||||||
|
if (Allocator.isComposite(buf)) {
|
||||||
|
assertThrows(IllegalStateException.class, () -> Allocator.extend(buf, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.bifurcate());
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.send());
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.acquire());
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.slice());
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.openCursor());
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.openCursor(0, 0));
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.openReverseCursor());
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.openReverseCursor(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyReadInaccessible(Buf buf) {
|
||||||
assertThrows(IllegalStateException.class, () -> buf.readByte());
|
assertThrows(IllegalStateException.class, () -> buf.readByte());
|
||||||
assertThrows(IllegalStateException.class, () -> buf.readUnsignedByte());
|
assertThrows(IllegalStateException.class, () -> buf.readUnsignedByte());
|
||||||
assertThrows(IllegalStateException.class, () -> buf.readChar());
|
assertThrows(IllegalStateException.class, () -> buf.readChar());
|
||||||
@ -387,6 +438,7 @@ public class BufTest {
|
|||||||
assertThrows(IllegalStateException.class, () -> buf.readFloat());
|
assertThrows(IllegalStateException.class, () -> buf.readFloat());
|
||||||
assertThrows(IllegalStateException.class, () -> buf.readLong());
|
assertThrows(IllegalStateException.class, () -> buf.readLong());
|
||||||
assertThrows(IllegalStateException.class, () -> buf.readDouble());
|
assertThrows(IllegalStateException.class, () -> buf.readDouble());
|
||||||
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.getByte(0));
|
assertThrows(IllegalStateException.class, () -> buf.getByte(0));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.getUnsignedByte(0));
|
assertThrows(IllegalStateException.class, () -> buf.getUnsignedByte(0));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.getChar(0));
|
assertThrows(IllegalStateException.class, () -> buf.getChar(0));
|
||||||
@ -399,6 +451,9 @@ public class BufTest {
|
|||||||
assertThrows(IllegalStateException.class, () -> buf.getFloat(0));
|
assertThrows(IllegalStateException.class, () -> buf.getFloat(0));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.getLong(0));
|
assertThrows(IllegalStateException.class, () -> buf.getLong(0));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.getDouble(0));
|
assertThrows(IllegalStateException.class, () -> buf.getDouble(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyWriteInaccessible(Buf buf) {
|
||||||
assertThrows(IllegalStateException.class, () -> buf.writeByte((byte) 32));
|
assertThrows(IllegalStateException.class, () -> buf.writeByte((byte) 32));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.writeUnsignedByte(32));
|
assertThrows(IllegalStateException.class, () -> buf.writeUnsignedByte(32));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.writeChar('3'));
|
assertThrows(IllegalStateException.class, () -> buf.writeChar('3'));
|
||||||
@ -411,6 +466,7 @@ public class BufTest {
|
|||||||
assertThrows(IllegalStateException.class, () -> buf.writeFloat(3.2f));
|
assertThrows(IllegalStateException.class, () -> buf.writeFloat(3.2f));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.writeLong(32));
|
assertThrows(IllegalStateException.class, () -> buf.writeLong(32));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.writeDouble(32));
|
assertThrows(IllegalStateException.class, () -> buf.writeDouble(32));
|
||||||
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.setByte(0, (byte) 32));
|
assertThrows(IllegalStateException.class, () -> buf.setByte(0, (byte) 32));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.setUnsignedByte(0, 32));
|
assertThrows(IllegalStateException.class, () -> buf.setUnsignedByte(0, 32));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.setChar(0, '3'));
|
assertThrows(IllegalStateException.class, () -> buf.setChar(0, '3'));
|
||||||
@ -425,22 +481,11 @@ public class BufTest {
|
|||||||
assertThrows(IllegalStateException.class, () -> buf.setDouble(0, 32));
|
assertThrows(IllegalStateException.class, () -> buf.setDouble(0, 32));
|
||||||
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.ensureWritable(1));
|
assertThrows(IllegalStateException.class, () -> buf.ensureWritable(1));
|
||||||
try (Allocator allocator = Allocator.heap();
|
|
||||||
Buf target = allocator.allocate(24)) {
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.copyInto(0, target, 0, 1));
|
|
||||||
if (Allocator.isComposite(buf)) {
|
|
||||||
assertThrows(IllegalStateException.class, () -> Allocator.extend(buf, target));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.bifurcate());
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.send());
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.acquire());
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.slice());
|
|
||||||
assertThrows(IllegalStateException.class, () -> buf.fill((byte) 0));
|
assertThrows(IllegalStateException.class, () -> buf.fill((byte) 0));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.openCursor());
|
try (Allocator allocator = Allocator.heap();
|
||||||
assertThrows(IllegalStateException.class, () -> buf.openCursor(0, 0));
|
Buf source = allocator.allocate(8)) {
|
||||||
assertThrows(IllegalStateException.class, () -> buf.openReverseCursor());
|
assertThrows(IllegalStateException.class, () -> source.copyInto(0, buf, 0, 1));
|
||||||
assertThrows(IllegalStateException.class, () -> buf.openReverseCursor(0, 0));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ -1893,6 +1938,18 @@ public class BufTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyCompositeBufferMustAllowExtendingWithReadOnlyBuffer() {
|
||||||
|
try (Allocator allocator = Allocator.heap()) {
|
||||||
|
try (Buf composite = allocator.compose()) {
|
||||||
|
try (Buf b = allocator.allocate(8).readOnly(true)) {
|
||||||
|
Allocator.extend(composite, b);
|
||||||
|
assertTrue(composite.readOnly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenExtendingCompositeBufferWithWriteOffsetAtCapacityExtensionWriteOffsetCanBeNonZero() {
|
public void whenExtendingCompositeBufferWithWriteOffsetAtCapacityExtensionWriteOffsetCanBeNonZero() {
|
||||||
try (Allocator allocator = Allocator.heap()) {
|
try (Allocator allocator = Allocator.heap()) {
|
||||||
@ -2262,6 +2319,255 @@ public class BufTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("allocators")
|
||||||
|
public void readOnlyBufferMustPreventWriteAccess(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
var b = buf.readOnly(true);
|
||||||
|
assertThat(b).isSameAs(buf);
|
||||||
|
verifyWriteInaccessible(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("allocators")
|
||||||
|
public void readOnlyBufferMustBecomeWritableAgainAfterTogglingReadOnlyOff(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
assertFalse(buf.readOnly());
|
||||||
|
buf.readOnly(true);
|
||||||
|
assertTrue(buf.readOnly());
|
||||||
|
verifyWriteInaccessible(buf);
|
||||||
|
|
||||||
|
buf.readOnly(false);
|
||||||
|
assertFalse(buf.readOnly());
|
||||||
|
|
||||||
|
verifyWriteAccessible(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyWriteAccessible(Buf buf) {
|
||||||
|
buf.writerOffset(0).writeByte((byte) 32);
|
||||||
|
assertThat(buf.readerOffset(0).readByte()).isEqualTo((byte) 32);
|
||||||
|
buf.writerOffset(0).writeUnsignedByte(32);
|
||||||
|
assertThat(buf.readerOffset(0).readUnsignedByte()).isEqualTo(32);
|
||||||
|
buf.writerOffset(0).writeChar('3');
|
||||||
|
assertThat(buf.readerOffset(0).readChar()).isEqualTo('3');
|
||||||
|
buf.writerOffset(0).writeShort((short) 32);
|
||||||
|
assertThat(buf.readerOffset(0).readShort()).isEqualTo((short) 32);
|
||||||
|
buf.writerOffset(0).writeUnsignedShort(32);
|
||||||
|
assertThat(buf.readerOffset(0).readUnsignedShort()).isEqualTo(32);
|
||||||
|
buf.writerOffset(0).writeMedium(32);
|
||||||
|
assertThat(buf.readerOffset(0).readMedium()).isEqualTo(32);
|
||||||
|
buf.writerOffset(0).writeUnsignedMedium(32);
|
||||||
|
assertThat(buf.readerOffset(0).readUnsignedMedium()).isEqualTo(32);
|
||||||
|
buf.writerOffset(0).writeInt(32);
|
||||||
|
assertThat(buf.readerOffset(0).readInt()).isEqualTo(32);
|
||||||
|
buf.writerOffset(0).writeUnsignedInt(32);
|
||||||
|
assertThat(buf.readerOffset(0).readUnsignedInt()).isEqualTo(32L);
|
||||||
|
buf.writerOffset(0).writeFloat(3.2f);
|
||||||
|
assertThat(buf.readerOffset(0).readFloat()).isEqualTo(3.2f);
|
||||||
|
buf.writerOffset(0).writeLong(32);
|
||||||
|
assertThat(buf.readerOffset(0).readLong()).isEqualTo(32L);
|
||||||
|
buf.writerOffset(0).writeDouble(3.2);
|
||||||
|
assertThat(buf.readerOffset(0).readDouble()).isEqualTo(3.2);
|
||||||
|
|
||||||
|
buf.setByte(0, (byte) 32);
|
||||||
|
assertThat(buf.getByte(0)).isEqualTo((byte) 32);
|
||||||
|
buf.setUnsignedByte(0, 32);
|
||||||
|
assertThat(buf.getUnsignedByte(0)).isEqualTo(32);
|
||||||
|
buf.setChar(0, '3');
|
||||||
|
assertThat(buf.getChar(0)).isEqualTo('3');
|
||||||
|
buf.setShort(0, (short) 32);
|
||||||
|
assertThat(buf.getShort(0)).isEqualTo((short) 32);
|
||||||
|
buf.setUnsignedShort(0, 32);
|
||||||
|
assertThat(buf.getUnsignedShort(0)).isEqualTo(32);
|
||||||
|
buf.setMedium(0, 32);
|
||||||
|
assertThat(buf.getMedium(0)).isEqualTo(32);
|
||||||
|
buf.setUnsignedMedium(0, 32);
|
||||||
|
assertThat(buf.getUnsignedMedium(0)).isEqualTo(32);
|
||||||
|
buf.setInt(0, 32);
|
||||||
|
assertThat(buf.getInt(0)).isEqualTo(32);
|
||||||
|
buf.setUnsignedInt(0, 32);
|
||||||
|
assertThat(buf.getUnsignedInt(0)).isEqualTo(32L);
|
||||||
|
buf.setFloat(0, 3.2f);
|
||||||
|
assertThat(buf.getFloat(0)).isEqualTo(3.2f);
|
||||||
|
buf.setLong(0, 32);
|
||||||
|
assertThat(buf.getLong(0)).isEqualTo(32L);
|
||||||
|
buf.setDouble(0, 3.2);
|
||||||
|
assertThat(buf.getDouble(0)).isEqualTo(3.2);
|
||||||
|
|
||||||
|
if (buf.isOwned()) {
|
||||||
|
buf.ensureWritable(1);
|
||||||
|
}
|
||||||
|
buf.fill((byte) 0);
|
||||||
|
try (Allocator allocator = Allocator.heap();
|
||||||
|
Buf source = allocator.allocate(8)) {
|
||||||
|
source.copyInto(0, buf, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void composingReadOnlyBuffersMustCreateReadOnlyCompositeBuffer() {
|
||||||
|
try (Allocator allocator = Allocator.heap();
|
||||||
|
Buf a = allocator.allocate(4).readOnly(true);
|
||||||
|
Buf b = allocator.allocate(4).readOnly(true);
|
||||||
|
Buf composite = allocator.compose(a, b)) {
|
||||||
|
assertTrue(composite.readOnly());
|
||||||
|
verifyWriteInaccessible(composite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("nonSliceAllocators")
|
||||||
|
public void readOnlyBufferMustRemainReadOnlyAfterSend(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
buf.readOnly(true);
|
||||||
|
var send = buf.send();
|
||||||
|
try (Buf receive = send.receive()) {
|
||||||
|
assertTrue(receive.readOnly());
|
||||||
|
verifyWriteInaccessible(receive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readOnlyBufferMustRemainReadOnlyAfterSendForEmptyCompositeBuffer() {
|
||||||
|
try (Allocator allocator = Allocator.heap();
|
||||||
|
Buf buf = allocator.compose()) {
|
||||||
|
buf.readOnly(true);
|
||||||
|
var send = buf.send();
|
||||||
|
try (Buf receive = send.receive()) {
|
||||||
|
assertTrue(receive.readOnly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("pooledAllocators")
|
||||||
|
public void readOnlyBufferMustNotBeReadOnlyAfterBeingReusedFromPool(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator()) {
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
try (Buf buf = allocator.allocate(8)) {
|
||||||
|
assertFalse(buf.readOnly());
|
||||||
|
buf.readOnly(true);
|
||||||
|
assertTrue(buf.readOnly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("allocators")
|
||||||
|
public void acquireOfReadOnlyBufferMustBeReadOnly(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
buf.readOnly(true);
|
||||||
|
try (Buf acquire = buf.acquire()) {
|
||||||
|
assertTrue(acquire.readOnly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("allocators")
|
||||||
|
public void sliceOfReadOnlyBufferMustBeReadOnly(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
buf.writeLong(0x0102030405060708L);
|
||||||
|
buf.readOnly(true);
|
||||||
|
try (Buf slice = buf.slice()) {
|
||||||
|
assertTrue(slice.readOnly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("nonSliceAllocators")
|
||||||
|
public void bifurcateOfReadOnlyBufferMustBeReadOnly(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(16)) {
|
||||||
|
buf.writeLong(0x0102030405060708L);
|
||||||
|
buf.readOnly(true);
|
||||||
|
try (Buf bifurcate = buf.bifurcate()) {
|
||||||
|
assertTrue(bifurcate.readOnly());
|
||||||
|
assertTrue(buf.readOnly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void composingReadOnlyAndWritableBuffersMustThrow() {
|
||||||
|
try (Allocator allocator = Allocator.heap();
|
||||||
|
Buf a = allocator.allocate(8).readOnly(true);
|
||||||
|
Buf b = allocator.allocate(8)) {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> allocator.compose(a, b));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> allocator.compose(b, a));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> allocator.compose(a, b, a));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> allocator.compose(b, a, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void compositeWritableBufferCannotBeExtendedWithReadOnlyBuffer() {
|
||||||
|
try (Allocator allocator = Allocator.heap()) {
|
||||||
|
Buf composite;
|
||||||
|
try (Buf a = allocator.allocate(8)) {
|
||||||
|
composite = allocator.compose(a);
|
||||||
|
}
|
||||||
|
try (composite; Buf b = allocator.allocate(8).readOnly(true)) {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> Allocator.extend(composite, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void compositeReadOnlyBufferCannotBeExtendedWithWritableBuffer() {
|
||||||
|
try (Allocator allocator = Allocator.heap()) {
|
||||||
|
Buf composite;
|
||||||
|
try (Buf a = allocator.allocate(8).readOnly(true)) {
|
||||||
|
composite = allocator.compose(a);
|
||||||
|
}
|
||||||
|
try (composite; Buf b = allocator.allocate(8)) {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> Allocator.extend(composite, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("nonSliceAllocators")
|
||||||
|
public void compactOnReadOnlyBufferMustThrow(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
buf.readOnly(true);
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.compact());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("nonSliceAllocators")
|
||||||
|
public void ensureWritableOnReadOnlyBufferMustThrow(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf buf = allocator.allocate(8)) {
|
||||||
|
buf.readOnly(true);
|
||||||
|
assertThrows(IllegalStateException.class, () -> buf.ensureWritable(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("nonSliceAllocators")
|
||||||
|
public void copyIntoOnReadOnlyBufferMustThrow(Fixture fixture) {
|
||||||
|
try (Allocator allocator = fixture.createAllocator();
|
||||||
|
Buf dest = allocator.allocate(8)) {
|
||||||
|
dest.readOnly(true);
|
||||||
|
try (Buf src = allocator.allocate(8)) {
|
||||||
|
assertThrows(IllegalStateException.class, () -> src.copyInto(0, dest, 0, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// <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