View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.util.ByteProcessor;
19  import io.netty.util.IllegalReferenceCountException;
20  import io.netty.util.ReferenceCountUtil;
21  import io.netty.util.internal.EmptyArrays;
22  import io.netty.util.internal.ObjectUtil;
23  import io.netty.util.internal.RecyclableArrayList;
24  
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.OutputStream;
28  import java.nio.ByteBuffer;
29  import java.nio.ByteOrder;
30  import java.nio.channels.FileChannel;
31  import java.nio.channels.GatheringByteChannel;
32  import java.nio.channels.ScatteringByteChannel;
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.Collection;
36  import java.util.Collections;
37  import java.util.ConcurrentModificationException;
38  import java.util.Iterator;
39  import java.util.List;
40  import java.util.NoSuchElementException;
41  
42  import static io.netty.util.internal.ObjectUtil.checkNotNull;
43  
44  /**
45   * A virtual buffer which shows multiple buffers as a single merged buffer.  It is recommended to use
46   * {@link ByteBufAllocator#compositeBuffer()} or {@link Unpooled#wrappedBuffer(ByteBuf...)} instead of calling the
47   * constructor explicitly.
48   */
49  public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf> {
50  
51      private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
52      private static final Iterator<ByteBuf> EMPTY_ITERATOR = Collections.<ByteBuf>emptyList().iterator();
53  
54      private final ByteBufAllocator alloc;
55      private final boolean direct;
56      private final int maxNumComponents;
57  
58      private int componentCount;
59      private Component[] components; // resized when needed
60  
61      private boolean freed;
62  
63      private CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, int initSize) {
64          super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
65  
66          this.alloc = ObjectUtil.checkNotNull(alloc, "alloc");
67          if (maxNumComponents < 1) {
68              throw new IllegalArgumentException(
69                      "maxNumComponents: " + maxNumComponents + " (expected: >= 1)");
70          }
71  
72          this.direct = direct;
73          this.maxNumComponents = maxNumComponents;
74          components = newCompArray(initSize, maxNumComponents);
75      }
76  
77      public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) {
78          this(alloc, direct, maxNumComponents, 0);
79      }
80  
81      public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf... buffers) {
82          this(alloc, direct, maxNumComponents, buffers, 0);
83      }
84  
85      CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents,
86              ByteBuf[] buffers, int offset) {
87          this(alloc, direct, maxNumComponents, buffers.length - offset);
88  
89          addComponents0(false, 0, buffers, offset);
90          consolidateIfNeeded();
91          setIndex0(0, capacity());
92      }
93  
94      public CompositeByteBuf(
95              ByteBufAllocator alloc, boolean direct, int maxNumComponents, Iterable<ByteBuf> buffers) {
96          this(alloc, direct, maxNumComponents,
97                  buffers instanceof Collection ? ((Collection<ByteBuf>) buffers).size() : 0);
98  
99          addComponents(false, 0, buffers);
100         setIndex(0, capacity());
101     }
102 
103     // support passing arrays of other types instead of having to copy to a ByteBuf[] first
104     interface ByteWrapper<T> {
105         ByteBuf wrap(T bytes);
106         boolean isEmpty(T bytes);
107     }
108 
109     static final ByteWrapper<byte[]> BYTE_ARRAY_WRAPPER = new ByteWrapper<byte[]>() {
110         @Override
111         public ByteBuf wrap(byte[] bytes) {
112             return Unpooled.wrappedBuffer(bytes);
113         }
114         @Override
115         public boolean isEmpty(byte[] bytes) {
116             return bytes.length == 0;
117         }
118     };
119 
120     static final ByteWrapper<ByteBuffer> BYTE_BUFFER_WRAPPER = new ByteWrapper<ByteBuffer>() {
121         @Override
122         public ByteBuf wrap(ByteBuffer bytes) {
123             return Unpooled.wrappedBuffer(bytes);
124         }
125         @Override
126         public boolean isEmpty(ByteBuffer bytes) {
127             return !bytes.hasRemaining();
128         }
129     };
130 
131     <T> CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents,
132             ByteWrapper<T> wrapper, T[] buffers, int offset) {
133         this(alloc, direct, maxNumComponents, buffers.length - offset);
134 
135         addComponents0(false, 0, wrapper, buffers, offset);
136         consolidateIfNeeded();
137         setIndex(0, capacity());
138     }
139 
140     private static Component[] newCompArray(int initComponents, int maxNumComponents) {
141         int capacityGuess = Math.min(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS, maxNumComponents);
142         return new Component[Math.max(initComponents, capacityGuess)];
143     }
144 
145     // Special constructor used by WrappedCompositeByteBuf
146     CompositeByteBuf(ByteBufAllocator alloc) {
147         super(Integer.MAX_VALUE);
148         this.alloc = alloc;
149         direct = false;
150         maxNumComponents = 0;
151         components = null;
152     }
153 
154     /**
155      * Add the given {@link ByteBuf}.
156      * <p>
157      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
158      * If you need to have it increased use {@link #addComponent(boolean, ByteBuf)}.
159      * <p>
160      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
161      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
162      * {@link CompositeByteBuf}.
163      */
164     public CompositeByteBuf addComponent(ByteBuf buffer) {
165         return addComponent(false, buffer);
166     }
167 
168     /**
169      * Add the given {@link ByteBuf}s.
170      * <p>
171      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
172      * If you need to have it increased use {@link #addComponents(boolean, ByteBuf[])}.
173      * <p>
174      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
175      * {@link CompositeByteBuf}.
176      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
177      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
178      */
179     public CompositeByteBuf addComponents(ByteBuf... buffers) {
180         return addComponents(false, buffers);
181     }
182 
183     /**
184      * Add the given {@link ByteBuf}s.
185      * <p>
186      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
187      * If you need to have it increased use {@link #addComponents(boolean, Iterable)}.
188      * <p>
189      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
190      * {@link CompositeByteBuf}.
191      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
192      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
193      */
194     public CompositeByteBuf addComponents(Iterable<ByteBuf> buffers) {
195         return addComponents(false, buffers);
196     }
197 
198     /**
199      * Add the given {@link ByteBuf} on the specific index.
200      * <p>
201      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
202      * If you need to have it increased use {@link #addComponent(boolean, int, ByteBuf)}.
203      * <p>
204      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
205      * @param cIndex the index on which the {@link ByteBuf} will be added.
206      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
207      * {@link CompositeByteBuf}.
208      */
209     public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
210         return addComponent(false, cIndex, buffer);
211     }
212 
213     /**
214      * Add the given {@link ByteBuf} and increase the {@code writerIndex} if {@code increaseWriterIndex} is
215      * {@code true}.
216      *
217      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
218      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
219      * {@link CompositeByteBuf}.
220      */
221     public CompositeByteBuf addComponent(boolean increaseWriterIndex, ByteBuf buffer) {
222         return addComponent(increaseWriterIndex, componentCount, buffer);
223     }
224 
225     /**
226      * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is
227      * {@code true}.
228      *
229      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
230      * {@link CompositeByteBuf}.
231      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
232      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
233      */
234     public CompositeByteBuf addComponents(boolean increaseWriterIndex, ByteBuf... buffers) {
235         checkNotNull(buffers, "buffers");
236         addComponents0(increaseWriterIndex, componentCount, buffers, 0);
237         consolidateIfNeeded();
238         return this;
239     }
240 
241     /**
242      * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is
243      * {@code true}.
244      *
245      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
246      * {@link CompositeByteBuf}.
247      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
248      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
249      */
250     public CompositeByteBuf addComponents(boolean increaseWriterIndex, Iterable<ByteBuf> buffers) {
251         return addComponents(increaseWriterIndex, componentCount, buffers);
252     }
253 
254     /**
255      * Add the given {@link ByteBuf} on the specific index and increase the {@code writerIndex}
256      * if {@code increaseWriterIndex} is {@code true}.
257      *
258      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
259      * @param cIndex the index on which the {@link ByteBuf} will be added.
260      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
261      * {@link CompositeByteBuf}.
262      */
263     public CompositeByteBuf addComponent(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
264         checkNotNull(buffer, "buffer");
265         addComponent0(increaseWriterIndex, cIndex, buffer);
266         consolidateIfNeeded();
267         return this;
268     }
269 
270     private static void checkForOverflow(int capacity, int readableBytes) {
271         if (capacity + readableBytes < 0) {
272             throw new IllegalArgumentException("Can't increase by " + readableBytes + " as capacity(" + capacity + ")" +
273                     " would overflow " + Integer.MAX_VALUE);
274         }
275     }
276 
277     /**
278      * Precondition is that {@code buffer != null}.
279      */
280     private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
281         assert buffer != null;
282         boolean wasAdded = false;
283         try {
284             checkComponentIndex(cIndex);
285 
286             // No need to consolidate - just add a component to the list.
287             Component c = newComponent(ensureAccessible(buffer), 0);
288             int readableBytes = c.length();
289 
290             // Check if we would overflow.
291             // See https://github.com/netty/netty/issues/10194
292             checkForOverflow(capacity(), readableBytes);
293 
294             addComp(cIndex, c);
295             wasAdded = true;
296             if (readableBytes > 0 && cIndex < componentCount - 1) {
297                 updateComponentOffsets(cIndex);
298             } else if (cIndex > 0) {
299                 c.reposition(components[cIndex - 1].endOffset);
300             }
301             if (increaseWriterIndex) {
302                 writerIndex += readableBytes;
303             }
304             return cIndex;
305         } finally {
306             if (!wasAdded) {
307                 buffer.release();
308             }
309         }
310     }
311 
312     private static ByteBuf ensureAccessible(final ByteBuf buf) {
313         if (checkAccessible && !buf.isAccessible()) {
314             throw new IllegalReferenceCountException(0);
315         }
316         return buf;
317     }
318 
319     @SuppressWarnings("deprecation")
320     private Component newComponent(final ByteBuf buf, final int offset) {
321         final int srcIndex = buf.readerIndex();
322         final int len = buf.readableBytes();
323 
324         // unpeel any intermediate outer layers (UnreleasableByteBuf, LeakAwareByteBufs, SwappedByteBuf)
325         ByteBuf unwrapped = buf;
326         int unwrappedIndex = srcIndex;
327         while (unwrapped instanceof WrappedByteBuf || unwrapped instanceof SwappedByteBuf) {
328             unwrapped = unwrapped.unwrap();
329         }
330 
331         // unwrap if already sliced
332         if (unwrapped instanceof AbstractUnpooledSlicedByteBuf) {
333             unwrappedIndex += ((AbstractUnpooledSlicedByteBuf) unwrapped).idx(0);
334             unwrapped = unwrapped.unwrap();
335         } else if (unwrapped instanceof PooledSlicedByteBuf) {
336             unwrappedIndex += ((PooledSlicedByteBuf) unwrapped).adjustment;
337             unwrapped = unwrapped.unwrap();
338         } else if (unwrapped instanceof DuplicatedByteBuf || unwrapped instanceof PooledDuplicatedByteBuf) {
339             unwrapped = unwrapped.unwrap();
340         }
341 
342         // We don't need to slice later to expose the internal component if the readable range
343         // is already the entire buffer
344         final ByteBuf slice = buf.capacity() == len ? buf : null;
345 
346         return new Component(buf.order(ByteOrder.BIG_ENDIAN), srcIndex,
347                 unwrapped.order(ByteOrder.BIG_ENDIAN), unwrappedIndex, offset, len, slice);
348     }
349 
350     /**
351      * Add the given {@link ByteBuf}s on the specific index
352      * <p>
353      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
354      * If you need to have it increased you need to handle it by your own.
355      * <p>
356      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
357      * {@link CompositeByteBuf}.
358      * @param cIndex the index on which the {@link ByteBuf} will be added. {@link ByteBuf#release()} ownership of all
359      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transferred to this
360      * {@link CompositeByteBuf}.
361      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
362      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
363      */
364     public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) {
365         checkNotNull(buffers, "buffers");
366         addComponents0(false, cIndex, buffers, 0);
367         consolidateIfNeeded();
368         return this;
369     }
370 
371     private CompositeByteBuf addComponents0(boolean increaseWriterIndex,
372             final int cIndex, ByteBuf[] buffers, int arrOffset) {
373         final int len = buffers.length, count = len - arrOffset;
374 
375         int readableBytes = 0;
376         int capacity = capacity();
377         for (int i = arrOffset; i < buffers.length; i++) {
378             ByteBuf b = buffers[i];
379             if (b == null) {
380                 break;
381             }
382             readableBytes += b.readableBytes();
383 
384             // Check if we would overflow.
385             // See https://github.com/netty/netty/issues/10194
386             checkForOverflow(capacity, readableBytes);
387         }
388         // only set ci after we've shifted so that finally block logic is always correct
389         int ci = Integer.MAX_VALUE;
390         try {
391             checkComponentIndex(cIndex);
392             shiftComps(cIndex, count); // will increase componentCount
393             int nextOffset = cIndex > 0 ? components[cIndex - 1].endOffset : 0;
394             for (ci = cIndex; arrOffset < len; arrOffset++, ci++) {
395                 ByteBuf b = buffers[arrOffset];
396                 if (b == null) {
397                     break;
398                 }
399                 Component c = newComponent(ensureAccessible(b), nextOffset);
400                 components[ci] = c;
401                 nextOffset = c.endOffset;
402             }
403             return this;
404         } finally {
405             // ci is now the index following the last successfully added component
406             if (ci < componentCount) {
407                 if (ci < cIndex + count) {
408                     // we bailed early
409                     removeCompRange(ci, cIndex + count);
410                     for (; arrOffset < len; ++arrOffset) {
411                         ReferenceCountUtil.safeRelease(buffers[arrOffset]);
412                     }
413                 }
414                 updateComponentOffsets(ci); // only need to do this here for components after the added ones
415             }
416             if (increaseWriterIndex && ci > cIndex && ci <= componentCount) {
417                 writerIndex += components[ci - 1].endOffset - components[cIndex].offset;
418             }
419         }
420     }
421 
422     private <T> int addComponents0(boolean increaseWriterIndex, int cIndex,
423             ByteWrapper<T> wrapper, T[] buffers, int offset) {
424         checkComponentIndex(cIndex);
425 
426         // No need for consolidation
427         for (int i = offset, len = buffers.length; i < len; i++) {
428             T b = buffers[i];
429             if (b == null) {
430                 break;
431             }
432             if (!wrapper.isEmpty(b)) {
433                 cIndex = addComponent0(increaseWriterIndex, cIndex, wrapper.wrap(b)) + 1;
434                 int size = componentCount;
435                 if (cIndex > size) {
436                     cIndex = size;
437                 }
438             }
439         }
440         return cIndex;
441     }
442 
443     /**
444      * Add the given {@link ByteBuf}s on the specific index
445      *
446      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
447      * If you need to have it increased you need to handle it by your own.
448      * <p>
449      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
450      * {@link CompositeByteBuf}.
451      * @param cIndex the index on which the {@link ByteBuf} will be added.
452      * @param buffers the {@link ByteBuf}s to add.  {@link ByteBuf#release()} ownership of all
453      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transferred to this
454      * {@link CompositeByteBuf}.
455      */
456     public CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers) {
457         return addComponents(false, cIndex, buffers);
458     }
459 
460     /**
461      * Add the given {@link ByteBuf} and increase the {@code writerIndex} if {@code increaseWriterIndex} is
462      * {@code true}. If the provided buffer is a {@link CompositeByteBuf} itself, a "shallow copy" of its
463      * readable components will be performed. Thus the actual number of new components added may vary
464      * and in particular will be zero if the provided buffer is not readable.
465      * <p>
466      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
467      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
468      * {@link CompositeByteBuf}.
469      */
470     public CompositeByteBuf addFlattenedComponents(boolean increaseWriterIndex, ByteBuf buffer) {
471         checkNotNull(buffer, "buffer");
472         final int ridx = buffer.readerIndex();
473         final int widx = buffer.writerIndex();
474         if (ridx == widx) {
475             buffer.release();
476             return this;
477         }
478         if (!(buffer instanceof CompositeByteBuf)) {
479             addComponent0(increaseWriterIndex, componentCount, buffer);
480             consolidateIfNeeded();
481             return this;
482         }
483         final CompositeByteBuf from;
484         if (buffer instanceof WrappedCompositeByteBuf) {
485             from = (CompositeByteBuf) buffer.unwrap();
486         } else {
487             from = (CompositeByteBuf) buffer;
488         }
489         from.checkIndex(ridx, widx - ridx);
490         final Component[] fromComponents = from.components;
491         final int compCountBefore = componentCount;
492         final int writerIndexBefore = writerIndex;
493         try {
494             for (int cidx = from.toComponentIndex0(ridx), newOffset = capacity();; cidx++) {
495                 final Component component = fromComponents[cidx];
496                 final int compOffset = component.offset;
497                 final int fromIdx = Math.max(ridx, compOffset);
498                 final int toIdx = Math.min(widx, component.endOffset);
499                 final int len = toIdx - fromIdx;
500                 if (len > 0) { // skip empty components
501                     addComp(componentCount, new Component(
502                             component.srcBuf.retain(), component.srcIdx(fromIdx),
503                             component.buf, component.idx(fromIdx), newOffset, len, null));
504                 }
505                 if (widx == toIdx) {
506                     break;
507                 }
508                 newOffset += len;
509             }
510             if (increaseWriterIndex) {
511                 writerIndex = writerIndexBefore + (widx - ridx);
512             }
513             consolidateIfNeeded();
514             buffer.release();
515             buffer = null;
516             return this;
517         } finally {
518             if (buffer != null) {
519                 // if we did not succeed, attempt to rollback any components that were added
520                 if (increaseWriterIndex) {
521                     writerIndex = writerIndexBefore;
522                 }
523                 for (int cidx = componentCount - 1; cidx >= compCountBefore; cidx--) {
524                     components[cidx].free();
525                     removeComp(cidx);
526                 }
527             }
528         }
529     }
530 
531     // TODO optimize further, similar to ByteBuf[] version
532     // (difference here is that we don't know *always* know precise size increase in advance,
533     // but we do in the most common case that the Iterable is a Collection)
534     private CompositeByteBuf addComponents(boolean increaseIndex, int cIndex, Iterable<ByteBuf> buffers) {
535         if (buffers instanceof ByteBuf) {
536             // If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf).
537             return addComponent(increaseIndex, cIndex, (ByteBuf) buffers);
538         }
539         checkNotNull(buffers, "buffers");
540         Iterator<ByteBuf> it = buffers.iterator();
541         try {
542             checkComponentIndex(cIndex);
543 
544             // No need for consolidation
545             while (it.hasNext()) {
546                 ByteBuf b = it.next();
547                 if (b == null) {
548                     break;
549                 }
550                 cIndex = addComponent0(increaseIndex, cIndex, b) + 1;
551                 cIndex = Math.min(cIndex, componentCount);
552             }
553         } finally {
554             while (it.hasNext()) {
555                 ReferenceCountUtil.safeRelease(it.next());
556             }
557         }
558         consolidateIfNeeded();
559         return this;
560     }
561 
562     /**
563      * This should only be called as last operation from a method as this may adjust the underlying
564      * array of components and so affect the index etc.
565      */
566     private void consolidateIfNeeded() {
567         // Consolidate if the number of components will exceed the allowed maximum by the current
568         // operation.
569         int size = componentCount;
570         if (size > maxNumComponents) {
571             consolidate0(0, size);
572         }
573     }
574 
575     private void checkComponentIndex(int cIndex) {
576         ensureAccessible();
577         if (cIndex < 0 || cIndex > componentCount) {
578             throw new IndexOutOfBoundsException(String.format(
579                     "cIndex: %d (expected: >= 0 && <= numComponents(%d))",
580                     cIndex, componentCount));
581         }
582     }
583 
584     private void checkComponentIndex(int cIndex, int numComponents) {
585         ensureAccessible();
586         if (cIndex < 0 || cIndex + numComponents > componentCount) {
587             throw new IndexOutOfBoundsException(String.format(
588                     "cIndex: %d, numComponents: %d " +
589                     "(expected: cIndex >= 0 && cIndex + numComponents <= totalNumComponents(%d))",
590                     cIndex, numComponents, componentCount));
591         }
592     }
593 
594     private void updateComponentOffsets(int cIndex) {
595         int size = componentCount;
596         if (size <= cIndex) {
597             return;
598         }
599 
600         int nextIndex = cIndex > 0 ? components[cIndex - 1].endOffset : 0;
601         for (; cIndex < size; cIndex++) {
602             Component c = components[cIndex];
603             c.reposition(nextIndex);
604             nextIndex = c.endOffset;
605         }
606     }
607 
608     /**
609      * Remove the {@link ByteBuf} from the given index.
610      *
611      * @param cIndex the index on from which the {@link ByteBuf} will be remove
612      */
613     public CompositeByteBuf removeComponent(int cIndex) {
614         checkComponentIndex(cIndex);
615         Component comp = components[cIndex];
616         if (lastAccessed == comp) {
617             lastAccessed = null;
618         }
619         comp.free();
620         removeComp(cIndex);
621         if (comp.length() > 0) {
622             // Only need to call updateComponentOffsets if the length was > 0
623             updateComponentOffsets(cIndex);
624         }
625         return this;
626     }
627 
628     /**
629      * Remove the number of {@link ByteBuf}s starting from the given index.
630      *
631      * @param cIndex the index on which the {@link ByteBuf}s will be started to removed
632      * @param numComponents the number of components to remove
633      */
634     public CompositeByteBuf removeComponents(int cIndex, int numComponents) {
635         checkComponentIndex(cIndex, numComponents);
636 
637         if (numComponents == 0) {
638             return this;
639         }
640         int endIndex = cIndex + numComponents;
641         boolean needsUpdate = false;
642         for (int i = cIndex; i < endIndex; ++i) {
643             Component c = components[i];
644             if (c.length() > 0) {
645                 needsUpdate = true;
646             }
647             if (lastAccessed == c) {
648                 lastAccessed = null;
649             }
650             c.free();
651         }
652         removeCompRange(cIndex, endIndex);
653 
654         if (needsUpdate) {
655             // Only need to call updateComponentOffsets if the length was > 0
656             updateComponentOffsets(cIndex);
657         }
658         return this;
659     }
660 
661     @Override
662     public Iterator<ByteBuf> iterator() {
663         ensureAccessible();
664         return componentCount == 0 ? EMPTY_ITERATOR : new CompositeByteBufIterator();
665     }
666 
667     @Override
668     protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
669         if (end <= start) {
670             return -1;
671         }
672         for (int i = toComponentIndex0(start), length = end - start; length > 0; i++) {
673             Component c = components[i];
674             if (c.offset == c.endOffset) {
675                 continue; // empty
676             }
677             ByteBuf s = c.buf;
678             int localStart = c.idx(start);
679             int localLength = Math.min(length, c.endOffset - start);
680             // avoid additional checks in AbstractByteBuf case
681             int result = s instanceof AbstractByteBuf
682                 ? ((AbstractByteBuf) s).forEachByteAsc0(localStart, localStart + localLength, processor)
683                 : s.forEachByte(localStart, localLength, processor);
684             if (result != -1) {
685                 return result - c.adjustment;
686             }
687             start += localLength;
688             length -= localLength;
689         }
690         return -1;
691     }
692 
693     @Override
694     protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) throws Exception {
695         if (rEnd > rStart) { // rStart *and* rEnd are inclusive
696             return -1;
697         }
698         for (int i = toComponentIndex0(rStart), length = 1 + rStart - rEnd; length > 0; i--) {
699             Component c = components[i];
700             if (c.offset == c.endOffset) {
701                 continue; // empty
702             }
703             ByteBuf s = c.buf;
704             int localRStart = c.idx(length + rEnd);
705             int localLength = Math.min(length, localRStart), localIndex = localRStart - localLength;
706             // avoid additional checks in AbstractByteBuf case
707             int result = s instanceof AbstractByteBuf
708                 ? ((AbstractByteBuf) s).forEachByteDesc0(localRStart - 1, localIndex, processor)
709                 : s.forEachByteDesc(localIndex, localLength, processor);
710 
711             if (result != -1) {
712                 return result - c.adjustment;
713             }
714             length -= localLength;
715         }
716         return -1;
717     }
718 
719     /**
720      * Same with {@link #slice(int, int)} except that this method returns a list.
721      */
722     public List<ByteBuf> decompose(int offset, int length) {
723         checkIndex(offset, length);
724         if (length == 0) {
725             return Collections.emptyList();
726         }
727 
728         int componentId = toComponentIndex0(offset);
729         int bytesToSlice = length;
730         // The first component
731         Component firstC = components[componentId];
732 
733         // It's important to use srcBuf and NOT buf as we need to return the "original" source buffer and not the
734         // unwrapped one as otherwise we could loose the ability to correctly update the reference count on the
735         // returned buffer.
736         ByteBuf slice = firstC.srcBuf.slice(firstC.srcIdx(offset), Math.min(firstC.endOffset - offset, bytesToSlice));
737         bytesToSlice -= slice.readableBytes();
738 
739         if (bytesToSlice == 0) {
740             return Collections.singletonList(slice);
741         }
742 
743         List<ByteBuf> sliceList = new ArrayList<ByteBuf>(componentCount - componentId);
744         sliceList.add(slice);
745 
746         // Add all the slices until there is nothing more left and then return the List.
747         do {
748             Component component = components[++componentId];
749             // It's important to use srcBuf and NOT buf as we need to return the "original" source buffer and not the
750             // unwrapped one as otherwise we could loose the ability to correctly update the reference count on the
751             // returned buffer.
752             slice = component.srcBuf.slice(component.srcIdx(component.offset),
753                     Math.min(component.length(), bytesToSlice));
754             bytesToSlice -= slice.readableBytes();
755             sliceList.add(slice);
756         } while (bytesToSlice > 0);
757 
758         return sliceList;
759     }
760 
761     @Override
762     public boolean isDirect() {
763         int size = componentCount;
764         if (size == 0) {
765             return false;
766         }
767         for (int i = 0; i < size; i++) {
768            if (!components[i].buf.isDirect()) {
769                return false;
770            }
771         }
772         return true;
773     }
774 
775     @Override
776     public boolean hasArray() {
777         switch (componentCount) {
778         case 0:
779             return true;
780         case 1:
781             return components[0].buf.hasArray();
782         default:
783             return false;
784         }
785     }
786 
787     @Override
788     public byte[] array() {
789         switch (componentCount) {
790         case 0:
791             return EmptyArrays.EMPTY_BYTES;
792         case 1:
793             return components[0].buf.array();
794         default:
795             throw new UnsupportedOperationException();
796         }
797     }
798 
799     @Override
800     public int arrayOffset() {
801         switch (componentCount) {
802         case 0:
803             return 0;
804         case 1:
805             Component c = components[0];
806             return c.idx(c.buf.arrayOffset());
807         default:
808             throw new UnsupportedOperationException();
809         }
810     }
811 
812     @Override
813     public boolean hasMemoryAddress() {
814         switch (componentCount) {
815         case 0:
816             return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
817         case 1:
818             return components[0].buf.hasMemoryAddress();
819         default:
820             return false;
821         }
822     }
823 
824     @Override
825     public long memoryAddress() {
826         switch (componentCount) {
827         case 0:
828             return Unpooled.EMPTY_BUFFER.memoryAddress();
829         case 1:
830             Component c = components[0];
831             return c.buf.memoryAddress() + c.adjustment;
832         default:
833             throw new UnsupportedOperationException();
834         }
835     }
836 
837     @Override
838     public int capacity() {
839         int size = componentCount;
840         return size > 0 ? components[size - 1].endOffset : 0;
841     }
842 
843     @Override
844     public CompositeByteBuf capacity(int newCapacity) {
845         checkNewCapacity(newCapacity);
846 
847         final int size = componentCount, oldCapacity = capacity();
848         if (newCapacity > oldCapacity) {
849             final int paddingLength = newCapacity - oldCapacity;
850             ByteBuf padding = allocBuffer(paddingLength).setIndex(0, paddingLength);
851             addComponent0(false, size, padding);
852             if (componentCount >= maxNumComponents) {
853                 // FIXME: No need to create a padding buffer and consolidate.
854                 // Just create a big single buffer and put the current content there.
855                 consolidateIfNeeded();
856             }
857         } else if (newCapacity < oldCapacity) {
858             lastAccessed = null;
859             int i = size - 1;
860             for (int bytesToTrim = oldCapacity - newCapacity; i >= 0; i--) {
861                 Component c = components[i];
862                 final int cLength = c.length();
863                 if (bytesToTrim < cLength) {
864                     // Trim the last component
865                     c.endOffset -= bytesToTrim;
866                     ByteBuf slice = c.slice;
867                     if (slice != null) {
868                         // We must replace the cached slice with a derived one to ensure that
869                         // it can later be released properly in the case of PooledSlicedByteBuf.
870                         c.slice = slice.slice(0, c.length());
871                     }
872                     break;
873                 }
874                 c.free();
875                 bytesToTrim -= cLength;
876             }
877             removeCompRange(i + 1, size);
878 
879             if (readerIndex() > newCapacity) {
880                 setIndex0(newCapacity, newCapacity);
881             } else if (writerIndex > newCapacity) {
882                 writerIndex = newCapacity;
883             }
884         }
885         return this;
886     }
887 
888     @Override
889     public ByteBufAllocator alloc() {
890         return alloc;
891     }
892 
893     @Override
894     public ByteOrder order() {
895         return ByteOrder.BIG_ENDIAN;
896     }
897 
898     /**
899      * Return the current number of {@link ByteBuf}'s that are composed in this instance
900      */
901     public int numComponents() {
902         return componentCount;
903     }
904 
905     /**
906      * Return the max number of {@link ByteBuf}'s that are composed in this instance
907      */
908     public int maxNumComponents() {
909         return maxNumComponents;
910     }
911 
912     /**
913      * Return the index for the given offset
914      */
915     public int toComponentIndex(int offset) {
916         checkIndex(offset);
917         return toComponentIndex0(offset);
918     }
919 
920     private int toComponentIndex0(int offset) {
921         int size = componentCount;
922         if (offset == 0) { // fast-path zero offset
923             for (int i = 0; i < size; i++) {
924                 if (components[i].endOffset > 0) {
925                     return i;
926                 }
927             }
928         }
929         if (size <= 2) { // fast-path for 1 and 2 component count
930             return size == 1 || offset < components[0].endOffset ? 0 : 1;
931         }
932         for (int low = 0, high = size; low <= high;) {
933             int mid = low + high >>> 1;
934             Component c = components[mid];
935             if (offset >= c.endOffset) {
936                 low = mid + 1;
937             } else if (offset < c.offset) {
938                 high = mid - 1;
939             } else {
940                 return mid;
941             }
942         }
943 
944         throw new Error("should not reach here");
945     }
946 
947     public int toByteIndex(int cIndex) {
948         checkComponentIndex(cIndex);
949         return components[cIndex].offset;
950     }
951 
952     @Override
953     public byte getByte(int index) {
954         Component c = findComponent(index);
955         return c.buf.getByte(c.idx(index));
956     }
957 
958     @Override
959     protected byte _getByte(int index) {
960         Component c = findComponent0(index);
961         return c.buf.getByte(c.idx(index));
962     }
963 
964     @Override
965     protected short _getShort(int index) {
966         Component c = findComponent0(index);
967         if (index + 2 <= c.endOffset) {
968             return c.buf.getShort(c.idx(index));
969         } else if (order() == ByteOrder.BIG_ENDIAN) {
970             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
971         } else {
972             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
973         }
974     }
975 
976     @Override
977     protected short _getShortLE(int index) {
978         Component c = findComponent0(index);
979         if (index + 2 <= c.endOffset) {
980             return c.buf.getShortLE(c.idx(index));
981         } else if (order() == ByteOrder.BIG_ENDIAN) {
982             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
983         } else {
984             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
985         }
986     }
987 
988     @Override
989     protected int _getUnsignedMedium(int index) {
990         Component c = findComponent0(index);
991         if (index + 3 <= c.endOffset) {
992             return c.buf.getUnsignedMedium(c.idx(index));
993         } else if (order() == ByteOrder.BIG_ENDIAN) {
994             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
995         } else {
996             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
997         }
998     }
999 
1000     @Override
1001     protected int _getUnsignedMediumLE(int index) {
1002         Component c = findComponent0(index);
1003         if (index + 3 <= c.endOffset) {
1004             return c.buf.getUnsignedMediumLE(c.idx(index));
1005         } else if (order() == ByteOrder.BIG_ENDIAN) {
1006             return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16;
1007         } else {
1008             return (_getShortLE(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
1009         }
1010     }
1011 
1012     @Override
1013     protected int _getInt(int index) {
1014         Component c = findComponent0(index);
1015         if (index + 4 <= c.endOffset) {
1016             return c.buf.getInt(c.idx(index));
1017         } else if (order() == ByteOrder.BIG_ENDIAN) {
1018             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
1019         } else {
1020             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
1021         }
1022     }
1023 
1024     @Override
1025     protected int _getIntLE(int index) {
1026         Component c = findComponent0(index);
1027         if (index + 4 <= c.endOffset) {
1028             return c.buf.getIntLE(c.idx(index));
1029         } else if (order() == ByteOrder.BIG_ENDIAN) {
1030             return _getShortLE(index) & 0xffff | (_getShortLE(index + 2) & 0xffff) << 16;
1031         } else {
1032             return (_getShortLE(index) & 0xffff) << 16 | _getShortLE(index + 2) & 0xffff;
1033         }
1034     }
1035 
1036     @Override
1037     protected long _getLong(int index) {
1038         Component c = findComponent0(index);
1039         if (index + 8 <= c.endOffset) {
1040             return c.buf.getLong(c.idx(index));
1041         } else if (order() == ByteOrder.BIG_ENDIAN) {
1042             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
1043         } else {
1044             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
1045         }
1046     }
1047 
1048     @Override
1049     protected long _getLongLE(int index) {
1050         Component c = findComponent0(index);
1051         if (index + 8 <= c.endOffset) {
1052             return c.buf.getLongLE(c.idx(index));
1053         } else if (order() == ByteOrder.BIG_ENDIAN) {
1054             return _getIntLE(index) & 0xffffffffL | (_getIntLE(index + 4) & 0xffffffffL) << 32;
1055         } else {
1056             return (_getIntLE(index) & 0xffffffffL) << 32 | _getIntLE(index + 4) & 0xffffffffL;
1057         }
1058     }
1059 
1060     @Override
1061     public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
1062         checkDstIndex(index, length, dstIndex, dst.length);
1063         if (length == 0) {
1064             return this;
1065         }
1066 
1067         int i = toComponentIndex0(index);
1068         while (length > 0) {
1069             Component c = components[i];
1070             int localLength = Math.min(length, c.endOffset - index);
1071             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1072             index += localLength;
1073             dstIndex += localLength;
1074             length -= localLength;
1075             i ++;
1076         }
1077         return this;
1078     }
1079 
1080     @Override
1081     public CompositeByteBuf getBytes(int index, ByteBuffer dst) {
1082         int limit = dst.limit();
1083         int length = dst.remaining();
1084 
1085         checkIndex(index, length);
1086         if (length == 0) {
1087             return this;
1088         }
1089 
1090         int i = toComponentIndex0(index);
1091         try {
1092             while (length > 0) {
1093                 Component c = components[i];
1094                 int localLength = Math.min(length, c.endOffset - index);
1095                 dst.limit(dst.position() + localLength);
1096                 c.buf.getBytes(c.idx(index), dst);
1097                 index += localLength;
1098                 length -= localLength;
1099                 i ++;
1100             }
1101         } finally {
1102             dst.limit(limit);
1103         }
1104         return this;
1105     }
1106 
1107     @Override
1108     public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
1109         checkDstIndex(index, length, dstIndex, dst.capacity());
1110         if (length == 0) {
1111             return this;
1112         }
1113 
1114         int i = toComponentIndex0(index);
1115         while (length > 0) {
1116             Component c = components[i];
1117             int localLength = Math.min(length, c.endOffset - index);
1118             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1119             index += localLength;
1120             dstIndex += localLength;
1121             length -= localLength;
1122             i ++;
1123         }
1124         return this;
1125     }
1126 
1127     @Override
1128     public int getBytes(int index, GatheringByteChannel out, int length)
1129             throws IOException {
1130         int count = nioBufferCount();
1131         if (count == 1) {
1132             return out.write(internalNioBuffer(index, length));
1133         } else {
1134             long writtenBytes = out.write(nioBuffers(index, length));
1135             if (writtenBytes > Integer.MAX_VALUE) {
1136                 return Integer.MAX_VALUE;
1137             } else {
1138                 return (int) writtenBytes;
1139             }
1140         }
1141     }
1142 
1143     @Override
1144     public int getBytes(int index, FileChannel out, long position, int length)
1145             throws IOException {
1146         int count = nioBufferCount();
1147         if (count == 1) {
1148             return out.write(internalNioBuffer(index, length), position);
1149         } else {
1150             long writtenBytes = 0;
1151             for (ByteBuffer buf : nioBuffers(index, length)) {
1152                 writtenBytes += out.write(buf, position + writtenBytes);
1153             }
1154             if (writtenBytes > Integer.MAX_VALUE) {
1155                 return Integer.MAX_VALUE;
1156             }
1157             return (int) writtenBytes;
1158         }
1159     }
1160 
1161     @Override
1162     public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
1163         checkIndex(index, length);
1164         if (length == 0) {
1165             return this;
1166         }
1167 
1168         int i = toComponentIndex0(index);
1169         while (length > 0) {
1170             Component c = components[i];
1171             int localLength = Math.min(length, c.endOffset - index);
1172             c.buf.getBytes(c.idx(index), out, localLength);
1173             index += localLength;
1174             length -= localLength;
1175             i ++;
1176         }
1177         return this;
1178     }
1179 
1180     @Override
1181     public CompositeByteBuf setByte(int index, int value) {
1182         Component c = findComponent(index);
1183         c.buf.setByte(c.idx(index), value);
1184         return this;
1185     }
1186 
1187     @Override
1188     protected void _setByte(int index, int value) {
1189         Component c = findComponent0(index);
1190         c.buf.setByte(c.idx(index), value);
1191     }
1192 
1193     @Override
1194     public CompositeByteBuf setShort(int index, int value) {
1195         checkIndex(index, 2);
1196         _setShort(index, value);
1197         return this;
1198     }
1199 
1200     @Override
1201     protected void _setShort(int index, int value) {
1202         Component c = findComponent0(index);
1203         if (index + 2 <= c.endOffset) {
1204             c.buf.setShort(c.idx(index), value);
1205         } else if (order() == ByteOrder.BIG_ENDIAN) {
1206             _setByte(index, (byte) (value >>> 8));
1207             _setByte(index + 1, (byte) value);
1208         } else {
1209             _setByte(index, (byte) value);
1210             _setByte(index + 1, (byte) (value >>> 8));
1211         }
1212     }
1213 
1214     @Override
1215     protected void _setShortLE(int index, int value) {
1216         Component c = findComponent0(index);
1217         if (index + 2 <= c.endOffset) {
1218             c.buf.setShortLE(c.idx(index), value);
1219         } else if (order() == ByteOrder.BIG_ENDIAN) {
1220             _setByte(index, (byte) value);
1221             _setByte(index + 1, (byte) (value >>> 8));
1222         } else {
1223             _setByte(index, (byte) (value >>> 8));
1224             _setByte(index + 1, (byte) value);
1225         }
1226     }
1227 
1228     @Override
1229     public CompositeByteBuf setMedium(int index, int value) {
1230         checkIndex(index, 3);
1231         _setMedium(index, value);
1232         return this;
1233     }
1234 
1235     @Override
1236     protected void _setMedium(int index, int value) {
1237         Component c = findComponent0(index);
1238         if (index + 3 <= c.endOffset) {
1239             c.buf.setMedium(c.idx(index), value);
1240         } else if (order() == ByteOrder.BIG_ENDIAN) {
1241             _setShort(index, (short) (value >> 8));
1242             _setByte(index + 2, (byte) value);
1243         } else {
1244             _setShort(index, (short) value);
1245             _setByte(index + 2, (byte) (value >>> 16));
1246         }
1247     }
1248 
1249     @Override
1250     protected void _setMediumLE(int index, int value) {
1251         Component c = findComponent0(index);
1252         if (index + 3 <= c.endOffset) {
1253             c.buf.setMediumLE(c.idx(index), value);
1254         } else if (order() == ByteOrder.BIG_ENDIAN) {
1255             _setShortLE(index, (short) value);
1256             _setByte(index + 2, (byte) (value >>> 16));
1257         } else {
1258             _setShortLE(index, (short) (value >> 8));
1259             _setByte(index + 2, (byte) value);
1260         }
1261     }
1262 
1263     @Override
1264     public CompositeByteBuf setInt(int index, int value) {
1265         checkIndex(index, 4);
1266         _setInt(index, value);
1267         return this;
1268     }
1269 
1270     @Override
1271     protected void _setInt(int index, int value) {
1272         Component c = findComponent0(index);
1273         if (index + 4 <= c.endOffset) {
1274             c.buf.setInt(c.idx(index), value);
1275         } else if (order() == ByteOrder.BIG_ENDIAN) {
1276             _setShort(index, (short) (value >>> 16));
1277             _setShort(index + 2, (short) value);
1278         } else {
1279             _setShort(index, (short) value);
1280             _setShort(index + 2, (short) (value >>> 16));
1281         }
1282     }
1283 
1284     @Override
1285     protected void _setIntLE(int index, int value) {
1286         Component c = findComponent0(index);
1287         if (index + 4 <= c.endOffset) {
1288             c.buf.setIntLE(c.idx(index), value);
1289         } else if (order() == ByteOrder.BIG_ENDIAN) {
1290             _setShortLE(index, (short) value);
1291             _setShortLE(index + 2, (short) (value >>> 16));
1292         } else {
1293             _setShortLE(index, (short) (value >>> 16));
1294             _setShortLE(index + 2, (short) value);
1295         }
1296     }
1297 
1298     @Override
1299     public CompositeByteBuf setLong(int index, long value) {
1300         checkIndex(index, 8);
1301         _setLong(index, value);
1302         return this;
1303     }
1304 
1305     @Override
1306     protected void _setLong(int index, long value) {
1307         Component c = findComponent0(index);
1308         if (index + 8 <= c.endOffset) {
1309             c.buf.setLong(c.idx(index), value);
1310         } else if (order() == ByteOrder.BIG_ENDIAN) {
1311             _setInt(index, (int) (value >>> 32));
1312             _setInt(index + 4, (int) value);
1313         } else {
1314             _setInt(index, (int) value);
1315             _setInt(index + 4, (int) (value >>> 32));
1316         }
1317     }
1318 
1319     @Override
1320     protected void _setLongLE(int index, long value) {
1321         Component c = findComponent0(index);
1322         if (index + 8 <= c.endOffset) {
1323             c.buf.setLongLE(c.idx(index), value);
1324         } else if (order() == ByteOrder.BIG_ENDIAN) {
1325             _setIntLE(index, (int) value);
1326             _setIntLE(index + 4, (int) (value >>> 32));
1327         } else {
1328             _setIntLE(index, (int) (value >>> 32));
1329             _setIntLE(index + 4, (int) value);
1330         }
1331     }
1332 
1333     @Override
1334     public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
1335         checkSrcIndex(index, length, srcIndex, src.length);
1336         if (length == 0) {
1337             return this;
1338         }
1339 
1340         int i = toComponentIndex0(index);
1341         while (length > 0) {
1342             Component c = components[i];
1343             int localLength = Math.min(length, c.endOffset - index);
1344             c.buf.setBytes(c.idx(index), src, srcIndex, localLength);
1345             index += localLength;
1346             srcIndex += localLength;
1347             length -= localLength;
1348             i ++;
1349         }
1350         return this;
1351     }
1352 
1353     @Override
1354     public CompositeByteBuf setBytes(int index, ByteBuffer src) {
1355         int limit = src.limit();
1356         int length = src.remaining();
1357 
1358         checkIndex(index, length);
1359         if (length == 0) {
1360             return this;
1361         }
1362 
1363         int i = toComponentIndex0(index);
1364         try {
1365             while (length > 0) {
1366                 Component c = components[i];
1367                 int localLength = Math.min(length, c.endOffset - index);
1368                 src.limit(src.position() + localLength);
1369                 c.buf.setBytes(c.idx(index), src);
1370                 index += localLength;
1371                 length -= localLength;
1372                 i ++;
1373             }
1374         } finally {
1375             src.limit(limit);
1376         }
1377         return this;
1378     }
1379 
1380     @Override
1381     public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
1382         checkSrcIndex(index, length, srcIndex, src.capacity());
1383         if (length == 0) {
1384             return this;
1385         }
1386 
1387         int i = toComponentIndex0(index);
1388         while (length > 0) {
1389             Component c = components[i];
1390             int localLength = Math.min(length, c.endOffset - index);
1391             c.buf.setBytes(c.idx(index), src, srcIndex, localLength);
1392             index += localLength;
1393             srcIndex += localLength;
1394             length -= localLength;
1395             i ++;
1396         }
1397         return this;
1398     }
1399 
1400     @Override
1401     public int setBytes(int index, InputStream in, int length) throws IOException {
1402         checkIndex(index, length);
1403         if (length == 0) {
1404             return in.read(EmptyArrays.EMPTY_BYTES);
1405         }
1406 
1407         int i = toComponentIndex0(index);
1408         int readBytes = 0;
1409         do {
1410             Component c = components[i];
1411             int localLength = Math.min(length, c.endOffset - index);
1412             if (localLength == 0) {
1413                 // Skip empty buffer
1414                 i++;
1415                 continue;
1416             }
1417             int localReadBytes = c.buf.setBytes(c.idx(index), in, localLength);
1418             if (localReadBytes < 0) {
1419                 if (readBytes == 0) {
1420                     return -1;
1421                 } else {
1422                     break;
1423                 }
1424             }
1425 
1426             index += localReadBytes;
1427             length -= localReadBytes;
1428             readBytes += localReadBytes;
1429             if (localReadBytes == localLength) {
1430                 i ++;
1431             }
1432         } while (length > 0);
1433 
1434         return readBytes;
1435     }
1436 
1437     @Override
1438     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
1439         checkIndex(index, length);
1440         if (length == 0) {
1441             return in.read(EMPTY_NIO_BUFFER);
1442         }
1443 
1444         int i = toComponentIndex0(index);
1445         int readBytes = 0;
1446         do {
1447             Component c = components[i];
1448             int localLength = Math.min(length, c.endOffset - index);
1449             if (localLength == 0) {
1450                 // Skip empty buffer
1451                 i++;
1452                 continue;
1453             }
1454             int localReadBytes = c.buf.setBytes(c.idx(index), in, localLength);
1455 
1456             if (localReadBytes == 0) {
1457                 break;
1458             }
1459 
1460             if (localReadBytes < 0) {
1461                 if (readBytes == 0) {
1462                     return -1;
1463                 } else {
1464                     break;
1465                 }
1466             }
1467 
1468             index += localReadBytes;
1469             length -= localReadBytes;
1470             readBytes += localReadBytes;
1471             if (localReadBytes == localLength) {
1472                 i ++;
1473             }
1474         } while (length > 0);
1475 
1476         return readBytes;
1477     }
1478 
1479     @Override
1480     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
1481         checkIndex(index, length);
1482         if (length == 0) {
1483             return in.read(EMPTY_NIO_BUFFER, position);
1484         }
1485 
1486         int i = toComponentIndex0(index);
1487         int readBytes = 0;
1488         do {
1489             Component c = components[i];
1490             int localLength = Math.min(length, c.endOffset - index);
1491             if (localLength == 0) {
1492                 // Skip empty buffer
1493                 i++;
1494                 continue;
1495             }
1496             int localReadBytes = c.buf.setBytes(c.idx(index), in, position + readBytes, localLength);
1497 
1498             if (localReadBytes == 0) {
1499                 break;
1500             }
1501 
1502             if (localReadBytes < 0) {
1503                 if (readBytes == 0) {
1504                     return -1;
1505                 } else {
1506                     break;
1507                 }
1508             }
1509 
1510             index += localReadBytes;
1511             length -= localReadBytes;
1512             readBytes += localReadBytes;
1513             if (localReadBytes == localLength) {
1514                 i ++;
1515             }
1516         } while (length > 0);
1517 
1518         return readBytes;
1519     }
1520 
1521     @Override
1522     public ByteBuf copy(int index, int length) {
1523         checkIndex(index, length);
1524         ByteBuf dst = allocBuffer(length);
1525         if (length != 0) {
1526             copyTo(index, length, toComponentIndex0(index), dst);
1527         }
1528         return dst;
1529     }
1530 
1531     private void copyTo(int index, int length, int componentId, ByteBuf dst) {
1532         int dstIndex = 0;
1533         int i = componentId;
1534 
1535         while (length > 0) {
1536             Component c = components[i];
1537             int localLength = Math.min(length, c.endOffset - index);
1538             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1539             index += localLength;
1540             dstIndex += localLength;
1541             length -= localLength;
1542             i ++;
1543         }
1544 
1545         dst.writerIndex(dst.capacity());
1546     }
1547 
1548     /**
1549      * Return a duplicate of the {@link ByteBuf} on the specified component index.
1550      * <p>
1551      * Note that this method returns a shallow duplicate of the underlying component buffer.
1552      * The returned buffer's {@code readerIndex} and {@code writerIndex} will be independent of the
1553      * composite buffer's indices and will not be adjusted to reflect the component's view within
1554      * the composite buffer.
1555      * <p>
1556      * If you need a buffer that represents the component's readable view as seen from the composite
1557      * buffer, use {@link #componentSlice(int cIndex)} instead.
1558      *
1559      * @param cIndex the index for which the {@link ByteBuf} should be returned
1560      * @return a duplicate of the underlying {@link ByteBuf} on the specified index
1561      */
1562     public ByteBuf component(int cIndex) {
1563         checkComponentIndex(cIndex);
1564         return components[cIndex].duplicate();
1565     }
1566 
1567     /**
1568      * Return a slice of the {@link ByteBuf} on the specified component index.
1569      * <p>
1570      * This method provides a view of the component that reflects its state within the composite buffer.
1571      * The returned buffer's readable bytes will correspond to the bytes that this component
1572      * contributes to the composite buffer's capacity. The slice will have its own independent
1573      * {@code readerIndex} and {@code writerIndex}, starting at {@code 0}.
1574      *
1575      * @param cIndex the index for which the sliced {@link ByteBuf} should be returned
1576      * @return a sliced {@link ByteBuf} representing the component's view
1577      */
1578     public ByteBuf componentSlice(int cIndex) {
1579         checkComponentIndex(cIndex);
1580         return components[cIndex].slice();
1581     }
1582 
1583     /**
1584      * Return the {@link ByteBuf} on the specified index
1585      *
1586      * @param offset the offset for which the {@link ByteBuf} should be returned
1587      * @return the {@link ByteBuf} on the specified index
1588      */
1589     public ByteBuf componentAtOffset(int offset) {
1590         return findComponent(offset).duplicate();
1591     }
1592 
1593     /**
1594      * Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
1595      * buffer will lead to an undefined behavior of this buffer.
1596      *
1597      * @param cIndex the index for which the {@link ByteBuf} should be returned
1598      */
1599     public ByteBuf internalComponent(int cIndex) {
1600         checkComponentIndex(cIndex);
1601         return components[cIndex].slice();
1602     }
1603 
1604     /**
1605      * Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
1606      * buffer will lead to an undefined behavior of this buffer.
1607      *
1608      * @param offset the offset for which the {@link ByteBuf} should be returned
1609      */
1610     public ByteBuf internalComponentAtOffset(int offset) {
1611         return findComponent(offset).slice();
1612     }
1613 
1614     // weak cache - check it first when looking for component
1615     private Component lastAccessed;
1616 
1617     private Component findComponent(int offset) {
1618         Component la = lastAccessed;
1619         if (la != null && offset >= la.offset && offset < la.endOffset) {
1620            ensureAccessible();
1621            return la;
1622         }
1623         checkIndex(offset);
1624         return findIt(offset);
1625     }
1626 
1627     private Component findComponent0(int offset) {
1628         Component la = lastAccessed;
1629         if (la != null && offset >= la.offset && offset < la.endOffset) {
1630            return la;
1631         }
1632         return findIt(offset);
1633     }
1634 
1635     private Component findIt(int offset) {
1636         for (int low = 0, high = componentCount; low <= high;) {
1637             int mid = low + high >>> 1;
1638             Component c = components[mid];
1639             if (c == null) {
1640                 throw new IllegalStateException("No component found for offset. " +
1641                         "Composite buffer layout might be outdated, e.g. from a discardReadBytes call.");
1642             }
1643             if (offset >= c.endOffset) {
1644                 low = mid + 1;
1645             } else if (offset < c.offset) {
1646                 high = mid - 1;
1647             } else {
1648                 lastAccessed = c;
1649                 return c;
1650             }
1651         }
1652 
1653         throw new Error("should not reach here");
1654     }
1655 
1656     @Override
1657     public int nioBufferCount() {
1658         int size = componentCount;
1659         switch (size) {
1660         case 0:
1661             return 1;
1662         case 1:
1663             return components[0].buf.nioBufferCount();
1664         default:
1665             int count = 0;
1666             for (int i = 0; i < size; i++) {
1667                 count += components[i].buf.nioBufferCount();
1668             }
1669             return count;
1670         }
1671     }
1672 
1673     @Override
1674     public ByteBuffer internalNioBuffer(int index, int length) {
1675         switch (componentCount) {
1676         case 0:
1677             return EMPTY_NIO_BUFFER;
1678         case 1:
1679             return components[0].internalNioBuffer(index, length);
1680         default:
1681             throw new UnsupportedOperationException();
1682         }
1683     }
1684 
1685     @Override
1686     public ByteBuffer nioBuffer(int index, int length) {
1687         checkIndex(index, length);
1688 
1689         switch (componentCount) {
1690         case 0:
1691             return EMPTY_NIO_BUFFER;
1692         case 1:
1693             Component c = components[0];
1694             ByteBuf buf = c.buf;
1695             if (buf.nioBufferCount() == 1) {
1696                 return buf.nioBuffer(c.idx(index), length);
1697             }
1698             break;
1699         default:
1700             break;
1701         }
1702 
1703         ByteBuffer[] buffers = nioBuffers(index, length);
1704 
1705         if (buffers.length == 1) {
1706             return buffers[0];
1707         }
1708 
1709         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
1710         for (ByteBuffer buf: buffers) {
1711             merged.put(buf);
1712         }
1713 
1714         merged.flip();
1715         return merged;
1716     }
1717 
1718     @Override
1719     public ByteBuffer[] nioBuffers(int index, int length) {
1720         checkIndex(index, length);
1721         if (length == 0) {
1722             return new ByteBuffer[] { EMPTY_NIO_BUFFER };
1723         }
1724 
1725         RecyclableArrayList buffers = RecyclableArrayList.newInstance(componentCount);
1726         try {
1727             int i = toComponentIndex0(index);
1728             while (length > 0) {
1729                 Component c = components[i];
1730                 ByteBuf s = c.buf;
1731                 int localLength = Math.min(length, c.endOffset - index);
1732                 switch (s.nioBufferCount()) {
1733                 case 0:
1734                     throw new UnsupportedOperationException();
1735                 case 1:
1736                     buffers.add(s.nioBuffer(c.idx(index), localLength));
1737                     break;
1738                 default:
1739                     Collections.addAll(buffers, s.nioBuffers(c.idx(index), localLength));
1740                 }
1741 
1742                 index += localLength;
1743                 length -= localLength;
1744                 i ++;
1745             }
1746 
1747             return buffers.toArray(EmptyArrays.EMPTY_BYTE_BUFFERS);
1748         } finally {
1749             buffers.recycle();
1750         }
1751     }
1752 
1753     /**
1754      * Consolidate the composed {@link ByteBuf}s
1755      */
1756     public CompositeByteBuf consolidate() {
1757         ensureAccessible();
1758         consolidate0(0, componentCount);
1759         return this;
1760     }
1761 
1762     /**
1763      * Consolidate the composed {@link ByteBuf}s
1764      *
1765      * @param cIndex the index on which to start to compose
1766      * @param numComponents the number of components to compose
1767      */
1768     public CompositeByteBuf consolidate(int cIndex, int numComponents) {
1769         checkComponentIndex(cIndex, numComponents);
1770         consolidate0(cIndex, numComponents);
1771         return this;
1772     }
1773 
1774     private void consolidate0(int cIndex, int numComponents) {
1775         if (numComponents <= 1) {
1776             return;
1777         }
1778 
1779         final int endCIndex = cIndex + numComponents;
1780         final int startOffset = cIndex != 0 ? components[cIndex].offset : 0;
1781         final int capacity = components[endCIndex - 1].endOffset - startOffset;
1782         final ByteBuf consolidated = allocBuffer(capacity);
1783 
1784         for (int i = cIndex; i < endCIndex; i ++) {
1785             components[i].transferTo(consolidated);
1786         }
1787         lastAccessed = null;
1788         removeCompRange(cIndex + 1, endCIndex);
1789         components[cIndex] = newComponent(consolidated, 0);
1790         if (cIndex != 0 || numComponents != componentCount) {
1791             updateComponentOffsets(cIndex);
1792         }
1793     }
1794 
1795     /**
1796      * Discard all {@link ByteBuf}s which are read.
1797      */
1798     public CompositeByteBuf discardReadComponents() {
1799         ensureAccessible();
1800         final int readerIndex = readerIndex();
1801         if (readerIndex == 0) {
1802             return this;
1803         }
1804 
1805         // Discard everything if (readerIndex = writerIndex = capacity).
1806         int writerIndex = writerIndex();
1807         if (readerIndex == writerIndex && writerIndex == capacity()) {
1808             for (int i = 0, size = componentCount; i < size; i++) {
1809                 components[i].free();
1810             }
1811             lastAccessed = null;
1812             clearComps();
1813             setIndex(0, 0);
1814             adjustMarkers(readerIndex);
1815             return this;
1816         }
1817 
1818         // Remove read components.
1819         int firstComponentId = 0;
1820         Component c = null;
1821         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1822             c = components[firstComponentId];
1823             if (c.endOffset > readerIndex) {
1824                 break;
1825             }
1826             c.free();
1827         }
1828         if (firstComponentId == 0) {
1829             return this; // Nothing to discard
1830         }
1831         Component la = lastAccessed;
1832         if (la != null && la.endOffset <= readerIndex) {
1833             lastAccessed = null;
1834         }
1835         removeCompRange(0, firstComponentId);
1836 
1837         // Update indexes and markers.
1838         int offset = c.offset;
1839         updateComponentOffsets(0);
1840         setIndex(readerIndex - offset, writerIndex - offset);
1841         adjustMarkers(offset);
1842         return this;
1843     }
1844 
1845     @Override
1846     public CompositeByteBuf discardReadBytes() {
1847         ensureAccessible();
1848         final int readerIndex = readerIndex();
1849         if (readerIndex == 0) {
1850             return this;
1851         }
1852 
1853         // Discard everything if (readerIndex = writerIndex = capacity).
1854         int writerIndex = writerIndex();
1855         if (readerIndex == writerIndex && writerIndex == capacity()) {
1856             for (int i = 0, size = componentCount; i < size; i++) {
1857                 components[i].free();
1858             }
1859             lastAccessed = null;
1860             clearComps();
1861             setIndex(0, 0);
1862             adjustMarkers(readerIndex);
1863             return this;
1864         }
1865 
1866         int firstComponentId = 0;
1867         Component c = null;
1868         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1869             c = components[firstComponentId];
1870             if (c.endOffset > readerIndex) {
1871                 break;
1872             }
1873             c.free();
1874         }
1875 
1876         // Replace the first readable component with a new slice.
1877         int trimmedBytes = readerIndex - c.offset;
1878         c.offset = 0;
1879         c.endOffset -= readerIndex;
1880         c.srcAdjustment += readerIndex;
1881         c.adjustment += readerIndex;
1882         ByteBuf slice = c.slice;
1883         if (slice != null) {
1884             // We must replace the cached slice with a derived one to ensure that
1885             // it can later be released properly in the case of PooledSlicedByteBuf.
1886             c.slice = slice.slice(trimmedBytes, c.length());
1887         }
1888         Component la = lastAccessed;
1889         if (la != null && la.endOffset <= readerIndex) {
1890             lastAccessed = null;
1891         }
1892 
1893         removeCompRange(0, firstComponentId);
1894 
1895         // Update indexes and markers.
1896         updateComponentOffsets(0);
1897         setIndex(0, writerIndex - readerIndex);
1898         adjustMarkers(readerIndex);
1899         return this;
1900     }
1901 
1902     private ByteBuf allocBuffer(int capacity) {
1903         return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
1904     }
1905 
1906     @Override
1907     public String toString() {
1908         String result = super.toString();
1909         result = result.substring(0, result.length() - 1);
1910         return result + ", components=" + componentCount + ')';
1911     }
1912 
1913     private static final class Component {
1914         final ByteBuf srcBuf; // the originally added buffer
1915         final ByteBuf buf; // srcBuf unwrapped zero or more times
1916 
1917         int srcAdjustment; // index of the start of this CompositeByteBuf relative to srcBuf
1918         int adjustment; // index of the start of this CompositeByteBuf relative to buf
1919 
1920         int offset; // offset of this component within this CompositeByteBuf
1921         int endOffset; // end offset of this component within this CompositeByteBuf
1922 
1923         private ByteBuf slice; // cached slice, may be null
1924 
1925         Component(ByteBuf srcBuf, int srcOffset, ByteBuf buf, int bufOffset,
1926                 int offset, int len, ByteBuf slice) {
1927             this.srcBuf = srcBuf;
1928             this.srcAdjustment = srcOffset - offset;
1929             this.buf = buf;
1930             this.adjustment = bufOffset - offset;
1931             this.offset = offset;
1932             this.endOffset = offset + len;
1933             this.slice = slice;
1934         }
1935 
1936         int srcIdx(int index) {
1937             return index + srcAdjustment;
1938         }
1939 
1940         int idx(int index) {
1941             return index + adjustment;
1942         }
1943 
1944         int length() {
1945             return endOffset - offset;
1946         }
1947 
1948         void reposition(int newOffset) {
1949             int move = newOffset - offset;
1950             endOffset += move;
1951             srcAdjustment -= move;
1952             adjustment -= move;
1953             offset = newOffset;
1954         }
1955 
1956         // copy then release
1957         void transferTo(ByteBuf dst) {
1958             dst.writeBytes(buf, idx(offset), length());
1959             free();
1960         }
1961 
1962         ByteBuf slice() {
1963             ByteBuf s = slice;
1964             if (s == null) {
1965                 slice = s = srcBuf.slice(srcIdx(offset), length());
1966             }
1967             return s;
1968         }
1969 
1970         ByteBuf duplicate() {
1971             return srcBuf.duplicate();
1972         }
1973 
1974         ByteBuffer internalNioBuffer(int index, int length) {
1975             // Some buffers override this so we must use srcBuf
1976             return srcBuf.internalNioBuffer(srcIdx(index), length);
1977         }
1978 
1979         void free() {
1980             slice = null;
1981             // Release the original buffer since it may have a different
1982             // refcount to the unwrapped buf (e.g. if PooledSlicedByteBuf)
1983             srcBuf.release();
1984         }
1985     }
1986 
1987     @Override
1988     public CompositeByteBuf readerIndex(int readerIndex) {
1989         super.readerIndex(readerIndex);
1990         return this;
1991     }
1992 
1993     @Override
1994     public CompositeByteBuf writerIndex(int writerIndex) {
1995         super.writerIndex(writerIndex);
1996         return this;
1997     }
1998 
1999     @Override
2000     public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
2001         super.setIndex(readerIndex, writerIndex);
2002         return this;
2003     }
2004 
2005     @Override
2006     public CompositeByteBuf clear() {
2007         super.clear();
2008         return this;
2009     }
2010 
2011     @Override
2012     public CompositeByteBuf markReaderIndex() {
2013         super.markReaderIndex();
2014         return this;
2015     }
2016 
2017     @Override
2018     public CompositeByteBuf resetReaderIndex() {
2019         super.resetReaderIndex();
2020         return this;
2021     }
2022 
2023     @Override
2024     public CompositeByteBuf markWriterIndex() {
2025         super.markWriterIndex();
2026         return this;
2027     }
2028 
2029     @Override
2030     public CompositeByteBuf resetWriterIndex() {
2031         super.resetWriterIndex();
2032         return this;
2033     }
2034 
2035     @Override
2036     public CompositeByteBuf ensureWritable(int minWritableBytes) {
2037         super.ensureWritable(minWritableBytes);
2038         return this;
2039     }
2040 
2041     @Override
2042     public CompositeByteBuf getBytes(int index, ByteBuf dst) {
2043         return getBytes(index, dst, dst.writableBytes());
2044     }
2045 
2046     @Override
2047     public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
2048         getBytes(index, dst, dst.writerIndex(), length);
2049         dst.writerIndex(dst.writerIndex() + length);
2050         return this;
2051     }
2052 
2053     @Override
2054     public CompositeByteBuf getBytes(int index, byte[] dst) {
2055         return getBytes(index, dst, 0, dst.length);
2056     }
2057 
2058     @Override
2059     public CompositeByteBuf setBoolean(int index, boolean value) {
2060         return setByte(index, value? 1 : 0);
2061     }
2062 
2063     @Override
2064     public CompositeByteBuf setChar(int index, int value) {
2065         return setShort(index, value);
2066     }
2067 
2068     @Override
2069     public CompositeByteBuf setFloat(int index, float value) {
2070         return setInt(index, Float.floatToRawIntBits(value));
2071     }
2072 
2073     @Override
2074     public CompositeByteBuf setDouble(int index, double value) {
2075         return setLong(index, Double.doubleToRawLongBits(value));
2076     }
2077 
2078     @Override
2079     public CompositeByteBuf setBytes(int index, ByteBuf src) {
2080         super.setBytes(index, src, src.readableBytes());
2081         return this;
2082     }
2083 
2084     @Override
2085     public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
2086         super.setBytes(index, src, length);
2087         return this;
2088     }
2089 
2090     @Override
2091     public CompositeByteBuf setBytes(int index, byte[] src) {
2092         return setBytes(index, src, 0, src.length);
2093     }
2094 
2095     @Override
2096     public CompositeByteBuf setZero(int index, int length) {
2097         super.setZero(index, length);
2098         return this;
2099     }
2100 
2101     @Override
2102     public CompositeByteBuf readBytes(ByteBuf dst) {
2103         super.readBytes(dst, dst.writableBytes());
2104         return this;
2105     }
2106 
2107     @Override
2108     public CompositeByteBuf readBytes(ByteBuf dst, int length) {
2109         super.readBytes(dst, length);
2110         return this;
2111     }
2112 
2113     @Override
2114     public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
2115         super.readBytes(dst, dstIndex, length);
2116         return this;
2117     }
2118 
2119     @Override
2120     public CompositeByteBuf readBytes(byte[] dst) {
2121         super.readBytes(dst, 0, dst.length);
2122         return this;
2123     }
2124 
2125     @Override
2126     public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
2127         super.readBytes(dst, dstIndex, length);
2128         return this;
2129     }
2130 
2131     @Override
2132     public CompositeByteBuf readBytes(ByteBuffer dst) {
2133         super.readBytes(dst);
2134         return this;
2135     }
2136 
2137     @Override
2138     public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
2139         super.readBytes(out, length);
2140         return this;
2141     }
2142 
2143     @Override
2144     public CompositeByteBuf skipBytes(int length) {
2145         super.skipBytes(length);
2146         return this;
2147     }
2148 
2149     @Override
2150     public CompositeByteBuf writeBoolean(boolean value) {
2151         writeByte(value ? 1 : 0);
2152         return this;
2153     }
2154 
2155     @Override
2156     public CompositeByteBuf writeByte(int value) {
2157         ensureWritable0(1);
2158         _setByte(writerIndex++, value);
2159         return this;
2160     }
2161 
2162     @Override
2163     public CompositeByteBuf writeShort(int value) {
2164         super.writeShort(value);
2165         return this;
2166     }
2167 
2168     @Override
2169     public CompositeByteBuf writeMedium(int value) {
2170         super.writeMedium(value);
2171         return this;
2172     }
2173 
2174     @Override
2175     public CompositeByteBuf writeInt(int value) {
2176         super.writeInt(value);
2177         return this;
2178     }
2179 
2180     @Override
2181     public CompositeByteBuf writeLong(long value) {
2182         super.writeLong(value);
2183         return this;
2184     }
2185 
2186     @Override
2187     public CompositeByteBuf writeChar(int value) {
2188         super.writeShort(value);
2189         return this;
2190     }
2191 
2192     @Override
2193     public CompositeByteBuf writeFloat(float value) {
2194         super.writeInt(Float.floatToRawIntBits(value));
2195         return this;
2196     }
2197 
2198     @Override
2199     public CompositeByteBuf writeDouble(double value) {
2200         super.writeLong(Double.doubleToRawLongBits(value));
2201         return this;
2202     }
2203 
2204     @Override
2205     public CompositeByteBuf writeBytes(ByteBuf src) {
2206         super.writeBytes(src, src.readableBytes());
2207         return this;
2208     }
2209 
2210     @Override
2211     public CompositeByteBuf writeBytes(ByteBuf src, int length) {
2212         super.writeBytes(src, length);
2213         return this;
2214     }
2215 
2216     @Override
2217     public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
2218         super.writeBytes(src, srcIndex, length);
2219         return this;
2220     }
2221 
2222     @Override
2223     public CompositeByteBuf writeBytes(byte[] src) {
2224         super.writeBytes(src, 0, src.length);
2225         return this;
2226     }
2227 
2228     @Override
2229     public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
2230         super.writeBytes(src, srcIndex, length);
2231         return this;
2232     }
2233 
2234     @Override
2235     public CompositeByteBuf writeBytes(ByteBuffer src) {
2236         super.writeBytes(src);
2237         return this;
2238     }
2239 
2240     @Override
2241     public CompositeByteBuf writeZero(int length) {
2242         super.writeZero(length);
2243         return this;
2244     }
2245 
2246     @Override
2247     public CompositeByteBuf retain(int increment) {
2248         super.retain(increment);
2249         return this;
2250     }
2251 
2252     @Override
2253     public CompositeByteBuf retain() {
2254         super.retain();
2255         return this;
2256     }
2257 
2258     @Override
2259     public CompositeByteBuf touch() {
2260         return this;
2261     }
2262 
2263     @Override
2264     public CompositeByteBuf touch(Object hint) {
2265         return this;
2266     }
2267 
2268     @Override
2269     public ByteBuffer[] nioBuffers() {
2270         return nioBuffers(readerIndex(), readableBytes());
2271     }
2272 
2273     @Override
2274     public CompositeByteBuf discardSomeReadBytes() {
2275         return discardReadComponents();
2276     }
2277 
2278     @Override
2279     protected void deallocate() {
2280         if (freed) {
2281             return;
2282         }
2283 
2284         freed = true;
2285         // We're not using foreach to avoid creating an iterator.
2286         // see https://github.com/netty/netty/issues/2642
2287         for (int i = 0, size = componentCount; i < size; i++) {
2288             components[i].free();
2289         }
2290     }
2291 
2292     @Override
2293     boolean isAccessible() {
2294         return !freed;
2295     }
2296 
2297     @Override
2298     public ByteBuf unwrap() {
2299         return null;
2300     }
2301 
2302     private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
2303         private final int size = numComponents();
2304         private int index;
2305 
2306         @Override
2307         public boolean hasNext() {
2308             return size > index;
2309         }
2310 
2311         @Override
2312         public ByteBuf next() {
2313             if (size != numComponents()) {
2314                 throw new ConcurrentModificationException();
2315             }
2316             if (!hasNext()) {
2317                 throw new NoSuchElementException();
2318             }
2319             try {
2320                 return components[index++].slice();
2321             } catch (IndexOutOfBoundsException e) {
2322                 throw new ConcurrentModificationException();
2323             }
2324         }
2325 
2326         @Override
2327         public void remove() {
2328             throw new UnsupportedOperationException("Read-Only");
2329         }
2330     }
2331 
2332     // Component array manipulation - range checking omitted
2333 
2334     private void clearComps() {
2335         removeCompRange(0, componentCount);
2336     }
2337 
2338     private void removeComp(int i) {
2339         removeCompRange(i, i + 1);
2340     }
2341 
2342     private void removeCompRange(int from, int to) {
2343         if (from >= to) {
2344             return;
2345         }
2346         final int size = componentCount;
2347         assert from >= 0 && to <= size;
2348         if (to < size) {
2349             System.arraycopy(components, to, components, from, size - to);
2350         }
2351         int newSize = size - to + from;
2352         for (int i = newSize; i < size; i++) {
2353             components[i] = null;
2354         }
2355         componentCount = newSize;
2356     }
2357 
2358     private void addComp(int i, Component c) {
2359         shiftComps(i, 1);
2360         components[i] = c;
2361     }
2362 
2363     private void shiftComps(int i, int count) {
2364         final int size = componentCount, newSize = size + count;
2365         assert i >= 0 && i <= size && count > 0;
2366         if (newSize > components.length) {
2367             // grow the array
2368             int newArrSize = Math.max(size + (size >> 1), newSize);
2369             Component[] newArr;
2370             if (i == size) {
2371                 newArr = Arrays.copyOf(components, newArrSize, Component[].class);
2372             } else {
2373                 newArr = new Component[newArrSize];
2374                 if (i > 0) {
2375                     System.arraycopy(components, 0, newArr, 0, i);
2376                 }
2377                 if (i < size) {
2378                     System.arraycopy(components, i, newArr, i + count, size - i);
2379                 }
2380             }
2381             components = newArr;
2382         } else if (i < size) {
2383             System.arraycopy(components, i, components, i + count, size - i);
2384         }
2385         componentCount = newSize;
2386     }
2387 }