[#3623] CompositeByteBuf.iterator() should return optimized Iterable

Motivation:

CompositeByteBuf.iterator() currently creates a new ArrayList and fill it with the ByteBufs, which is more expensive then it needs to be.

Modifications:

- Use special Iterator implementation

Result:

Less overhead when calling iterator()
This commit is contained in:
Norman Maurer 2015-04-10 09:43:06 +02:00
parent 62057f73d6
commit 8b1f247a1a
2 changed files with 109 additions and 4 deletions

View File

@ -28,9 +28,11 @@ import java.nio.channels.ScatteringByteChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* A virtual buffer which shows multiple buffers as a single merged buffer. It is recommended to use
@ -40,6 +42,7 @@ import java.util.ListIterator;
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf> {
private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
private static final Iterator<ByteBuf> EMPTY_ITERATOR = Collections.<ByteBuf>emptyList().iterator();
private final ResourceLeak leak;
private final ByteBufAllocator alloc;
@ -374,11 +377,10 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
@Override
public Iterator<ByteBuf> iterator() {
ensureAccessible();
List<ByteBuf> list = new ArrayList<ByteBuf>(components.size());
for (Component c: components) {
list.add(c.buf);
if (components.isEmpty()) {
return EMPTY_ITERATOR;
}
return list.iterator();
return new CompositeByteBufIterator();
}
/**
@ -1648,4 +1650,34 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
public ByteBuf unwrap() {
return null;
}
private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
private final int size = components.size();
private int index;
@Override
public boolean hasNext() {
return size > index;
}
@Override
public ByteBuf next() {
if (size != components.size()) {
throw new ConcurrentModificationException();
}
if (!hasNext()) {
throw new NoSuchElementException();
}
try {
return components.get(index++).buf;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read-Only");
}
}
}

View File

@ -21,7 +21,10 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import static io.netty.buffer.Unpooled.*;
import static io.netty.util.ReferenceCountUtil.*;
@ -865,4 +868,74 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
assertNotSame(EMPTY_BUFFER, cbuf.internalComponentAtOffset(1));
cbuf.release();
}
@Test
public void testIterator() {
CompositeByteBuf cbuf = compositeBuffer();
cbuf.addComponent(EMPTY_BUFFER);
cbuf.addComponent(EMPTY_BUFFER);
Iterator<ByteBuf> it = cbuf.iterator();
assertTrue(it.hasNext());
assertSame(EMPTY_BUFFER, it.next());
assertTrue(it.hasNext());
assertSame(EMPTY_BUFFER, it.next());
assertFalse(it.hasNext());
try {
it.next();
fail();
} catch (NoSuchElementException e) {
//Expected
}
cbuf.release();
}
@Test
public void testEmptyIterator() {
CompositeByteBuf cbuf = compositeBuffer();
Iterator<ByteBuf> it = cbuf.iterator();
assertFalse(it.hasNext());
try {
it.next();
fail();
} catch (NoSuchElementException e) {
//Expected
}
cbuf.release();
}
@Test(expected = ConcurrentModificationException.class)
public void testIteratorConcurrentModificationAdd() {
CompositeByteBuf cbuf = compositeBuffer();
cbuf.addComponent(EMPTY_BUFFER);
Iterator<ByteBuf> it = cbuf.iterator();
cbuf.addComponent(EMPTY_BUFFER);
assertTrue(it.hasNext());
try {
it.next();
} finally {
cbuf.release();
}
}
@Test(expected = ConcurrentModificationException.class)
public void testIteratorConcurrentModificationRemove() {
CompositeByteBuf cbuf = compositeBuffer();
cbuf.addComponent(EMPTY_BUFFER);
Iterator<ByteBuf> it = cbuf.iterator();
cbuf.removeComponent(0);
assertTrue(it.hasNext());
try {
it.next();
} finally {
cbuf.release();
}
}
}