Implement internal memory access methods of CompositeByteBuf correctly
Motivation: When a CompositeByteBuf is empty (i.e. has no component), its internal memory access operations do not always behave as expected. Modifications: Check if the nunmber of components is zero. If so, return an empty array or an empty NIO buffer, etc. Result: More robustness
This commit is contained in:
parent
a666acce6d
commit
155c0e2f36
@ -39,13 +39,13 @@ import java.util.ListIterator;
|
|||||||
*/
|
*/
|
||||||
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
||||||
|
|
||||||
|
private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
|
||||||
|
|
||||||
private final ResourceLeak leak;
|
private final ResourceLeak leak;
|
||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
private final boolean direct;
|
private final boolean direct;
|
||||||
private final List<Component> components = new ArrayList<Component>();
|
private final List<Component> components = new ArrayList<Component>();
|
||||||
private final int maxNumComponents;
|
private final int maxNumComponents;
|
||||||
private static final ByteBuffer FULL_BYTEBUFFER = (ByteBuffer) ByteBuffer.allocate(1).position(1);
|
|
||||||
private static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocateDirect(0);
|
|
||||||
|
|
||||||
private boolean freed;
|
private boolean freed;
|
||||||
|
|
||||||
@ -444,50 +444,71 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasArray() {
|
public boolean hasArray() {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.hasArray();
|
return components.get(0).buf.hasArray();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] array() {
|
public byte[] array() {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return EmptyArrays.EMPTY_BYTES;
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.array();
|
return components.get(0).buf.array();
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int arrayOffset() {
|
public int arrayOffset() {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.arrayOffset();
|
return components.get(0).buf.arrayOffset();
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasMemoryAddress() {
|
public boolean hasMemoryAddress() {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.hasMemoryAddress();
|
return components.get(0).buf.hasMemoryAddress();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long memoryAddress() {
|
public long memoryAddress() {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return Unpooled.EMPTY_BUFFER.memoryAddress();
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.memoryAddress();
|
return components.get(0).buf.memoryAddress();
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int capacity() {
|
public int capacity() {
|
||||||
if (components.isEmpty()) {
|
final int numComponents = components.size();
|
||||||
|
if (numComponents == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return components.get(components.size() - 1).endOffset;
|
return components.get(numComponents - 1).endOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -964,7 +985,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
|
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return in.read(FULL_BYTEBUFFER);
|
return in.read(EMPTY_NIO_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = toComponentIndex(index);
|
int i = toComponentIndex(index);
|
||||||
@ -1093,9 +1114,12 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int nioBufferCount() {
|
public int nioBufferCount() {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return 1;
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.nioBufferCount();
|
return components.get(0).buf.nioBufferCount();
|
||||||
} else {
|
default:
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int componentsCount = components.size();
|
int componentsCount = components.size();
|
||||||
for (int i = 0; i < componentsCount; i++) {
|
for (int i = 0; i < componentsCount; i++) {
|
||||||
@ -1108,26 +1132,35 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer internalNioBuffer(int index, int length) {
|
public ByteBuffer internalNioBuffer(int index, int length) {
|
||||||
if (components.size() == 1) {
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return EMPTY_NIO_BUFFER;
|
||||||
|
case 1:
|
||||||
return components.get(0).buf.internalNioBuffer(index, length);
|
return components.get(0).buf.internalNioBuffer(index, length);
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer nioBuffer(int index, int length) {
|
public ByteBuffer nioBuffer(int index, int length) {
|
||||||
if (components.size() == 1) {
|
checkIndex(index, length);
|
||||||
|
|
||||||
|
switch (components.size()) {
|
||||||
|
case 0:
|
||||||
|
return EMPTY_NIO_BUFFER;
|
||||||
|
case 1:
|
||||||
ByteBuf buf = components.get(0).buf;
|
ByteBuf buf = components.get(0).buf;
|
||||||
if (buf.nioBufferCount() == 1) {
|
if (buf.nioBufferCount() == 1) {
|
||||||
return components.get(0).buf.nioBuffer(index, length);
|
return components.get(0).buf.nioBuffer(index, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer merged = ByteBuffer.allocate(length).order(order());
|
ByteBuffer merged = ByteBuffer.allocate(length).order(order());
|
||||||
ByteBuffer[] buffers = nioBuffers(index, length);
|
ByteBuffer[] buffers = nioBuffers(index, length);
|
||||||
|
|
||||||
//noinspection ForLoopReplaceableByForEach
|
for (ByteBuffer buf: buffers) {
|
||||||
for (int i = 0; i < buffers.length; i++) {
|
merged.put(buf);
|
||||||
merged.put(buffers[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
merged.flip();
|
merged.flip();
|
||||||
@ -1138,7 +1171,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
public ByteBuffer[] nioBuffers(int index, int length) {
|
public ByteBuffer[] nioBuffers(int index, int length) {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return new ByteBuffer[] { EMPTY_BYTEBUFFER };
|
return new ByteBuffer[] { EMPTY_NIO_BUFFER };
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.size());
|
List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.size());
|
||||||
|
Loading…
Reference in New Issue
Block a user