Optimized CompositeChannelBuffer creation

This commit is contained in:
Trustin Lee 2009-11-03 02:34:54 +00:00
parent ec80daae01
commit 5eb56831e8
2 changed files with 81 additions and 48 deletions

View File

@ -19,6 +19,8 @@ import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.List;
/**
@ -338,16 +340,34 @@ public class ChannelBuffers {
}
break;
default:
ChannelBuffer[] wrappedBuffers = new ChannelBuffer[arrays.length];
for (int i = 0; i < arrays.length; i ++) {
wrappedBuffers[i] = wrappedBuffer(endianness, arrays[i]);
// Get the list of the component, while guessing the byte order.
final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(arrays.length);
for (byte[] a: arrays) {
if (a == null) {
break;
}
if (a.length > 0) {
components.add(wrappedBuffer(endianness, a));
}
}
return wrappedBuffer(wrappedBuffers);
return compositeBuffer(endianness, components);
}
return EMPTY_BUFFER;
}
private static ChannelBuffer compositeBuffer(
ByteOrder endianness, List<ChannelBuffer> components) {
switch (components.size()) {
case 0:
return EMPTY_BUFFER;
case 1:
return components.get(0);
default:
return new CompositeChannelBuffer(endianness, components);
}
}
/**
* Creates a new composite buffer which wraps the readable bytes of the
* specified buffers without copying them. A modification on the content
@ -367,11 +387,33 @@ public class ChannelBuffers {
}
break;
default:
for (ChannelBuffer b: buffers) {
if (b.readable()) {
return new CompositeChannelBuffer(buffers);
ByteOrder order = null;
final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(buffers.length);
for (ChannelBuffer c: buffers) {
if (c == null) {
break;
}
if (c.readable()) {
if (order != null) {
if (!order.equals(c.order())) {
throw new IllegalArgumentException(
"inconsistent byte order");
}
} else {
order = c.order();
}
if (c instanceof CompositeChannelBuffer) {
// Expand nested composition.
components.addAll(
((CompositeChannelBuffer) c).decompose(
c.readerIndex(), c.readableBytes()));
} else {
// An ordinary buffer (non-composite)
components.add(c.slice());
}
}
}
return compositeBuffer(order, components);
}
return EMPTY_BUFFER;
}
@ -395,11 +437,25 @@ public class ChannelBuffers {
}
break;
default:
ChannelBuffer[] wrappedBuffers = new ChannelBuffer[buffers.length];
for (int i = 0; i < buffers.length; i ++) {
wrappedBuffers[i] = wrappedBuffer(buffers[i]);
ByteOrder order = null;
final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(buffers.length);
for (ByteBuffer b: buffers) {
if (b == null) {
break;
}
if (b.hasRemaining()) {
if (order != null) {
if (!order.equals(b.order())) {
throw new IllegalArgumentException(
"inconsistent byte order");
}
} else {
order = b.order();
}
components.add(wrappedBuffer(b));
}
}
return wrappedBuffer(wrappedBuffers);
return compositeBuffer(order, components);
}
return EMPTY_BUFFER;

View File

@ -48,44 +48,15 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
private int[] indices;
private int lastAccessedComponentId;
public CompositeChannelBuffer(ChannelBuffer... buffers) {
if (buffers.length == 0) {
throw new IllegalArgumentException("buffers should not be empty.");
}
// Get the list of the component, while guessing the byte order.
ByteOrder expectedEndianness = null;
final List<ChannelBuffer> newComponents = new ArrayList<ChannelBuffer>(buffers.length);
for (ChannelBuffer c: buffers) {
if (c.readableBytes() > 0) {
expectedEndianness = c.order();
if (c instanceof CompositeChannelBuffer) {
// Expand nested composition.
newComponents.addAll(
((CompositeChannelBuffer) c).slice0(
c.readerIndex(), c.readableBytes()));
} else {
// An ordinary buffer (non-composite)
newComponents.add(c.slice());
}
} else if (c.capacity() != 0) {
expectedEndianness = c.order();
}
}
if (expectedEndianness == null) {
throw new IllegalArgumentException(
"buffers have only empty buffers.");
}
order = expectedEndianness;
setComponents(newComponents);
public CompositeChannelBuffer(ByteOrder endianness, List<ChannelBuffer> buffers) {
order = endianness;
setComponents(buffers);
}
/**
* Same with {@link #slice(int, int)} except that this method returns a list.
*/
private List<ChannelBuffer> slice0(int index, int length) {
public List<ChannelBuffer> decompose(int index, int length) {
if (length == 0) {
return Collections.emptyList();
}
@ -556,9 +527,15 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
return ChannelBuffers.EMPTY_BUFFER;
}
List<ChannelBuffer> listBuffer = slice0(index, length);
ChannelBuffer[] buffers = listBuffer.toArray(new ChannelBuffer[listBuffer.size()]);
return new CompositeChannelBuffer(buffers);
List<ChannelBuffer> components = decompose(index, length);
switch (components.size()) {
case 0:
return ChannelBuffers.EMPTY_BUFFER;
case 1:
return components.get(0);
default:
return new CompositeChannelBuffer(order(), components);
}
}
public ByteBuffer toByteBuffer(int index, int length) {
@ -667,7 +644,7 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
int localWriterIndex = this.writerIndex();
final int bytesToMove = capacity() - localReaderIndex;
List<ChannelBuffer> list = slice0(localReaderIndex, bytesToMove);
List<ChannelBuffer> list = decompose(localReaderIndex, bytesToMove);
// Add a new buffer so that the capacity of this composite buffer does
// not decrease due to the discarded components.