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:
Trustin Lee 2014-12-30 15:52:57 +09:00
parent 38fae09f23
commit 0b8f47da04

View File

@ -39,13 +39,13 @@ import java.util.ListIterator;
*/
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
private final ResourceLeak leak;
private final ByteBufAllocator alloc;
private final boolean direct;
private final List<Component> components = new ArrayList<Component>();
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;
@ -444,50 +444,71 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
@Override
public boolean hasArray() {
if (components.size() == 1) {
switch (components.size()) {
case 0:
return true;
case 1:
return components.get(0).buf.hasArray();
default:
return false;
}
return false;
}
@Override
public byte[] array() {
if (components.size() == 1) {
switch (components.size()) {
case 0:
return EmptyArrays.EMPTY_BYTES;
case 1:
return components.get(0).buf.array();
default:
throw new UnsupportedOperationException();
}
throw new UnsupportedOperationException();
}
@Override
public int arrayOffset() {
if (components.size() == 1) {
switch (components.size()) {
case 0:
return 0;
case 1:
return components.get(0).buf.arrayOffset();
default:
throw new UnsupportedOperationException();
}
throw new UnsupportedOperationException();
}
@Override
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();
default:
return false;
}
return false;
}
@Override
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();
default:
throw new UnsupportedOperationException();
}
throw new UnsupportedOperationException();
}
@Override
public int capacity() {
if (components.isEmpty()) {
final int numComponents = components.size();
if (numComponents == 0) {
return 0;
}
return components.get(components.size() - 1).endOffset;
return components.get(numComponents - 1).endOffset;
}
@Override
@ -964,7 +985,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
checkIndex(index, length);
if (length == 0) {
return in.read(FULL_BYTEBUFFER);
return in.read(EMPTY_NIO_BUFFER);
}
int i = toComponentIndex(index);
@ -1093,9 +1114,12 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
@Override
public int nioBufferCount() {
if (components.size() == 1) {
switch (components.size()) {
case 0:
return 1;
case 1:
return components.get(0).buf.nioBufferCount();
} else {
default:
int count = 0;
int componentsCount = components.size();
for (int i = 0; i < componentsCount; i++) {
@ -1108,26 +1132,35 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
@Override
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);
default:
throw new UnsupportedOperationException();
}
throw new UnsupportedOperationException();
}
@Override
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;
if (buf.nioBufferCount() == 1) {
return components.get(0).buf.nioBuffer(index, length);
}
}
ByteBuffer merged = ByteBuffer.allocate(length).order(order());
ByteBuffer[] buffers = nioBuffers(index, length);
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < buffers.length; i++) {
merged.put(buffers[i]);
for (ByteBuffer buf: buffers) {
merged.put(buf);
}
merged.flip();
@ -1138,7 +1171,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
public ByteBuffer[] nioBuffers(int index, int length) {
checkIndex(index, length);
if (length == 0) {
return new ByteBuffer[] { EMPTY_BYTEBUFFER };
return new ByteBuffer[] { EMPTY_NIO_BUFFER };
}
List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.size());