[#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:
parent
62057f73d6
commit
8b1f247a1a
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user