All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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).

There is a newer version: 35.0.0.Beta1
Show newest version
/*
 * 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.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.FileChannel;
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.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;

import static io.netty.util.internal.ObjectUtil.checkNotNull;

/**
 * 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 implements Iterable {

    private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
    private static final Iterator EMPTY_ITERATOR = Collections.emptyList().iterator();

    private final ByteBufAllocator alloc;
    private final boolean direct;
    private final ComponentList components;
    private final int maxNumComponents;

    private boolean freed;

    public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) {
        super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
        if (alloc == null) {
            throw new NullPointerException("alloc");
        }
        this.alloc = alloc;
        this.direct = direct;
        this.maxNumComponents = maxNumComponents;
        components = newList(0, maxNumComponents);
    }

    public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf... buffers) {
        this(alloc, direct, maxNumComponents, buffers, 0, buffers.length);
    }

    CompositeByteBuf(
            ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf[] buffers, int offset, int len) {
        super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
        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;
        components = newList(len, maxNumComponents);

        addComponents0(false, 0, buffers, offset, len);
        consolidateIfNeeded();
        setIndex(0, capacity());
    }

    public CompositeByteBuf(
            ByteBufAllocator alloc, boolean direct, int maxNumComponents, Iterable buffers) {
        super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
        if (alloc == null) {
            throw new NullPointerException("alloc");
        }
        if (maxNumComponents < 2) {
            throw new IllegalArgumentException(
                    "maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
        }

        int len = buffers instanceof Collection ? ((Collection) buffers).size() : 0;

        this.alloc = alloc;
        this.direct = direct;
        this.maxNumComponents = maxNumComponents;
        components = newList(len, maxNumComponents);

        addComponents0(false, 0, buffers);
        consolidateIfNeeded();
        setIndex(0, capacity());
    }

    private static ComponentList newList(int initComponents, int maxNumComponents) {
        int capacityGuess = Math.min(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS, maxNumComponents);
        return new ComponentList(Math.max(initComponents, capacityGuess));
    }

    // Special constructor used by WrappedCompositeByteBuf
    CompositeByteBuf(ByteBufAllocator alloc) {
        super(Integer.MAX_VALUE);
        this.alloc = alloc;
        direct = false;
        maxNumComponents = 0;
        components = null;
    }

    /**
     * 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 use {@link #addComponent(boolean, ByteBuf)}. *

* {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}. * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this * {@link CompositeByteBuf}. */ public CompositeByteBuf addComponent(ByteBuf buffer) { return addComponent(false, buffer); } /** * 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 use {@link #addComponents(boolean, ByteBuf[])}. *

* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this * {@link CompositeByteBuf}. * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()} * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}. */ public CompositeByteBuf addComponents(ByteBuf... buffers) { return addComponents(false, buffers); } /** * 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 use {@link #addComponents(boolean, Iterable)}. *

* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this * {@link CompositeByteBuf}. * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()} * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}. */ public CompositeByteBuf addComponents(Iterable buffers) { return addComponents(false, buffers); } /** * 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 use {@link #addComponent(boolean, int, ByteBuf)}. *

* {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}. * @param cIndex the index on which the {@link ByteBuf} will be added. * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this * {@link CompositeByteBuf}. */ public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) { return addComponent(false, cIndex, buffer); } /** * Add the given {@link ByteBuf} and increase the {@code writerIndex} if {@code increaseWriterIndex} is * {@code true}. * * {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}. * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this * {@link CompositeByteBuf}. */ public CompositeByteBuf addComponent(boolean increaseWriterIndex, ByteBuf buffer) { checkNotNull(buffer, "buffer"); addComponent0(increaseWriterIndex, components.size(), buffer); consolidateIfNeeded(); return this; } /** * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is * {@code true}. * * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this * {@link CompositeByteBuf}. * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()} * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}. */ public CompositeByteBuf addComponents(boolean increaseWriterIndex, ByteBuf... buffers) { addComponents0(increaseWriterIndex, components.size(), buffers, 0, buffers.length); consolidateIfNeeded(); return this; } /** * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is * {@code true}. * * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this * {@link CompositeByteBuf}. * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()} * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}. */ public CompositeByteBuf addComponents(boolean increaseWriterIndex, Iterable buffers) { addComponents0(increaseWriterIndex, components.size(), buffers); consolidateIfNeeded(); return this; } /** * Add the given {@link ByteBuf} on the specific index and increase the {@code writerIndex} * if {@code increaseWriterIndex} is {@code true}. * * {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}. * @param cIndex the index on which the {@link ByteBuf} will be added. * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this * {@link CompositeByteBuf}. */ public CompositeByteBuf addComponent(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) { checkNotNull(buffer, "buffer"); addComponent0(increaseWriterIndex, cIndex, buffer); consolidateIfNeeded(); return this; } /** * Precondition is that {@code buffer != null}. */ private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) { assert buffer != null; boolean wasAdded = false; try { checkComponentIndex(cIndex); int readableBytes = buffer.readableBytes(); // No need to consolidate - just add a component to the list. @SuppressWarnings("deprecation") Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice()); if (cIndex == components.size()) { wasAdded = 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); wasAdded = true; if (readableBytes != 0) { updateComponentOffsets(cIndex); } } if (increaseWriterIndex) { writerIndex(writerIndex() + buffer.readableBytes()); } return cIndex; } finally { if (!wasAdded) { buffer.release(); } } } /** * 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. *

* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this * {@link CompositeByteBuf}. * @param cIndex the index on which the {@link ByteBuf} will be added. {@link ByteBuf#release()} ownership of all * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transfered to this * {@link CompositeByteBuf}. * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()} * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}. */ public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) { addComponents0(false, cIndex, buffers, 0, buffers.length); consolidateIfNeeded(); return this; } private int addComponents0(boolean increaseWriterIndex, int cIndex, ByteBuf[] buffers, int offset, int len) { checkNotNull(buffers, "buffers"); int i = offset; try { checkComponentIndex(cIndex); // No need for consolidation while (i < len) { // Increment i now to prepare for the next iteration and prevent a duplicate release (addComponent0 // will release if an exception occurs, and we also release in the finally block here). ByteBuf b = buffers[i++]; if (b == null) { break; } cIndex = addComponent0(increaseWriterIndex, cIndex, b) + 1; int size = components.size(); if (cIndex > size) { cIndex = size; } } return cIndex; } finally { for (; i < len; ++i) { ByteBuf b = buffers[i]; if (b != null) { try { b.release(); } catch (Throwable ignored) { // ignore } } } } } /** * 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. *

* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this * {@link CompositeByteBuf}. * @param cIndex the index on which the {@link ByteBuf} will be added. * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transfered to this * {@link CompositeByteBuf}. */ public CompositeByteBuf addComponents(int cIndex, Iterable buffers) { addComponents0(false, cIndex, buffers); consolidateIfNeeded(); return this; } private int addComponents0(boolean increaseIndex, int cIndex, Iterable buffers) { if (buffers instanceof ByteBuf) { // If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf). return addComponent0(increaseIndex, cIndex, (ByteBuf) buffers); } checkNotNull(buffers, "buffers"); if (!(buffers instanceof Collection)) { List list = new ArrayList(); try { for (ByteBuf b: buffers) { list.add(b); } buffers = list; } finally { if (buffers != list) { for (ByteBuf b: buffers) { if (b != null) { try { b.release(); } catch (Throwable ignored) { // ignore } } } } } } Collection col = (Collection) buffers; return addComponents0(increaseIndex, cIndex, col.toArray(new ByteBuf[0]), 0 , 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; } int endIndex = cIndex + numComponents; boolean needsUpdate = false; for (int i = cIndex; i < endIndex; ++i) { Component c = components.get(i); if (c.length > 0) { needsUpdate = true; } c.freeIfNecessary(); } components.removeRange(cIndex, endIndex); if (needsUpdate) { // Only need to call updateComponentOffsets if the length was > 0 updateComponentOffsets(cIndex); } return this; } @Override public Iterator iterator() { ensureAccessible(); if (components.isEmpty()) { return EMPTY_ITERATOR; } return new CompositeByteBufIterator(); } /** * 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) { checkNewCapacity(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(false, 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(false, 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 short _getShortLE(int index) { Component c = findComponent(index); if (index + 2 <= c.endOffset) { return c.buf.getShortLE(index - c.offset); } else if (order() == ByteOrder.BIG_ENDIAN) { return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8); } else { return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff); } } @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 _getUnsignedMediumLE(int index) { Component c = findComponent(index); if (index + 3 <= c.endOffset) { return c.buf.getUnsignedMediumLE(index - c.offset); } else if (order() == ByteOrder.BIG_ENDIAN) { return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16; } else { return (_getShortLE(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff; } } @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 int _getIntLE(int index) { Component c = findComponent(index); if (index + 4 <= c.endOffset) { return c.buf.getIntLE(index - c.offset); } else if (order() == ByteOrder.BIG_ENDIAN) { return _getShortLE(index) & 0xffff | (_getShortLE(index + 2) & 0xffff) << 16; } else { return (_getShortLE(index) & 0xffff) << 16 | _getShortLE(index + 2) & 0xffff; } } @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 protected long _getLongLE(int index) { Component c = findComponent(index); if (index + 8 <= c.endOffset) { return c.buf.getLongLE(index - c.offset); } else if (order() == ByteOrder.BIG_ENDIAN) { return _getIntLE(index) & 0xffffffffL | (_getIntLE(index + 4) & 0xffffffffL) << 32; } else { return (_getIntLE(index) & 0xffffffffL) << 32 | _getIntLE(index + 4) & 0xffffffffL; } } @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 int getBytes(int index, FileChannel out, long position, int length) throws IOException { int count = nioBufferCount(); if (count == 1) { return out.write(internalNioBuffer(index, length), position); } else { long writtenBytes = 0; for (ByteBuffer buf : nioBuffers(index, length)) { writtenBytes += out.write(buf, position + writtenBytes); } if (writtenBytes > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } 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 protected void _setShortLE(int index, int value) { Component c = findComponent(index); if (index + 2 <= c.endOffset) { c.buf.setShortLE(index - c.offset, value); } else if (order() == ByteOrder.BIG_ENDIAN) { _setByte(index, (byte) value); _setByte(index + 1, (byte) (value >>> 8)); } else { _setByte(index, (byte) (value >>> 8)); _setByte(index + 1, (byte) value); } } @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 protected void _setMediumLE(int index, int value) { Component c = findComponent(index); if (index + 3 <= c.endOffset) { c.buf.setMediumLE(index - c.offset, value); } else if (order() == ByteOrder.BIG_ENDIAN) { _setShortLE(index, (short) value); _setByte(index + 2, (byte) (value >>> 16)); } else { _setShortLE(index, (short) (value >> 8)); _setByte(index + 2, (byte) value); } } @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 protected void _setIntLE(int index, int value) { Component c = findComponent(index); if (index + 4 <= c.endOffset) { c.buf.setIntLE(index - c.offset, value); } else if (order() == ByteOrder.BIG_ENDIAN) { _setShortLE(index, (short) value); _setShortLE(index + 2, (short) (value >>> 16)); } else { _setShortLE(index, (short) (value >>> 16)); _setShortLE(index + 2, (short) value); } } @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 protected void _setLongLE(int index, long value) { Component c = findComponent(index); if (index + 8 <= c.endOffset) { c.buf.setLongLE(index - c.offset, value); } else if (order() == ByteOrder.BIG_ENDIAN) { _setIntLE(index, (int) value); _setIntLE(index + 4, (int) (value >>> 32)); } else { _setIntLE(index, (int) (value >>> 32)); _setIntLE(index + 4, (int) value); } } @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)); if (localLength == 0) { // Skip empty buffer i++; continue; } 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)); if (localLength == 0) { // Skip empty buffer i++; continue; } 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 int setBytes(int index, FileChannel in, long position, int length) throws IOException { checkIndex(index, length); if (length == 0) { return in.read(EMPTY_NIO_BUFFER, position); } 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)); if (localLength == 0) { // Skip empty buffer i++; continue; } int localReadBytes = s.setBytes(index - adjustment, in, position + readBytes, 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 = allocBuffer(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[] buffers = nioBuffers(index, length); if (buffers.length == 1) { return buffers[0].duplicate(); } ByteBuffer merged = ByteBuffer.allocate(length).order(order()); 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[0]); } /** * 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.removeRange(cIndex + 1, endCIndex); 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()) { int size = components.size(); for (int i = 0; i < size; i++) { components.get(i).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.removeRange(0, firstComponentId); // 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()) { int size = components.size(); for (int i = 0; i < size; i++) { components.get(i).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(); } // Remove or replace the first readable component with a new slice. Component c = components.get(firstComponentId); int adjustment = readerIndex - c.offset; if (adjustment == c.length) { // new slice would be empty, so remove instead firstComponentId++; } else { Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment)); components.set(firstComponentId, newC); } components.removeRange(0, firstComponentId); // Update indexes and markers. updateComponentOffsets(0); setIndex(0, writerIndex - readerIndex); adjustMarkers(readerIndex); return this; } private ByteBuf allocBuffer(int capacity) { return direct ? alloc().directBuffer(capacity) : 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() { 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 CompositeByteBuf touch() { return this; } @Override public CompositeByteBuf touch(Object hint) { return this; } @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(); } } @Override public ByteBuf unwrap() { return null; } private final class CompositeByteBufIterator implements Iterator { 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"); } } private static final class ComponentList extends ArrayList { ComponentList(int initialCapacity) { super(initialCapacity); } // Expose this methods so we not need to create a new subList just to remove a range of elements. @Override public void removeRange(int fromIndex, int toIndex) { super.removeRange(fromIndex, toIndex); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy