[#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
52878880b4
commit
43d57ddd46
@ -28,9 +28,11 @@ import java.nio.channels.ScatteringByteChannel;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.ConcurrentModificationException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
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
|
* 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> {
|
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf> {
|
||||||
|
|
||||||
private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
|
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 ResourceLeak leak;
|
||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
@ -374,11 +377,10 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
@Override
|
@Override
|
||||||
public Iterator<ByteBuf> iterator() {
|
public Iterator<ByteBuf> iterator() {
|
||||||
ensureAccessible();
|
ensureAccessible();
|
||||||
List<ByteBuf> list = new ArrayList<ByteBuf>(components.size());
|
if (components.isEmpty()) {
|
||||||
for (Component c: components) {
|
return EMPTY_ITERATOR;
|
||||||
list.add(c.buf);
|
|
||||||
}
|
}
|
||||||
return list.iterator();
|
return new CompositeByteBufIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1648,4 +1650,34 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
public ByteBuf unwrap() {
|
public ByteBuf unwrap() {
|
||||||
return null;
|
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.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.ConcurrentModificationException;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import static io.netty.buffer.Unpooled.*;
|
import static io.netty.buffer.Unpooled.*;
|
||||||
import static io.netty.util.ReferenceCountUtil.*;
|
import static io.netty.util.ReferenceCountUtil.*;
|
||||||
@ -865,4 +868,74 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
|
|||||||
assertNotSame(EMPTY_BUFFER, cbuf.internalComponentAtOffset(1));
|
assertNotSame(EMPTY_BUFFER, cbuf.internalComponentAtOffset(1));
|
||||||
cbuf.release();
|
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…
x
Reference in New Issue
Block a user