io.netty.buffer.CompositeByteBuf Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including
all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and
Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.buffer;
import io.netty.util.ResourceLeak;
import io.netty.util.internal.EmptyArrays;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* A virtual buffer which shows multiple buffers as a single merged buffer. It is recommended to use
* {@link ByteBufAllocator#compositeBuffer()} or {@link Unpooled#wrappedBuffer(ByteBuf...)} instead of calling the
* constructor explicitly.
*/
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 components = new ArrayList();
private final int maxNumComponents;
private boolean freed;
public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) {
super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
this.alloc = alloc;
this.direct = direct;
this.maxNumComponents = maxNumComponents;
leak = leakDetector.open(this);
}
public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf... buffers) {
super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (maxNumComponents < 2) {
throw new IllegalArgumentException(
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
}
this.alloc = alloc;
this.direct = direct;
this.maxNumComponents = maxNumComponents;
addComponents0(0, buffers);
consolidateIfNeeded();
setIndex(0, capacity());
leak = leakDetector.open(this);
}
public CompositeByteBuf(
ByteBufAllocator alloc, boolean direct, int maxNumComponents, Iterable buffers) {
super(Integer.MAX_VALUE);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (maxNumComponents < 2) {
throw new IllegalArgumentException(
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
}
this.alloc = alloc;
this.direct = direct;
this.maxNumComponents = maxNumComponents;
addComponents0(0, buffers);
consolidateIfNeeded();
setIndex(0, capacity());
leak = leakDetector.open(this);
}
/**
* Add the given {@link ByteBuf}.
*
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
* If you need to have it increased you need to handle it by your own.
*
* @param buffer the {@link ByteBuf} to add
*/
public CompositeByteBuf addComponent(ByteBuf buffer) {
addComponent0(components.size(), buffer);
consolidateIfNeeded();
return this;
}
/**
* Add the given {@link ByteBuf}s.
*
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
* If you need to have it increased you need to handle it by your own.
*
* @param buffers the {@link ByteBuf}s to add
*/
public CompositeByteBuf addComponents(ByteBuf... buffers) {
addComponents0(components.size(), buffers);
consolidateIfNeeded();
return this;
}
/**
* Add the given {@link ByteBuf}s.
*
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
* If you need to have it increased you need to handle it by your own.
*
* @param buffers the {@link ByteBuf}s to add
*/
public CompositeByteBuf addComponents(Iterable buffers) {
addComponents0(components.size(), buffers);
consolidateIfNeeded();
return this;
}
/**
* Add the given {@link ByteBuf} on the specific index.
*
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
* If you need to have it increased you need to handle it by your own.
*
* @param cIndex the index on which the {@link ByteBuf} will be added
* @param buffer the {@link ByteBuf} to add
*/
public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
addComponent0(cIndex, buffer);
consolidateIfNeeded();
return this;
}
private int addComponent0(int cIndex, ByteBuf buffer) {
checkComponentIndex(cIndex);
if (buffer == null) {
throw new NullPointerException("buffer");
}
int readableBytes = buffer.readableBytes();
// No need to consolidate - just add a component to the list.
Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
if (cIndex == components.size()) {
components.add(c);
if (cIndex == 0) {
c.endOffset = readableBytes;
} else {
Component prev = components.get(cIndex - 1);
c.offset = prev.endOffset;
c.endOffset = c.offset + readableBytes;
}
} else {
components.add(cIndex, c);
if (readableBytes != 0) {
updateComponentOffsets(cIndex);
}
}
return cIndex;
}
/**
* Add the given {@link ByteBuf}s on the specific index
*
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
* If you need to have it increased you need to handle it by your own.
*
* @param cIndex the index on which the {@link ByteBuf} will be added.
* @param buffers the {@link ByteBuf}s to add
*/
public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) {
addComponents0(cIndex, buffers);
consolidateIfNeeded();
return this;
}
private int addComponents0(int cIndex, ByteBuf... buffers) {
checkComponentIndex(cIndex);
if (buffers == null) {
throw new NullPointerException("buffers");
}
// No need for consolidation
for (ByteBuf b: buffers) {
if (b == null) {
break;
}
cIndex = addComponent0(cIndex, b) + 1;
int size = components.size();
if (cIndex > size) {
cIndex = size;
}
}
return cIndex;
}
/**
* Add the given {@link ByteBuf}s on the specific index
*
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
* If you need to have it increased you need to handle it by your own.
*
* @param cIndex the index on which the {@link ByteBuf} will be added.
* @param buffers the {@link ByteBuf}s to add
*/
public CompositeByteBuf addComponents(int cIndex, Iterable buffers) {
addComponents0(cIndex, buffers);
consolidateIfNeeded();
return this;
}
private int addComponents0(int cIndex, Iterable buffers) {
if (buffers == null) {
throw new NullPointerException("buffers");
}
if (buffers instanceof ByteBuf) {
// If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf).
return addComponent0(cIndex, (ByteBuf) buffers);
}
if (!(buffers instanceof Collection)) {
List list = new ArrayList();
for (ByteBuf b: buffers) {
list.add(b);
}
buffers = list;
}
Collection col = (Collection) buffers;
return addComponents0(cIndex, col.toArray(new ByteBuf[col.size()]));
}
/**
* This should only be called as last operation from a method as this may adjust the underlying
* array of components and so affect the index etc.
*/
private void consolidateIfNeeded() {
// Consolidate if the number of components will exceed the allowed maximum by the current
// operation.
final int numComponents = components.size();
if (numComponents > maxNumComponents) {
final int capacity = components.get(numComponents - 1).endOffset;
ByteBuf consolidated = allocBuffer(capacity);
// We're not using foreach to avoid creating an iterator.
for (int i = 0; i < numComponents; i ++) {
Component c = components.get(i);
ByteBuf b = c.buf;
consolidated.writeBytes(b);
c.freeIfNecessary();
}
Component c = new Component(consolidated);
c.endOffset = c.length;
components.clear();
components.add(c);
}
}
private void checkComponentIndex(int cIndex) {
ensureAccessible();
if (cIndex < 0 || cIndex > components.size()) {
throw new IndexOutOfBoundsException(String.format(
"cIndex: %d (expected: >= 0 && <= numComponents(%d))",
cIndex, components.size()));
}
}
private void checkComponentIndex(int cIndex, int numComponents) {
ensureAccessible();
if (cIndex < 0 || cIndex + numComponents > components.size()) {
throw new IndexOutOfBoundsException(String.format(
"cIndex: %d, numComponents: %d " +
"(expected: cIndex >= 0 && cIndex + numComponents <= totalNumComponents(%d))",
cIndex, numComponents, components.size()));
}
}
private void updateComponentOffsets(int cIndex) {
int size = components.size();
if (size <= cIndex) {
return;
}
Component c = components.get(cIndex);
if (cIndex == 0) {
c.offset = 0;
c.endOffset = c.length;
cIndex ++;
}
for (int i = cIndex; i < size; i ++) {
Component prev = components.get(i - 1);
Component cur = components.get(i);
cur.offset = prev.endOffset;
cur.endOffset = cur.offset + cur.length;
}
}
/**
* Remove the {@link ByteBuf} from the given index.
*
* @param cIndex the index on from which the {@link ByteBuf} will be remove
*/
public CompositeByteBuf removeComponent(int cIndex) {
checkComponentIndex(cIndex);
Component comp = components.remove(cIndex);
comp.freeIfNecessary();
if (comp.length > 0) {
// Only need to call updateComponentOffsets if the length was > 0
updateComponentOffsets(cIndex);
}
return this;
}
/**
* Remove the number of {@link ByteBuf}s starting from the given index.
*
* @param cIndex the index on which the {@link ByteBuf}s will be started to removed
* @param numComponents the number of components to remove
*/
public CompositeByteBuf removeComponents(int cIndex, int numComponents) {
checkComponentIndex(cIndex, numComponents);
if (numComponents == 0) {
return this;
}
List toRemove = components.subList(cIndex, cIndex + numComponents);
boolean needsUpdate = false;
for (Component c: toRemove) {
if (c.length > 0) {
needsUpdate = true;
}
c.freeIfNecessary();
}
toRemove.clear();
if (needsUpdate) {
// Only need to call updateComponentOffsets if the length was > 0
updateComponentOffsets(cIndex);
}
return this;
}
public Iterator iterator() {
ensureAccessible();
List list = new ArrayList(components.size());
for (Component c: components) {
list.add(c.buf);
}
return list.iterator();
}
/**
* Same with {@link #slice(int, int)} except that this method returns a list.
*/
public List decompose(int offset, int length) {
checkIndex(offset, length);
if (length == 0) {
return Collections.emptyList();
}
int componentId = toComponentIndex(offset);
List slice = new ArrayList(components.size());
// The first component
Component firstC = components.get(componentId);
ByteBuf first = firstC.buf.duplicate();
first.readerIndex(offset - firstC.offset);
ByteBuf buf = first;
int bytesToSlice = length;
do {
int readableBytes = buf.readableBytes();
if (bytesToSlice <= readableBytes) {
// Last component
buf.writerIndex(buf.readerIndex() + bytesToSlice);
slice.add(buf);
break;
} else {
// Not the last component
slice.add(buf);
bytesToSlice -= readableBytes;
componentId ++;
// Fetch the next component.
buf = components.get(componentId).buf.duplicate();
}
} while (bytesToSlice > 0);
// Slice all components because only readable bytes are interesting.
for (int i = 0; i < slice.size(); i ++) {
slice.set(i, slice.get(i).slice());
}
return slice;
}
@Override
public boolean isDirect() {
int size = components.size();
if (size == 0) {
return false;
}
for (int i = 0; i < size; i++) {
if (!components.get(i).buf.isDirect()) {
return false;
}
}
return true;
}
@Override
public boolean hasArray() {
switch (components.size()) {
case 0:
return true;
case 1:
return components.get(0).buf.hasArray();
default:
return false;
}
}
@Override
public byte[] array() {
switch (components.size()) {
case 0:
return EmptyArrays.EMPTY_BYTES;
case 1:
return components.get(0).buf.array();
default:
throw new UnsupportedOperationException();
}
}
@Override
public int arrayOffset() {
switch (components.size()) {
case 0:
return 0;
case 1:
return components.get(0).buf.arrayOffset();
default:
throw new UnsupportedOperationException();
}
}
@Override
public boolean hasMemoryAddress() {
switch (components.size()) {
case 0:
return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
case 1:
return components.get(0).buf.hasMemoryAddress();
default:
return false;
}
}
@Override
public long memoryAddress() {
switch (components.size()) {
case 0:
return Unpooled.EMPTY_BUFFER.memoryAddress();
case 1:
return components.get(0).buf.memoryAddress();
default:
throw new UnsupportedOperationException();
}
}
@Override
public int capacity() {
final int numComponents = components.size();
if (numComponents == 0) {
return 0;
}
return components.get(numComponents - 1).endOffset;
}
@Override
public CompositeByteBuf capacity(int newCapacity) {
ensureAccessible();
if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity);
}
int oldCapacity = capacity();
if (newCapacity > oldCapacity) {
final int paddingLength = newCapacity - oldCapacity;
ByteBuf padding;
int nComponents = components.size();
if (nComponents < maxNumComponents) {
padding = allocBuffer(paddingLength);
padding.setIndex(0, paddingLength);
addComponent0(components.size(), padding);
} else {
padding = allocBuffer(paddingLength);
padding.setIndex(0, paddingLength);
// FIXME: No need to create a padding buffer and consolidate.
// Just create a big single buffer and put the current content there.
addComponent0(components.size(), padding);
consolidateIfNeeded();
}
} else if (newCapacity < oldCapacity) {
int bytesToTrim = oldCapacity - newCapacity;
for (ListIterator i = components.listIterator(components.size()); i.hasPrevious();) {
Component c = i.previous();
if (bytesToTrim >= c.length) {
bytesToTrim -= c.length;
i.remove();
continue;
}
// Replace the last component with the trimmed slice.
Component newC = new Component(c.buf.slice(0, c.length - bytesToTrim));
newC.offset = c.offset;
newC.endOffset = newC.offset + newC.length;
i.set(newC);
break;
}
if (readerIndex() > newCapacity) {
setIndex(newCapacity, newCapacity);
} else if (writerIndex() > newCapacity) {
writerIndex(newCapacity);
}
}
return this;
}
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
/**
* Return the current number of {@link ByteBuf}'s that are composed in this instance
*/
public int numComponents() {
return components.size();
}
/**
* Return the max number of {@link ByteBuf}'s that are composed in this instance
*/
public int maxNumComponents() {
return maxNumComponents;
}
/**
* Return the index for the given offset
*/
public int toComponentIndex(int offset) {
checkIndex(offset);
for (int low = 0, high = components.size(); low <= high;) {
int mid = low + high >>> 1;
Component c = components.get(mid);
if (offset >= c.endOffset) {
low = mid + 1;
} else if (offset < c.offset) {
high = mid - 1;
} else {
return mid;
}
}
throw new Error("should not reach here");
}
public int toByteIndex(int cIndex) {
checkComponentIndex(cIndex);
return components.get(cIndex).offset;
}
@Override
public byte getByte(int index) {
return _getByte(index);
}
@Override
protected byte _getByte(int index) {
Component c = findComponent(index);
return c.buf.getByte(index - c.offset);
}
@Override
protected short _getShort(int index) {
Component c = findComponent(index);
if (index + 2 <= c.endOffset) {
return c.buf.getShort(index - c.offset);
} else if (order() == ByteOrder.BIG_ENDIAN) {
return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
} else {
return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
}
}
@Override
protected int _getUnsignedMedium(int index) {
Component c = findComponent(index);
if (index + 3 <= c.endOffset) {
return c.buf.getUnsignedMedium(index - c.offset);
} else if (order() == ByteOrder.BIG_ENDIAN) {
return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
} else {
return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
}
}
@Override
protected int _getInt(int index) {
Component c = findComponent(index);
if (index + 4 <= c.endOffset) {
return c.buf.getInt(index - c.offset);
} else if (order() == ByteOrder.BIG_ENDIAN) {
return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
} else {
return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
}
}
@Override
protected long _getLong(int index) {
Component c = findComponent(index);
if (index + 8 <= c.endOffset) {
return c.buf.getLong(index - c.offset);
} else if (order() == ByteOrder.BIG_ENDIAN) {
return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
} else {
return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
}
}
@Override
public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
checkDstIndex(index, length, dstIndex, dst.length);
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
s.getBytes(index - adjustment, dst, dstIndex, localLength);
index += localLength;
dstIndex += localLength;
length -= localLength;
i ++;
}
return this;
}
@Override
public CompositeByteBuf getBytes(int index, ByteBuffer dst) {
int limit = dst.limit();
int length = dst.remaining();
checkIndex(index, length);
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
try {
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
dst.limit(dst.position() + localLength);
s.getBytes(index - adjustment, dst);
index += localLength;
length -= localLength;
i ++;
}
} finally {
dst.limit(limit);
}
return this;
}
@Override
public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
checkDstIndex(index, length, dstIndex, dst.capacity());
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
s.getBytes(index - adjustment, dst, dstIndex, localLength);
index += localLength;
dstIndex += localLength;
length -= localLength;
i ++;
}
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length)
throws IOException {
int count = nioBufferCount();
if (count == 1) {
return out.write(internalNioBuffer(index, length));
} else {
long writtenBytes = out.write(nioBuffers(index, length));
if (writtenBytes > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
} else {
return (int) writtenBytes;
}
}
}
@Override
public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
checkIndex(index, length);
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
s.getBytes(index - adjustment, out, localLength);
index += localLength;
length -= localLength;
i ++;
}
return this;
}
@Override
public CompositeByteBuf setByte(int index, int value) {
Component c = findComponent(index);
c.buf.setByte(index - c.offset, value);
return this;
}
@Override
protected void _setByte(int index, int value) {
setByte(index, value);
}
@Override
public CompositeByteBuf setShort(int index, int value) {
return (CompositeByteBuf) super.setShort(index, value);
}
@Override
protected void _setShort(int index, int value) {
Component c = findComponent(index);
if (index + 2 <= c.endOffset) {
c.buf.setShort(index - c.offset, value);
} else if (order() == ByteOrder.BIG_ENDIAN) {
_setByte(index, (byte) (value >>> 8));
_setByte(index + 1, (byte) value);
} else {
_setByte(index, (byte) value);
_setByte(index + 1, (byte) (value >>> 8));
}
}
@Override
public CompositeByteBuf setMedium(int index, int value) {
return (CompositeByteBuf) super.setMedium(index, value);
}
@Override
protected void _setMedium(int index, int value) {
Component c = findComponent(index);
if (index + 3 <= c.endOffset) {
c.buf.setMedium(index - c.offset, value);
} else if (order() == ByteOrder.BIG_ENDIAN) {
_setShort(index, (short) (value >> 8));
_setByte(index + 2, (byte) value);
} else {
_setShort(index, (short) value);
_setByte(index + 2, (byte) (value >>> 16));
}
}
@Override
public CompositeByteBuf setInt(int index, int value) {
return (CompositeByteBuf) super.setInt(index, value);
}
@Override
protected void _setInt(int index, int value) {
Component c = findComponent(index);
if (index + 4 <= c.endOffset) {
c.buf.setInt(index - c.offset, value);
} else if (order() == ByteOrder.BIG_ENDIAN) {
_setShort(index, (short) (value >>> 16));
_setShort(index + 2, (short) value);
} else {
_setShort(index, (short) value);
_setShort(index + 2, (short) (value >>> 16));
}
}
@Override
public CompositeByteBuf setLong(int index, long value) {
return (CompositeByteBuf) super.setLong(index, value);
}
@Override
protected void _setLong(int index, long value) {
Component c = findComponent(index);
if (index + 8 <= c.endOffset) {
c.buf.setLong(index - c.offset, value);
} else if (order() == ByteOrder.BIG_ENDIAN) {
_setInt(index, (int) (value >>> 32));
_setInt(index + 4, (int) value);
} else {
_setInt(index, (int) value);
_setInt(index + 4, (int) (value >>> 32));
}
}
@Override
public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
s.setBytes(index - adjustment, src, srcIndex, localLength);
index += localLength;
srcIndex += localLength;
length -= localLength;
i ++;
}
return this;
}
@Override
public CompositeByteBuf setBytes(int index, ByteBuffer src) {
int limit = src.limit();
int length = src.remaining();
checkIndex(index, length);
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
try {
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
src.limit(src.position() + localLength);
s.setBytes(index - adjustment, src);
index += localLength;
length -= localLength;
i ++;
}
} finally {
src.limit(limit);
}
return this;
}
@Override
public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.capacity());
if (length == 0) {
return this;
}
int i = toComponentIndex(index);
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
s.setBytes(index - adjustment, src, srcIndex, localLength);
index += localLength;
srcIndex += localLength;
length -= localLength;
i ++;
}
return this;
}
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
checkIndex(index, length);
if (length == 0) {
return in.read(EmptyArrays.EMPTY_BYTES);
}
int i = toComponentIndex(index);
int readBytes = 0;
do {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
int localReadBytes = s.setBytes(index - adjustment, in, localLength);
if (localReadBytes < 0) {
if (readBytes == 0) {
return -1;
} else {
break;
}
}
if (localReadBytes == localLength) {
index += localLength;
length -= localLength;
readBytes += localLength;
i ++;
} else {
index += localReadBytes;
length -= localReadBytes;
readBytes += localReadBytes;
}
} while (length > 0);
return readBytes;
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
checkIndex(index, length);
if (length == 0) {
return in.read(EMPTY_NIO_BUFFER);
}
int i = toComponentIndex(index);
int readBytes = 0;
do {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
int localReadBytes = s.setBytes(index - adjustment, in, localLength);
if (localReadBytes == 0) {
break;
}
if (localReadBytes < 0) {
if (readBytes == 0) {
return -1;
} else {
break;
}
}
if (localReadBytes == localLength) {
index += localLength;
length -= localLength;
readBytes += localLength;
i ++;
} else {
index += localReadBytes;
length -= localReadBytes;
readBytes += localReadBytes;
}
} while (length > 0);
return readBytes;
}
@Override
public ByteBuf copy(int index, int length) {
checkIndex(index, length);
ByteBuf dst = Unpooled.buffer(length);
if (length != 0) {
copyTo(index, length, toComponentIndex(index), dst);
}
return dst;
}
private void copyTo(int index, int length, int componentId, ByteBuf dst) {
int dstIndex = 0;
int i = componentId;
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
s.getBytes(index - adjustment, dst, dstIndex, localLength);
index += localLength;
dstIndex += localLength;
length -= localLength;
i ++;
}
dst.writerIndex(dst.capacity());
}
/**
* Return the {@link ByteBuf} on the specified index
*
* @param cIndex the index for which the {@link ByteBuf} should be returned
* @return buf the {@link ByteBuf} on the specified index
*/
public ByteBuf component(int cIndex) {
return internalComponent(cIndex).duplicate();
}
/**
* Return the {@link ByteBuf} on the specified index
*
* @param offset the offset for which the {@link ByteBuf} should be returned
* @return the {@link ByteBuf} on the specified index
*/
public ByteBuf componentAtOffset(int offset) {
return internalComponentAtOffset(offset).duplicate();
}
/**
* Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
* buffer will lead to an undefined behavior of this buffer.
*
* @param cIndex the index for which the {@link ByteBuf} should be returned
*/
public ByteBuf internalComponent(int cIndex) {
checkComponentIndex(cIndex);
return components.get(cIndex).buf;
}
/**
* Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
* buffer will lead to an undefined behavior of this buffer.
*
* @param offset the offset for which the {@link ByteBuf} should be returned
*/
public ByteBuf internalComponentAtOffset(int offset) {
return findComponent(offset).buf;
}
private Component findComponent(int offset) {
checkIndex(offset);
for (int low = 0, high = components.size(); low <= high;) {
int mid = low + high >>> 1;
Component c = components.get(mid);
if (offset >= c.endOffset) {
low = mid + 1;
} else if (offset < c.offset) {
high = mid - 1;
} else {
assert c.length != 0;
return c;
}
}
throw new Error("should not reach here");
}
@Override
public int nioBufferCount() {
switch (components.size()) {
case 0:
return 1;
case 1:
return components.get(0).buf.nioBufferCount();
default:
int count = 0;
int componentsCount = components.size();
for (int i = 0; i < componentsCount; i++) {
Component c = components.get(i);
count += c.buf.nioBufferCount();
}
return count;
}
}
@Override
public ByteBuffer internalNioBuffer(int index, int length) {
switch (components.size()) {
case 0:
return EMPTY_NIO_BUFFER;
case 1:
return components.get(0).buf.internalNioBuffer(index, length);
default:
throw new UnsupportedOperationException();
}
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
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);
for (ByteBuffer buf: buffers) {
merged.put(buf);
}
merged.flip();
return merged;
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
checkIndex(index, length);
if (length == 0) {
return new ByteBuffer[] { EMPTY_NIO_BUFFER };
}
List buffers = new ArrayList(components.size());
int i = toComponentIndex(index);
while (length > 0) {
Component c = components.get(i);
ByteBuf s = c.buf;
int adjustment = c.offset;
int localLength = Math.min(length, s.capacity() - (index - adjustment));
switch (s.nioBufferCount()) {
case 0:
throw new UnsupportedOperationException();
case 1:
buffers.add(s.nioBuffer(index - adjustment, localLength));
break;
default:
Collections.addAll(buffers, s.nioBuffers(index - adjustment, localLength));
}
index += localLength;
length -= localLength;
i ++;
}
return buffers.toArray(new ByteBuffer[buffers.size()]);
}
/**
* Consolidate the composed {@link ByteBuf}s
*/
public CompositeByteBuf consolidate() {
ensureAccessible();
final int numComponents = numComponents();
if (numComponents <= 1) {
return this;
}
final Component last = components.get(numComponents - 1);
final int capacity = last.endOffset;
final ByteBuf consolidated = allocBuffer(capacity);
for (int i = 0; i < numComponents; i ++) {
Component c = components.get(i);
ByteBuf b = c.buf;
consolidated.writeBytes(b);
c.freeIfNecessary();
}
components.clear();
components.add(new Component(consolidated));
updateComponentOffsets(0);
return this;
}
/**
* Consolidate the composed {@link ByteBuf}s
*
* @param cIndex the index on which to start to compose
* @param numComponents the number of components to compose
*/
public CompositeByteBuf consolidate(int cIndex, int numComponents) {
checkComponentIndex(cIndex, numComponents);
if (numComponents <= 1) {
return this;
}
final int endCIndex = cIndex + numComponents;
final Component last = components.get(endCIndex - 1);
final int capacity = last.endOffset - components.get(cIndex).offset;
final ByteBuf consolidated = allocBuffer(capacity);
for (int i = cIndex; i < endCIndex; i ++) {
Component c = components.get(i);
ByteBuf b = c.buf;
consolidated.writeBytes(b);
c.freeIfNecessary();
}
components.subList(cIndex + 1, endCIndex).clear();
components.set(cIndex, new Component(consolidated));
updateComponentOffsets(cIndex);
return this;
}
/**
* Discard all {@link ByteBuf}s which are read.
*/
public CompositeByteBuf discardReadComponents() {
ensureAccessible();
final int readerIndex = readerIndex();
if (readerIndex == 0) {
return this;
}
// Discard everything if (readerIndex = writerIndex = capacity).
int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) {
c.freeIfNecessary();
}
components.clear();
setIndex(0, 0);
adjustMarkers(readerIndex);
return this;
}
// Remove read components.
int firstComponentId = toComponentIndex(readerIndex);
for (int i = 0; i < firstComponentId; i ++) {
components.get(i).freeIfNecessary();
}
components.subList(0, firstComponentId).clear();
// Update indexes and markers.
Component first = components.get(0);
int offset = first.offset;
updateComponentOffsets(0);
setIndex(readerIndex - offset, writerIndex - offset);
adjustMarkers(offset);
return this;
}
@Override
public CompositeByteBuf discardReadBytes() {
ensureAccessible();
final int readerIndex = readerIndex();
if (readerIndex == 0) {
return this;
}
// Discard everything if (readerIndex = writerIndex = capacity).
int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) {
c.freeIfNecessary();
}
components.clear();
setIndex(0, 0);
adjustMarkers(readerIndex);
return this;
}
// Remove read components.
int firstComponentId = toComponentIndex(readerIndex);
for (int i = 0; i < firstComponentId; i ++) {
components.get(i).freeIfNecessary();
}
components.subList(0, firstComponentId).clear();
// Remove or replace the first readable component with a new slice.
Component c = components.get(0);
int adjustment = readerIndex - c.offset;
if (adjustment == c.length) {
// new slice would be empty, so remove instead
components.remove(0);
} else {
Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment));
components.set(0, newC);
}
// Update indexes and markers.
updateComponentOffsets(0);
setIndex(0, writerIndex - readerIndex);
adjustMarkers(readerIndex);
return this;
}
private ByteBuf allocBuffer(int capacity) {
if (direct) {
return alloc().directBuffer(capacity);
}
return alloc().heapBuffer(capacity);
}
@Override
public String toString() {
String result = super.toString();
result = result.substring(0, result.length() - 1);
return result + ", components=" + components.size() + ')';
}
private static final class Component {
final ByteBuf buf;
final int length;
int offset;
int endOffset;
Component(ByteBuf buf) {
this.buf = buf;
length = buf.readableBytes();
}
void freeIfNecessary() {
// Unwrap so that we can free slices, too.
buf.release(); // We should not get a NPE here. If so, it must be a bug.
}
}
@Override
public CompositeByteBuf readerIndex(int readerIndex) {
return (CompositeByteBuf) super.readerIndex(readerIndex);
}
@Override
public CompositeByteBuf writerIndex(int writerIndex) {
return (CompositeByteBuf) super.writerIndex(writerIndex);
}
@Override
public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
return (CompositeByteBuf) super.setIndex(readerIndex, writerIndex);
}
@Override
public CompositeByteBuf clear() {
return (CompositeByteBuf) super.clear();
}
@Override
public CompositeByteBuf markReaderIndex() {
return (CompositeByteBuf) super.markReaderIndex();
}
@Override
public CompositeByteBuf resetReaderIndex() {
return (CompositeByteBuf) super.resetReaderIndex();
}
@Override
public CompositeByteBuf markWriterIndex() {
return (CompositeByteBuf) super.markWriterIndex();
}
@Override
public CompositeByteBuf resetWriterIndex() {
return (CompositeByteBuf) super.resetWriterIndex();
}
@Override
public CompositeByteBuf ensureWritable(int minWritableBytes) {
return (CompositeByteBuf) super.ensureWritable(minWritableBytes);
}
@Override
public CompositeByteBuf getBytes(int index, ByteBuf dst) {
return (CompositeByteBuf) super.getBytes(index, dst);
}
@Override
public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
return (CompositeByteBuf) super.getBytes(index, dst, length);
}
@Override
public CompositeByteBuf getBytes(int index, byte[] dst) {
return (CompositeByteBuf) super.getBytes(index, dst);
}
@Override
public CompositeByteBuf setBoolean(int index, boolean value) {
return (CompositeByteBuf) super.setBoolean(index, value);
}
@Override
public CompositeByteBuf setChar(int index, int value) {
return (CompositeByteBuf) super.setChar(index, value);
}
@Override
public CompositeByteBuf setFloat(int index, float value) {
return (CompositeByteBuf) super.setFloat(index, value);
}
@Override
public CompositeByteBuf setDouble(int index, double value) {
return (CompositeByteBuf) super.setDouble(index, value);
}
@Override
public CompositeByteBuf setBytes(int index, ByteBuf src) {
return (CompositeByteBuf) super.setBytes(index, src);
}
@Override
public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
return (CompositeByteBuf) super.setBytes(index, src, length);
}
@Override
public CompositeByteBuf setBytes(int index, byte[] src) {
return (CompositeByteBuf) super.setBytes(index, src);
}
@Override
public CompositeByteBuf setZero(int index, int length) {
return (CompositeByteBuf) super.setZero(index, length);
}
@Override
public CompositeByteBuf readBytes(ByteBuf dst) {
return (CompositeByteBuf) super.readBytes(dst);
}
@Override
public CompositeByteBuf readBytes(ByteBuf dst, int length) {
return (CompositeByteBuf) super.readBytes(dst, length);
}
@Override
public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
return (CompositeByteBuf) super.readBytes(dst, dstIndex, length);
}
@Override
public CompositeByteBuf readBytes(byte[] dst) {
return (CompositeByteBuf) super.readBytes(dst);
}
@Override
public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
return (CompositeByteBuf) super.readBytes(dst, dstIndex, length);
}
@Override
public CompositeByteBuf readBytes(ByteBuffer dst) {
return (CompositeByteBuf) super.readBytes(dst);
}
@Override
public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
return (CompositeByteBuf) super.readBytes(out, length);
}
@Override
public CompositeByteBuf skipBytes(int length) {
return (CompositeByteBuf) super.skipBytes(length);
}
@Override
public CompositeByteBuf writeBoolean(boolean value) {
return (CompositeByteBuf) super.writeBoolean(value);
}
@Override
public CompositeByteBuf writeByte(int value) {
return (CompositeByteBuf) super.writeByte(value);
}
@Override
public CompositeByteBuf writeShort(int value) {
return (CompositeByteBuf) super.writeShort(value);
}
@Override
public CompositeByteBuf writeMedium(int value) {
return (CompositeByteBuf) super.writeMedium(value);
}
@Override
public CompositeByteBuf writeInt(int value) {
return (CompositeByteBuf) super.writeInt(value);
}
@Override
public CompositeByteBuf writeLong(long value) {
return (CompositeByteBuf) super.writeLong(value);
}
@Override
public CompositeByteBuf writeChar(int value) {
return (CompositeByteBuf) super.writeChar(value);
}
@Override
public CompositeByteBuf writeFloat(float value) {
return (CompositeByteBuf) super.writeFloat(value);
}
@Override
public CompositeByteBuf writeDouble(double value) {
return (CompositeByteBuf) super.writeDouble(value);
}
@Override
public CompositeByteBuf writeBytes(ByteBuf src) {
return (CompositeByteBuf) super.writeBytes(src);
}
@Override
public CompositeByteBuf writeBytes(ByteBuf src, int length) {
return (CompositeByteBuf) super.writeBytes(src, length);
}
@Override
public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
return (CompositeByteBuf) super.writeBytes(src, srcIndex, length);
}
@Override
public CompositeByteBuf writeBytes(byte[] src) {
return (CompositeByteBuf) super.writeBytes(src);
}
@Override
public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
return (CompositeByteBuf) super.writeBytes(src, srcIndex, length);
}
@Override
public CompositeByteBuf writeBytes(ByteBuffer src) {
return (CompositeByteBuf) super.writeBytes(src);
}
@Override
public CompositeByteBuf writeZero(int length) {
return (CompositeByteBuf) super.writeZero(length);
}
@Override
public CompositeByteBuf retain(int increment) {
return (CompositeByteBuf) super.retain(increment);
}
@Override
public CompositeByteBuf retain() {
return (CompositeByteBuf) super.retain();
}
@Override
public ByteBuffer[] nioBuffers() {
return nioBuffers(readerIndex(), readableBytes());
}
@Override
public CompositeByteBuf discardSomeReadBytes() {
return discardReadComponents();
}
@Override
protected void deallocate() {
if (freed) {
return;
}
freed = true;
int size = components.size();
// We're not using foreach to avoid creating an iterator.
// see https://github.com/netty/netty/issues/2642
for (int i = 0; i < size; i++) {
components.get(i).freeIfNecessary();
}
if (leak != null) {
leak.close();
}
}
@Override
public ByteBuf unwrap() {
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy