private int addComponents0(int cIndex, ByteBuf... buffers) { checkComponentIndex(cIndex); if (buffers == null) { throw new NullPointerException("buffers"); } int readableBytes = 0; for (ByteBuf b : buffers) { if (b == null) { break; } readableBytes += b.readableBytes(); } if (readableBytes == 0) { return cIndex; } // No need for consolidation for (ByteBuf b : buffers) { if (b == null) { break; } if (b.isReadable()) { cIndex = addComponent0(cIndex, b, false) + 1; int size = components.size(); if (cIndex > size) { cIndex = size; } } } return cIndex; }
@Test public void testCompositeWrappedBuffer() { ByteBuf header = buffer(12).order(order); ByteBuf payload = buffer(512).order(order); header.writeBytes(new byte[12]); payload.writeBytes(new byte[512]); ByteBuf buffer = wrappedBuffer(header, payload); assertEquals(12, header.readableBytes()); assertEquals(512, payload.readableBytes()); assertEquals(12 + 512, buffer.readableBytes()); assertEquals(2, buffer.nioBufferCount()); }
private int addComponent0(int cIndex, ByteBuf buffer, boolean addedBySelf) { checkComponentIndex(cIndex); if (buffer == null) { throw new NullPointerException("buffer"); } if (buffer instanceof Iterable) { @SuppressWarnings("unchecked") Iterable<ByteBuf> composite = (Iterable<ByteBuf>) buffer; return addComponents0(cIndex, composite); } int readableBytes = buffer.readableBytes(); if (readableBytes == 0) { return cIndex; } // No need to consolidate - just add a component to the list. Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice(), addedBySelf); 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); updateComponentOffsets(cIndex); } return cIndex; }
@Override public void addComponent(int cIndex, ByteBuf buffer) { checkComponentIndex(cIndex); if (buffer == null) { throw new NullPointerException("buffer"); } if (buffer instanceof Iterable) { @SuppressWarnings("unchecked") Iterable<ByteBuf> composite = (Iterable<ByteBuf>) buffer; addComponents(cIndex, composite); return; } int readableBytes = buffer.readableBytes(); if (readableBytes == 0) { return; } // 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 + readableBytes; ByteBuf consolidated = buffer.unsafe().newBuffer(capacity); for (int i = 0; i < numComponents; i++) { ByteBuf b = components.get(i).buf; consolidated.writeBytes(b); b.unsafe().release(); } consolidated.writeBytes(buffer, buffer.readerIndex(), readableBytes); Component c = new Component(consolidated); c.endOffset = c.length; components.clear(); components.add(c); return; } // 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); updateComponentOffsets(cIndex); } }
/** * Creates a new buffer whose content is a merged copy of the specified {@code buffers}' readable * bytes. The new buffer's {@code readerIndex} and {@code writerIndex} are {@code 0} and the sum * of all buffers' {@code readableBytes} respectively. * * @throws IllegalArgumentException if the specified buffers' endianness are different from each * other */ public static ByteBuf copiedBuffer(ByteBuf... buffers) { switch (buffers.length) { case 0: return EMPTY_BUFFER; case 1: return copiedBuffer(buffers[0]); } // Merge the specified buffers into one buffer. ByteOrder order = null; int length = 0; for (ByteBuf b : buffers) { int bLen = b.readableBytes(); if (bLen <= 0) { continue; } if (Integer.MAX_VALUE - length < bLen) { throw new IllegalArgumentException("The total length of the specified buffers is too big."); } length += bLen; if (order != null) { if (!order.equals(b.order())) { throw new IllegalArgumentException("inconsistent byte order"); } } else { order = b.order(); } } if (length == 0) { return EMPTY_BUFFER; } byte[] mergedArray = new byte[length]; for (int i = 0, j = 0; i < buffers.length; i++) { ByteBuf b = buffers[i]; int bLen = b.readableBytes(); b.getBytes(b.readerIndex(), mergedArray, j, bLen); j += bLen; } return wrappedBuffer(mergedArray).order(order); }
/** * Creates a new buffer whose content is a copy of the specified {@code buffer}'s readable bytes. * The new buffer's {@code readerIndex} and {@code writerIndex} are {@code 0} and {@code * buffer.readableBytes} respectively. */ public static ByteBuf copiedBuffer(ByteBuf buffer) { int readable = buffer.readableBytes(); if (readable > 0) { ByteBuf copy = buffer(readable); copy.writeBytes(buffer, buffer.readerIndex(), readable); return copy; } else { return EMPTY_BUFFER; } }
@Override public List<ByteBuf> decompose(int offset, int length) { if (length == 0) { return Collections.emptyList(); } if (offset + length > capacity()) { throw new IndexOutOfBoundsException( "Too many bytes to decompose - Need " + (offset + length) + ", capacity is " + capacity()); } int componentId = toComponentIndex(offset); List<ByteBuf> slice = new ArrayList<ByteBuf>(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; }
/** Tests the "getBufferFor" method */ @Test public void testComponentAtOffset() { CompositeByteBuf buf = (CompositeByteBuf) wrappedBuffer(new byte[] {1, 2, 3, 4, 5}, new byte[] {4, 5, 6, 7, 8, 9, 26}); // Ensure that a random place will be fine assertEquals(5, buf.componentAtOffset(2).capacity()); // Loop through each byte byte index = 0; while (index < buf.capacity()) { ByteBuf _buf = buf.componentAtOffset(index++); assertNotNull(_buf); assertTrue(_buf.capacity() > 0); assertNotNull(_buf.getByte(0)); assertNotNull(_buf.getByte(_buf.readableBytes() - 1)); } }
@Override protected ByteBuf newBuffer(int length) { buffers = new ArrayList<ByteBuf>(); for (int i = 0; i < length + 45; i += 45) { buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[1])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[2])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[3])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[4])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[5])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[6])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[7])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[8])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(new byte[9])); buffers.add(EMPTY_BUFFER); } buffer = Unpooled.wrappedBuffer(Integer.MAX_VALUE, buffers.toArray(new ByteBuf[buffers.size()])) .order(order); // Truncate to the requested capacity. buffer.capacity(length); assertEquals(length, buffer.capacity()); assertEquals(length, buffer.readableBytes()); assertFalse(buffer.isWritable()); buffer.writerIndex(0); return buffer; }
@Override public int readableBytes() { return buf.readableBytes(); }
Component(ByteBuf buf, boolean allocatedBySelf) { this.buf = buf; length = buf.readableBytes(); this.allocatedBySelf = allocatedBySelf; }
@Override public void addComponents(int cIndex, ByteBuf... buffers) { checkComponentIndex(cIndex); if (buffers == null) { throw new NullPointerException("buffers"); } ByteBuf lastBuf = null; int cnt = 0; int readableBytes = 0; for (ByteBuf b : buffers) { if (b == null) { break; } lastBuf = b; cnt++; readableBytes += b.readableBytes(); } if (readableBytes == 0) { return; } // Consolidate if the number of components will exceed the maximum by this operation. final int numComponents = components.size(); if (numComponents + cnt > maxNumComponents) { final ByteBuf consolidated; if (numComponents != 0) { final int capacity = components.get(numComponents - 1).endOffset + readableBytes; consolidated = lastBuf.unsafe().newBuffer(capacity); for (int i = 0; i < cIndex; i++) { ByteBuf b = components.get(i).buf; consolidated.writeBytes(b); b.unsafe().release(); } for (ByteBuf b : buffers) { if (b == null) { break; } consolidated.writeBytes(b, b.readerIndex(), b.readableBytes()); } for (int i = cIndex; i < numComponents; i++) { ByteBuf b = components.get(i).buf; consolidated.writeBytes(b); b.unsafe().release(); } } else { consolidated = lastBuf.unsafe().newBuffer(readableBytes); for (ByteBuf b : buffers) { if (b == null) { break; } consolidated.writeBytes(b, b.readerIndex(), b.readableBytes()); } } Component c = new Component(consolidated); c.endOffset = c.length; components.clear(); components.add(c); updateComponentOffsets(0); return; } // No need for consolidation for (ByteBuf b : buffers) { if (b == null) { break; } if (b.readable()) { addComponent(cIndex++, b); } } }
Component(ByteBuf buf) { this.buf = buf; length = buf.readableBytes(); }
private static void testDecodeString(String text, Charset charset) { ByteBuf buffer = Unpooled.copiedBuffer(text, charset); Assert.assertEquals(text, ByteBufUtil.decodeString(buffer, 0, buffer.readableBytes(), charset)); buffer.release(); }