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 the {@link ByteBuf} on the specified index
1550      *
1551      * @param cIndex the index for which the {@link ByteBuf} should be returned
1552      * @return buf the {@link ByteBuf} on the specified index
1553      */
1554     public ByteBuf component(int cIndex) {
1555         checkComponentIndex(cIndex);
1556         return components[cIndex].duplicate();
1557     }
1558 
1559     /**
1560      * Return the {@link ByteBuf} on the specified index
1561      *
1562      * @param offset the offset for which the {@link ByteBuf} should be returned
1563      * @return the {@link ByteBuf} on the specified index
1564      */
1565     public ByteBuf componentAtOffset(int offset) {
1566         return findComponent(offset).duplicate();
1567     }
1568 
1569     /**
1570      * Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
1571      * buffer will lead to an undefined behavior of this buffer.
1572      *
1573      * @param cIndex the index for which the {@link ByteBuf} should be returned
1574      */
1575     public ByteBuf internalComponent(int cIndex) {
1576         checkComponentIndex(cIndex);
1577         return components[cIndex].slice();
1578     }
1579 
1580     /**
1581      * Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
1582      * buffer will lead to an undefined behavior of this buffer.
1583      *
1584      * @param offset the offset for which the {@link ByteBuf} should be returned
1585      */
1586     public ByteBuf internalComponentAtOffset(int offset) {
1587         return findComponent(offset).slice();
1588     }
1589 
1590     // weak cache - check it first when looking for component
1591     private Component lastAccessed;
1592 
1593     private Component findComponent(int offset) {
1594         Component la = lastAccessed;
1595         if (la != null && offset >= la.offset && offset < la.endOffset) {
1596            ensureAccessible();
1597            return la;
1598         }
1599         checkIndex(offset);
1600         return findIt(offset);
1601     }
1602 
1603     private Component findComponent0(int offset) {
1604         Component la = lastAccessed;
1605         if (la != null && offset >= la.offset && offset < la.endOffset) {
1606            return la;
1607         }
1608         return findIt(offset);
1609     }
1610 
1611     private Component findIt(int offset) {
1612         for (int low = 0, high = componentCount; low <= high;) {
1613             int mid = low + high >>> 1;
1614             Component c = components[mid];
1615             if (c == null) {
1616                 throw new IllegalStateException("No component found for offset. " +
1617                         "Composite buffer layout might be outdated, e.g. from a discardReadBytes call.");
1618             }
1619             if (offset >= c.endOffset) {
1620                 low = mid + 1;
1621             } else if (offset < c.offset) {
1622                 high = mid - 1;
1623             } else {
1624                 lastAccessed = c;
1625                 return c;
1626             }
1627         }
1628 
1629         throw new Error("should not reach here");
1630     }
1631 
1632     @Override
1633     public int nioBufferCount() {
1634         int size = componentCount;
1635         switch (size) {
1636         case 0:
1637             return 1;
1638         case 1:
1639             return components[0].buf.nioBufferCount();
1640         default:
1641             int count = 0;
1642             for (int i = 0; i < size; i++) {
1643                 count += components[i].buf.nioBufferCount();
1644             }
1645             return count;
1646         }
1647     }
1648 
1649     @Override
1650     public ByteBuffer internalNioBuffer(int index, int length) {
1651         switch (componentCount) {
1652         case 0:
1653             return EMPTY_NIO_BUFFER;
1654         case 1:
1655             return components[0].internalNioBuffer(index, length);
1656         default:
1657             throw new UnsupportedOperationException();
1658         }
1659     }
1660 
1661     @Override
1662     public ByteBuffer nioBuffer(int index, int length) {
1663         checkIndex(index, length);
1664 
1665         switch (componentCount) {
1666         case 0:
1667             return EMPTY_NIO_BUFFER;
1668         case 1:
1669             Component c = components[0];
1670             ByteBuf buf = c.buf;
1671             if (buf.nioBufferCount() == 1) {
1672                 return buf.nioBuffer(c.idx(index), length);
1673             }
1674             break;
1675         default:
1676             break;
1677         }
1678 
1679         ByteBuffer[] buffers = nioBuffers(index, length);
1680 
1681         if (buffers.length == 1) {
1682             return buffers[0];
1683         }
1684 
1685         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
1686         for (ByteBuffer buf: buffers) {
1687             merged.put(buf);
1688         }
1689 
1690         merged.flip();
1691         return merged;
1692     }
1693 
1694     @Override
1695     public ByteBuffer[] nioBuffers(int index, int length) {
1696         checkIndex(index, length);
1697         if (length == 0) {
1698             return new ByteBuffer[] { EMPTY_NIO_BUFFER };
1699         }
1700 
1701         RecyclableArrayList buffers = RecyclableArrayList.newInstance(componentCount);
1702         try {
1703             int i = toComponentIndex0(index);
1704             while (length > 0) {
1705                 Component c = components[i];
1706                 ByteBuf s = c.buf;
1707                 int localLength = Math.min(length, c.endOffset - index);
1708                 switch (s.nioBufferCount()) {
1709                 case 0:
1710                     throw new UnsupportedOperationException();
1711                 case 1:
1712                     buffers.add(s.nioBuffer(c.idx(index), localLength));
1713                     break;
1714                 default:
1715                     Collections.addAll(buffers, s.nioBuffers(c.idx(index), localLength));
1716                 }
1717 
1718                 index += localLength;
1719                 length -= localLength;
1720                 i ++;
1721             }
1722 
1723             return buffers.toArray(EmptyArrays.EMPTY_BYTE_BUFFERS);
1724         } finally {
1725             buffers.recycle();
1726         }
1727     }
1728 
1729     /**
1730      * Consolidate the composed {@link ByteBuf}s
1731      */
1732     public CompositeByteBuf consolidate() {
1733         ensureAccessible();
1734         consolidate0(0, componentCount);
1735         return this;
1736     }
1737 
1738     /**
1739      * Consolidate the composed {@link ByteBuf}s
1740      *
1741      * @param cIndex the index on which to start to compose
1742      * @param numComponents the number of components to compose
1743      */
1744     public CompositeByteBuf consolidate(int cIndex, int numComponents) {
1745         checkComponentIndex(cIndex, numComponents);
1746         consolidate0(cIndex, numComponents);
1747         return this;
1748     }
1749 
1750     private void consolidate0(int cIndex, int numComponents) {
1751         if (numComponents <= 1) {
1752             return;
1753         }
1754 
1755         final int endCIndex = cIndex + numComponents;
1756         final int startOffset = cIndex != 0 ? components[cIndex].offset : 0;
1757         final int capacity = components[endCIndex - 1].endOffset - startOffset;
1758         final ByteBuf consolidated = allocBuffer(capacity);
1759 
1760         for (int i = cIndex; i < endCIndex; i ++) {
1761             components[i].transferTo(consolidated);
1762         }
1763         lastAccessed = null;
1764         removeCompRange(cIndex + 1, endCIndex);
1765         components[cIndex] = newComponent(consolidated, 0);
1766         if (cIndex != 0 || numComponents != componentCount) {
1767             updateComponentOffsets(cIndex);
1768         }
1769     }
1770 
1771     /**
1772      * Discard all {@link ByteBuf}s which are read.
1773      */
1774     public CompositeByteBuf discardReadComponents() {
1775         ensureAccessible();
1776         final int readerIndex = readerIndex();
1777         if (readerIndex == 0) {
1778             return this;
1779         }
1780 
1781         // Discard everything if (readerIndex = writerIndex = capacity).
1782         int writerIndex = writerIndex();
1783         if (readerIndex == writerIndex && writerIndex == capacity()) {
1784             for (int i = 0, size = componentCount; i < size; i++) {
1785                 components[i].free();
1786             }
1787             lastAccessed = null;
1788             clearComps();
1789             setIndex(0, 0);
1790             adjustMarkers(readerIndex);
1791             return this;
1792         }
1793 
1794         // Remove read components.
1795         int firstComponentId = 0;
1796         Component c = null;
1797         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1798             c = components[firstComponentId];
1799             if (c.endOffset > readerIndex) {
1800                 break;
1801             }
1802             c.free();
1803         }
1804         if (firstComponentId == 0) {
1805             return this; // Nothing to discard
1806         }
1807         Component la = lastAccessed;
1808         if (la != null && la.endOffset <= readerIndex) {
1809             lastAccessed = null;
1810         }
1811         removeCompRange(0, firstComponentId);
1812 
1813         // Update indexes and markers.
1814         int offset = c.offset;
1815         updateComponentOffsets(0);
1816         setIndex(readerIndex - offset, writerIndex - offset);
1817         adjustMarkers(offset);
1818         return this;
1819     }
1820 
1821     @Override
1822     public CompositeByteBuf discardReadBytes() {
1823         ensureAccessible();
1824         final int readerIndex = readerIndex();
1825         if (readerIndex == 0) {
1826             return this;
1827         }
1828 
1829         // Discard everything if (readerIndex = writerIndex = capacity).
1830         int writerIndex = writerIndex();
1831         if (readerIndex == writerIndex && writerIndex == capacity()) {
1832             for (int i = 0, size = componentCount; i < size; i++) {
1833                 components[i].free();
1834             }
1835             lastAccessed = null;
1836             clearComps();
1837             setIndex(0, 0);
1838             adjustMarkers(readerIndex);
1839             return this;
1840         }
1841 
1842         int firstComponentId = 0;
1843         Component c = null;
1844         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1845             c = components[firstComponentId];
1846             if (c.endOffset > readerIndex) {
1847                 break;
1848             }
1849             c.free();
1850         }
1851 
1852         // Replace the first readable component with a new slice.
1853         int trimmedBytes = readerIndex - c.offset;
1854         c.offset = 0;
1855         c.endOffset -= readerIndex;
1856         c.srcAdjustment += readerIndex;
1857         c.adjustment += readerIndex;
1858         ByteBuf slice = c.slice;
1859         if (slice != null) {
1860             // We must replace the cached slice with a derived one to ensure that
1861             // it can later be released properly in the case of PooledSlicedByteBuf.
1862             c.slice = slice.slice(trimmedBytes, c.length());
1863         }
1864         Component la = lastAccessed;
1865         if (la != null && la.endOffset <= readerIndex) {
1866             lastAccessed = null;
1867         }
1868 
1869         removeCompRange(0, firstComponentId);
1870 
1871         // Update indexes and markers.
1872         updateComponentOffsets(0);
1873         setIndex(0, writerIndex - readerIndex);
1874         adjustMarkers(readerIndex);
1875         return this;
1876     }
1877 
1878     private ByteBuf allocBuffer(int capacity) {
1879         return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
1880     }
1881 
1882     @Override
1883     public String toString() {
1884         String result = super.toString();
1885         result = result.substring(0, result.length() - 1);
1886         return result + ", components=" + componentCount + ')';
1887     }
1888 
1889     private static final class Component {
1890         final ByteBuf srcBuf; // the originally added buffer
1891         final ByteBuf buf; // srcBuf unwrapped zero or more times
1892 
1893         int srcAdjustment; // index of the start of this CompositeByteBuf relative to srcBuf
1894         int adjustment; // index of the start of this CompositeByteBuf relative to buf
1895 
1896         int offset; // offset of this component within this CompositeByteBuf
1897         int endOffset; // end offset of this component within this CompositeByteBuf
1898 
1899         private ByteBuf slice; // cached slice, may be null
1900 
1901         Component(ByteBuf srcBuf, int srcOffset, ByteBuf buf, int bufOffset,
1902                 int offset, int len, ByteBuf slice) {
1903             this.srcBuf = srcBuf;
1904             this.srcAdjustment = srcOffset - offset;
1905             this.buf = buf;
1906             this.adjustment = bufOffset - offset;
1907             this.offset = offset;
1908             this.endOffset = offset + len;
1909             this.slice = slice;
1910         }
1911 
1912         int srcIdx(int index) {
1913             return index + srcAdjustment;
1914         }
1915 
1916         int idx(int index) {
1917             return index + adjustment;
1918         }
1919 
1920         int length() {
1921             return endOffset - offset;
1922         }
1923 
1924         void reposition(int newOffset) {
1925             int move = newOffset - offset;
1926             endOffset += move;
1927             srcAdjustment -= move;
1928             adjustment -= move;
1929             offset = newOffset;
1930         }
1931 
1932         // copy then release
1933         void transferTo(ByteBuf dst) {
1934             dst.writeBytes(buf, idx(offset), length());
1935             free();
1936         }
1937 
1938         ByteBuf slice() {
1939             ByteBuf s = slice;
1940             if (s == null) {
1941                 slice = s = srcBuf.slice(srcIdx(offset), length());
1942             }
1943             return s;
1944         }
1945 
1946         ByteBuf duplicate() {
1947             return srcBuf.duplicate();
1948         }
1949 
1950         ByteBuffer internalNioBuffer(int index, int length) {
1951             // Some buffers override this so we must use srcBuf
1952             return srcBuf.internalNioBuffer(srcIdx(index), length);
1953         }
1954 
1955         void free() {
1956             slice = null;
1957             // Release the original buffer since it may have a different
1958             // refcount to the unwrapped buf (e.g. if PooledSlicedByteBuf)
1959             srcBuf.release();
1960         }
1961     }
1962 
1963     @Override
1964     public CompositeByteBuf readerIndex(int readerIndex) {
1965         super.readerIndex(readerIndex);
1966         return this;
1967     }
1968 
1969     @Override
1970     public CompositeByteBuf writerIndex(int writerIndex) {
1971         super.writerIndex(writerIndex);
1972         return this;
1973     }
1974 
1975     @Override
1976     public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
1977         super.setIndex(readerIndex, writerIndex);
1978         return this;
1979     }
1980 
1981     @Override
1982     public CompositeByteBuf clear() {
1983         super.clear();
1984         return this;
1985     }
1986 
1987     @Override
1988     public CompositeByteBuf markReaderIndex() {
1989         super.markReaderIndex();
1990         return this;
1991     }
1992 
1993     @Override
1994     public CompositeByteBuf resetReaderIndex() {
1995         super.resetReaderIndex();
1996         return this;
1997     }
1998 
1999     @Override
2000     public CompositeByteBuf markWriterIndex() {
2001         super.markWriterIndex();
2002         return this;
2003     }
2004 
2005     @Override
2006     public CompositeByteBuf resetWriterIndex() {
2007         super.resetWriterIndex();
2008         return this;
2009     }
2010 
2011     @Override
2012     public CompositeByteBuf ensureWritable(int minWritableBytes) {
2013         super.ensureWritable(minWritableBytes);
2014         return this;
2015     }
2016 
2017     @Override
2018     public CompositeByteBuf getBytes(int index, ByteBuf dst) {
2019         return getBytes(index, dst, dst.writableBytes());
2020     }
2021 
2022     @Override
2023     public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
2024         getBytes(index, dst, dst.writerIndex(), length);
2025         dst.writerIndex(dst.writerIndex() + length);
2026         return this;
2027     }
2028 
2029     @Override
2030     public CompositeByteBuf getBytes(int index, byte[] dst) {
2031         return getBytes(index, dst, 0, dst.length);
2032     }
2033 
2034     @Override
2035     public CompositeByteBuf setBoolean(int index, boolean value) {
2036         return setByte(index, value? 1 : 0);
2037     }
2038 
2039     @Override
2040     public CompositeByteBuf setChar(int index, int value) {
2041         return setShort(index, value);
2042     }
2043 
2044     @Override
2045     public CompositeByteBuf setFloat(int index, float value) {
2046         return setInt(index, Float.floatToRawIntBits(value));
2047     }
2048 
2049     @Override
2050     public CompositeByteBuf setDouble(int index, double value) {
2051         return setLong(index, Double.doubleToRawLongBits(value));
2052     }
2053 
2054     @Override
2055     public CompositeByteBuf setBytes(int index, ByteBuf src) {
2056         super.setBytes(index, src, src.readableBytes());
2057         return this;
2058     }
2059 
2060     @Override
2061     public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
2062         super.setBytes(index, src, length);
2063         return this;
2064     }
2065 
2066     @Override
2067     public CompositeByteBuf setBytes(int index, byte[] src) {
2068         return setBytes(index, src, 0, src.length);
2069     }
2070 
2071     @Override
2072     public CompositeByteBuf setZero(int index, int length) {
2073         super.setZero(index, length);
2074         return this;
2075     }
2076 
2077     @Override
2078     public CompositeByteBuf readBytes(ByteBuf dst) {
2079         super.readBytes(dst, dst.writableBytes());
2080         return this;
2081     }
2082 
2083     @Override
2084     public CompositeByteBuf readBytes(ByteBuf dst, int length) {
2085         super.readBytes(dst, length);
2086         return this;
2087     }
2088 
2089     @Override
2090     public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
2091         super.readBytes(dst, dstIndex, length);
2092         return this;
2093     }
2094 
2095     @Override
2096     public CompositeByteBuf readBytes(byte[] dst) {
2097         super.readBytes(dst, 0, dst.length);
2098         return this;
2099     }
2100 
2101     @Override
2102     public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
2103         super.readBytes(dst, dstIndex, length);
2104         return this;
2105     }
2106 
2107     @Override
2108     public CompositeByteBuf readBytes(ByteBuffer dst) {
2109         super.readBytes(dst);
2110         return this;
2111     }
2112 
2113     @Override
2114     public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
2115         super.readBytes(out, length);
2116         return this;
2117     }
2118 
2119     @Override
2120     public CompositeByteBuf skipBytes(int length) {
2121         super.skipBytes(length);
2122         return this;
2123     }
2124 
2125     @Override
2126     public CompositeByteBuf writeBoolean(boolean value) {
2127         writeByte(value ? 1 : 0);
2128         return this;
2129     }
2130 
2131     @Override
2132     public CompositeByteBuf writeByte(int value) {
2133         ensureWritable0(1);
2134         _setByte(writerIndex++, value);
2135         return this;
2136     }
2137 
2138     @Override
2139     public CompositeByteBuf writeShort(int value) {
2140         super.writeShort(value);
2141         return this;
2142     }
2143 
2144     @Override
2145     public CompositeByteBuf writeMedium(int value) {
2146         super.writeMedium(value);
2147         return this;
2148     }
2149 
2150     @Override
2151     public CompositeByteBuf writeInt(int value) {
2152         super.writeInt(value);
2153         return this;
2154     }
2155 
2156     @Override
2157     public CompositeByteBuf writeLong(long value) {
2158         super.writeLong(value);
2159         return this;
2160     }
2161 
2162     @Override
2163     public CompositeByteBuf writeChar(int value) {
2164         super.writeShort(value);
2165         return this;
2166     }
2167 
2168     @Override
2169     public CompositeByteBuf writeFloat(float value) {
2170         super.writeInt(Float.floatToRawIntBits(value));
2171         return this;
2172     }
2173 
2174     @Override
2175     public CompositeByteBuf writeDouble(double value) {
2176         super.writeLong(Double.doubleToRawLongBits(value));
2177         return this;
2178     }
2179 
2180     @Override
2181     public CompositeByteBuf writeBytes(ByteBuf src) {
2182         super.writeBytes(src, src.readableBytes());
2183         return this;
2184     }
2185 
2186     @Override
2187     public CompositeByteBuf writeBytes(ByteBuf src, int length) {
2188         super.writeBytes(src, length);
2189         return this;
2190     }
2191 
2192     @Override
2193     public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
2194         super.writeBytes(src, srcIndex, length);
2195         return this;
2196     }
2197 
2198     @Override
2199     public CompositeByteBuf writeBytes(byte[] src) {
2200         super.writeBytes(src, 0, src.length);
2201         return this;
2202     }
2203 
2204     @Override
2205     public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
2206         super.writeBytes(src, srcIndex, length);
2207         return this;
2208     }
2209 
2210     @Override
2211     public CompositeByteBuf writeBytes(ByteBuffer src) {
2212         super.writeBytes(src);
2213         return this;
2214     }
2215 
2216     @Override
2217     public CompositeByteBuf writeZero(int length) {
2218         super.writeZero(length);
2219         return this;
2220     }
2221 
2222     @Override
2223     public CompositeByteBuf retain(int increment) {
2224         super.retain(increment);
2225         return this;
2226     }
2227 
2228     @Override
2229     public CompositeByteBuf retain() {
2230         super.retain();
2231         return this;
2232     }
2233 
2234     @Override
2235     public CompositeByteBuf touch() {
2236         return this;
2237     }
2238 
2239     @Override
2240     public CompositeByteBuf touch(Object hint) {
2241         return this;
2242     }
2243 
2244     @Override
2245     public ByteBuffer[] nioBuffers() {
2246         return nioBuffers(readerIndex(), readableBytes());
2247     }
2248 
2249     @Override
2250     public CompositeByteBuf discardSomeReadBytes() {
2251         return discardReadComponents();
2252     }
2253 
2254     @Override
2255     protected void deallocate() {
2256         if (freed) {
2257             return;
2258         }
2259 
2260         freed = true;
2261         // We're not using foreach to avoid creating an iterator.
2262         // see https://github.com/netty/netty/issues/2642
2263         for (int i = 0, size = componentCount; i < size; i++) {
2264             components[i].free();
2265         }
2266     }
2267 
2268     @Override
2269     boolean isAccessible() {
2270         return !freed;
2271     }
2272 
2273     @Override
2274     public ByteBuf unwrap() {
2275         return null;
2276     }
2277 
2278     private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
2279         private final int size = numComponents();
2280         private int index;
2281 
2282         @Override
2283         public boolean hasNext() {
2284             return size > index;
2285         }
2286 
2287         @Override
2288         public ByteBuf next() {
2289             if (size != numComponents()) {
2290                 throw new ConcurrentModificationException();
2291             }
2292             if (!hasNext()) {
2293                 throw new NoSuchElementException();
2294             }
2295             try {
2296                 return components[index++].slice();
2297             } catch (IndexOutOfBoundsException e) {
2298                 throw new ConcurrentModificationException();
2299             }
2300         }
2301 
2302         @Override
2303         public void remove() {
2304             throw new UnsupportedOperationException("Read-Only");
2305         }
2306     }
2307 
2308     // Component array manipulation - range checking omitted
2309 
2310     private void clearComps() {
2311         removeCompRange(0, componentCount);
2312     }
2313 
2314     private void removeComp(int i) {
2315         removeCompRange(i, i + 1);
2316     }
2317 
2318     private void removeCompRange(int from, int to) {
2319         if (from >= to) {
2320             return;
2321         }
2322         final int size = componentCount;
2323         assert from >= 0 && to <= size;
2324         if (to < size) {
2325             System.arraycopy(components, to, components, from, size - to);
2326         }
2327         int newSize = size - to + from;
2328         for (int i = newSize; i < size; i++) {
2329             components[i] = null;
2330         }
2331         componentCount = newSize;
2332     }
2333 
2334     private void addComp(int i, Component c) {
2335         shiftComps(i, 1);
2336         components[i] = c;
2337     }
2338 
2339     private void shiftComps(int i, int count) {
2340         final int size = componentCount, newSize = size + count;
2341         assert i >= 0 && i <= size && count > 0;
2342         if (newSize > components.length) {
2343             // grow the array
2344             int newArrSize = Math.max(size + (size >> 1), newSize);
2345             Component[] newArr;
2346             if (i == size) {
2347                 newArr = Arrays.copyOf(components, newArrSize, Component[].class);
2348             } else {
2349                 newArr = new Component[newArrSize];
2350                 if (i > 0) {
2351                     System.arraycopy(components, 0, newArr, 0, i);
2352                 }
2353                 if (i < size) {
2354                     System.arraycopy(components, i, newArr, i + count, size - i);
2355                 }
2356             }
2357             components = newArr;
2358         } else if (i < size) {
2359             System.arraycopy(components, i, components, i + count, size - i);
2360         }
2361         componentCount = newSize;
2362     }
2363 }