Introduce ByteBuf#isContiguous() method (#9735)
Motivation There's currently no way to determine whether an arbitrary ByteBuf behaves internally like a "singluar" buffer or a composite one, and this can be important to know when making decisions about how to manipulate it in an efficient way. An example of this is the ByteBuf#discardReadBytes() method which increases the writable bytes for a contiguous buffer (by readerIndex) but does not for a composite one. Unfortunately !(buf instanceof CompositeByteBuf) is not reliable, since for example this will be true in the case of a sliced CompositeByteBuf or some third-party composite implementation. isContiguous was chosen over isComposite since we want to assume "not contiguous" in the unknown/default case - the doc will it clear that false does not imply composite. Modifications - Add ByteBuf#isContiguous() which returns true by default - Override the "concrete" ByteBuf impls to return true and ensure wrapped/derived impls delegate it appropriately - Include some basic unit tests Result Better assumptions/decisions possible when manipulating arbitrary ByteBufs, for example when combining/cumulating them.
This commit is contained in:
parent
d13ac5290a
commit
625981a296
@ -117,4 +117,9 @@ public abstract class AbstractDerivedByteBuf extends AbstractByteBuf {
|
||||
public ByteBuffer nioBuffer(int index, int length) {
|
||||
return unwrap().nioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContiguous() {
|
||||
return unwrap().isContiguous();
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,11 @@ abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByte
|
||||
return unwrap().hasMemoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContiguous() {
|
||||
return unwrap().isContiguous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int nioBufferCount() {
|
||||
return unwrap().nioBufferCount();
|
||||
|
@ -2338,6 +2338,19 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
|
||||
*/
|
||||
public abstract long memoryAddress();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this {@link ByteBuf} implementation is backed by a single memory region.
|
||||
* Composite buffer implementations must return false even if they currently hold ≤ 1 components.
|
||||
* For buffers that return {@code true}, it's guaranteed that a successful call to {@link #discardReadBytes()}
|
||||
* will increase the value of {@link #maxFastWritableBytes()} by the current {@code readerIndex}.
|
||||
* <p>
|
||||
* This method will return {@code false} by default, and a {@code false} return value does not necessarily
|
||||
* mean that the implementation is composite or that it is <i>not</i> backed by a single memory region.
|
||||
*/
|
||||
public boolean isContiguous() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes this buffer's readable bytes into a string with the specified
|
||||
* character set name. This method is identical to
|
||||
|
@ -939,6 +939,11 @@ public final class EmptyByteBuf extends ByteBuf {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContiguous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Charset charset) {
|
||||
return "";
|
||||
|
@ -213,6 +213,11 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
||||
return new ByteBuffer[] { nioBuffer(index, length) };
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isContiguous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
|
||||
return out.write(duplicateInternalNioBuffer(index, length));
|
||||
|
@ -453,6 +453,11 @@ class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
|
||||
return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isContiguous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return buffer.hasArray();
|
||||
|
@ -956,6 +956,11 @@ public class SwappedByteBuf extends ByteBuf {
|
||||
return buf.hasMemoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContiguous() {
|
||||
return buf.isContiguous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long memoryAddress() {
|
||||
return buf.memoryAddress();
|
||||
|
@ -595,6 +595,11 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
return new ByteBuffer[] { nioBuffer(index, length) };
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isContiguous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
ensureAccessible();
|
||||
|
@ -320,6 +320,11 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isContiguous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(int index) {
|
||||
ensureAccessible();
|
||||
|
@ -52,6 +52,11 @@ class WrappedByteBuf extends ByteBuf {
|
||||
return buf.hasMemoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContiguous() {
|
||||
return buf.isContiguous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long memoryAddress() {
|
||||
return buf.memoryAddress();
|
||||
|
@ -109,6 +109,13 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
ByteBuf buf = newBuffer(4);
|
||||
assertFalse(buf.isContiguous());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the "getBufferFor" method
|
||||
*/
|
||||
|
@ -114,4 +114,11 @@ public abstract class AbstractPooledByteBufTest extends AbstractByteBufTest {
|
||||
assertEquals(buffer.writableBytes(), buffer.maxFastWritableBytes());
|
||||
buffer.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
ByteBuf buf = newBuffer(4);
|
||||
assertTrue(buf.isContiguous());
|
||||
buf.release();
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests big-endian direct channel buffers
|
||||
*/
|
||||
@ -35,4 +37,11 @@ public class BigEndianDirectByteBufTest extends AbstractByteBufTest {
|
||||
protected ByteBuf newDirectBuffer(int length, int maxCapacity) {
|
||||
return new UnpooledDirectByteBuf(UnpooledByteBufAllocator.DEFAULT, length, maxCapacity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
ByteBuf buf = newBuffer(4);
|
||||
assertTrue(buf.isContiguous());
|
||||
buf.release();
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,13 @@ public class DuplicatedByteBufTest extends AbstractByteBufTest {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
ByteBuf buf = newBuffer(4);
|
||||
assertEquals(buf.unwrap().isContiguous(), buf.isContiguous());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullInConstructor() {
|
||||
new DuplicatedByteBuf(null);
|
||||
|
@ -22,6 +22,12 @@ import static org.junit.Assert.*;
|
||||
|
||||
public class EmptyByteBufTest {
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
EmptyByteBuf empty = new EmptyByteBuf(UnpooledByteBufAllocator.DEFAULT);
|
||||
assertTrue(empty.isContiguous());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWritable() {
|
||||
EmptyByteBuf empty = new EmptyByteBuf(UnpooledByteBufAllocator.DEFAULT);
|
||||
|
@ -37,6 +37,13 @@ public class ReadOnlyDirectByteBufferBufTest {
|
||||
return ByteBuffer.allocateDirect(size);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
ByteBuf buf = buffer(allocate(4).asReadOnlyBuffer());
|
||||
Assert.assertTrue(buf.isContiguous());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testConstructWithWritable() {
|
||||
buffer(allocate(1));
|
||||
|
@ -47,6 +47,13 @@ public class SlicedByteBufTest extends AbstractByteBufTest {
|
||||
return buffer.slice(offset, length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsContiguous() {
|
||||
ByteBuf buf = newBuffer(4);
|
||||
assertEquals(buf.unwrap().isContiguous(), buf.isContiguous());
|
||||
buf.release();
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullInConstructor() {
|
||||
new SlicedByteBuf(null, 0, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user