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             lastAccessedIndex = 0;
619         }
620         comp.free();
621         removeComp(cIndex);
622         if (comp.length() > 0) {
623             // Only need to call updateComponentOffsets if the length was > 0
624             updateComponentOffsets(cIndex);
625         }
626         return this;
627     }
628 
629     /**
630      * Remove the number of {@link ByteBuf}s starting from the given index.
631      *
632      * @param cIndex the index on which the {@link ByteBuf}s will be started to removed
633      * @param numComponents the number of components to remove
634      */
635     public CompositeByteBuf removeComponents(int cIndex, int numComponents) {
636         checkComponentIndex(cIndex, numComponents);
637 
638         if (numComponents == 0) {
639             return this;
640         }
641         int endIndex = cIndex + numComponents;
642         boolean needsUpdate = false;
643         for (int i = cIndex; i < endIndex; ++i) {
644             Component c = components[i];
645             if (c.length() > 0) {
646                 needsUpdate = true;
647             }
648             if (lastAccessed == c) {
649                 lastAccessed = null;
650                 lastAccessedIndex = 0;
651             }
652             c.free();
653         }
654         removeCompRange(cIndex, endIndex);
655 
656         if (needsUpdate) {
657             // Only need to call updateComponentOffsets if the length was > 0
658             updateComponentOffsets(cIndex);
659         }
660         return this;
661     }
662 
663     @Override
664     public Iterator<ByteBuf> iterator() {
665         ensureAccessible();
666         return componentCount == 0 ? EMPTY_ITERATOR : new CompositeByteBufIterator();
667     }
668 
669     @Override
670     protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
671         if (end <= start) {
672             return -1;
673         }
674         for (int i = toComponentIndex0(start), length = end - start; length > 0; i++) {
675             Component c = components[i];
676             if (c.offset == c.endOffset) {
677                 continue; // empty
678             }
679             ByteBuf s = c.buf;
680             int localStart = c.idx(start);
681             int localLength = Math.min(length, c.endOffset - start);
682             // avoid additional checks in AbstractByteBuf case
683             int result = s instanceof AbstractByteBuf
684                 ? ((AbstractByteBuf) s).forEachByteAsc0(localStart, localStart + localLength, processor)
685                 : s.forEachByte(localStart, localLength, processor);
686             if (result != -1) {
687                 return result - c.adjustment;
688             }
689             start += localLength;
690             length -= localLength;
691         }
692         return -1;
693     }
694 
695     @Override
696     protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) throws Exception {
697         if (rEnd > rStart) { // rStart *and* rEnd are inclusive
698             return -1;
699         }
700         for (int i = toComponentIndex0(rStart), length = 1 + rStart - rEnd; length > 0; i--) {
701             Component c = components[i];
702             if (c.offset == c.endOffset) {
703                 continue; // empty
704             }
705             ByteBuf s = c.buf;
706             int localRStart = c.idx(length + rEnd);
707             int localLength = Math.min(length, localRStart), localIndex = localRStart - localLength;
708             // avoid additional checks in AbstractByteBuf case
709             int result = s instanceof AbstractByteBuf
710                 ? ((AbstractByteBuf) s).forEachByteDesc0(localRStart - 1, localIndex, processor)
711                 : s.forEachByteDesc(localIndex, localLength, processor);
712 
713             if (result != -1) {
714                 return result - c.adjustment;
715             }
716             length -= localLength;
717         }
718         return -1;
719     }
720 
721     /**
722      * Same with {@link #slice(int, int)} except that this method returns a list.
723      */
724     public List<ByteBuf> decompose(int offset, int length) {
725         checkIndex(offset, length);
726         if (length == 0) {
727             return Collections.emptyList();
728         }
729 
730         int componentId = toComponentIndex0(offset);
731         int bytesToSlice = length;
732         // The first component
733         Component firstC = components[componentId];
734 
735         // It's important to use srcBuf and NOT buf as we need to return the "original" source buffer and not the
736         // unwrapped one as otherwise we could loose the ability to correctly update the reference count on the
737         // returned buffer.
738         ByteBuf slice = firstC.srcBuf.slice(firstC.srcIdx(offset), Math.min(firstC.endOffset - offset, bytesToSlice));
739         bytesToSlice -= slice.readableBytes();
740 
741         if (bytesToSlice == 0) {
742             return Collections.singletonList(slice);
743         }
744 
745         List<ByteBuf> sliceList = new ArrayList<ByteBuf>(componentCount - componentId);
746         sliceList.add(slice);
747 
748         // Add all the slices until there is nothing more left and then return the List.
749         do {
750             Component component = components[++componentId];
751             // It's important to use srcBuf and NOT buf as we need to return the "original" source buffer and not the
752             // unwrapped one as otherwise we could loose the ability to correctly update the reference count on the
753             // returned buffer.
754             slice = component.srcBuf.slice(component.srcIdx(component.offset),
755                     Math.min(component.length(), bytesToSlice));
756             bytesToSlice -= slice.readableBytes();
757             sliceList.add(slice);
758         } while (bytesToSlice > 0);
759 
760         return sliceList;
761     }
762 
763     @Override
764     public boolean isDirect() {
765         int size = componentCount;
766         if (size == 0) {
767             return false;
768         }
769         for (int i = 0; i < size; i++) {
770            if (!components[i].buf.isDirect()) {
771                return false;
772            }
773         }
774         return true;
775     }
776 
777     @Override
778     public boolean hasArray() {
779         switch (componentCount) {
780         case 0:
781             return true;
782         case 1:
783             return components[0].buf.hasArray();
784         default:
785             return false;
786         }
787     }
788 
789     @Override
790     public byte[] array() {
791         switch (componentCount) {
792         case 0:
793             return EmptyArrays.EMPTY_BYTES;
794         case 1:
795             return components[0].buf.array();
796         default:
797             throw new UnsupportedOperationException();
798         }
799     }
800 
801     @Override
802     public int arrayOffset() {
803         switch (componentCount) {
804         case 0:
805             return 0;
806         case 1:
807             Component c = components[0];
808             return c.idx(c.buf.arrayOffset());
809         default:
810             throw new UnsupportedOperationException();
811         }
812     }
813 
814     @Override
815     public boolean hasMemoryAddress() {
816         switch (componentCount) {
817         case 0:
818             return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
819         case 1:
820             return components[0].buf.hasMemoryAddress();
821         default:
822             return false;
823         }
824     }
825 
826     @Override
827     public long memoryAddress() {
828         switch (componentCount) {
829         case 0:
830             return Unpooled.EMPTY_BUFFER.memoryAddress();
831         case 1:
832             Component c = components[0];
833             return c.buf.memoryAddress() + c.adjustment;
834         default:
835             throw new UnsupportedOperationException();
836         }
837     }
838 
839     @Override
840     public int capacity() {
841         int size = componentCount;
842         return size > 0 ? components[size - 1].endOffset : 0;
843     }
844 
845     @Override
846     public CompositeByteBuf capacity(int newCapacity) {
847         checkNewCapacity(newCapacity);
848 
849         final int size = componentCount, oldCapacity = capacity();
850         if (newCapacity > oldCapacity) {
851             final int paddingLength = newCapacity - oldCapacity;
852             ByteBuf padding = allocBuffer(paddingLength).setIndex(0, paddingLength);
853             addComponent0(false, size, padding);
854             if (componentCount >= maxNumComponents) {
855                 // FIXME: No need to create a padding buffer and consolidate.
856                 // Just create a big single buffer and put the current content there.
857                 consolidateIfNeeded();
858             }
859         } else if (newCapacity < oldCapacity) {
860             lastAccessed = null;
861             lastAccessedIndex = 0;
862             int i = size - 1;
863             for (int bytesToTrim = oldCapacity - newCapacity; i >= 0; i--) {
864                 Component c = components[i];
865                 final int cLength = c.length();
866                 if (bytesToTrim < cLength) {
867                     // Trim the last component
868                     c.endOffset -= bytesToTrim;
869                     ByteBuf slice = c.slice;
870                     if (slice != null) {
871                         // We must replace the cached slice with a derived one to ensure that
872                         // it can later be released properly in the case of PooledSlicedByteBuf.
873                         c.slice = slice.slice(0, c.length());
874                     }
875                     break;
876                 }
877                 c.free();
878                 bytesToTrim -= cLength;
879             }
880             removeCompRange(i + 1, size);
881 
882             if (readerIndex() > newCapacity) {
883                 setIndex0(newCapacity, newCapacity);
884             } else if (writerIndex > newCapacity) {
885                 writerIndex = newCapacity;
886             }
887         }
888         return this;
889     }
890 
891     @Override
892     public ByteBufAllocator alloc() {
893         return alloc;
894     }
895 
896     @Override
897     public ByteOrder order() {
898         return ByteOrder.BIG_ENDIAN;
899     }
900 
901     /**
902      * Return the current number of {@link ByteBuf}'s that are composed in this instance
903      */
904     public int numComponents() {
905         return componentCount;
906     }
907 
908     /**
909      * Return the max number of {@link ByteBuf}'s that are composed in this instance
910      */
911     public int maxNumComponents() {
912         return maxNumComponents;
913     }
914 
915     /**
916      * Return the index for the given offset
917      */
918     public int toComponentIndex(int offset) {
919         checkIndex(offset);
920         return toComponentIndex0(offset);
921     }
922 
923     private int toComponentIndex0(int offset) {
924         int size = componentCount;
925         if (offset == 0) { // fast-path zero offset
926             for (int i = 0; i < size; i++) {
927                 if (components[i].endOffset > 0) {
928                     return i;
929                 }
930             }
931         }
932         if (size <= 2) { // fast-path for 1 and 2 component count
933             return size == 1 || offset < components[0].endOffset ? 0 : 1;
934         }
935         for (int low = 0, high = size; low <= high;) {
936             int mid = low + high >>> 1;
937             Component c = components[mid];
938             if (offset >= c.endOffset) {
939                 low = mid + 1;
940             } else if (offset < c.offset) {
941                 high = mid - 1;
942             } else {
943                 return mid;
944             }
945         }
946 
947         throw new Error("should not reach here");
948     }
949 
950     public int toByteIndex(int cIndex) {
951         checkComponentIndex(cIndex);
952         return components[cIndex].offset;
953     }
954 
955     @Override
956     public byte getByte(int index) {
957         Component c = findComponent(index);
958         return c.abuf != null ? c.abuf._getByte(c.idx(index)) : c.buf.getByte(c.idx(index));
959     }
960 
961     @Override
962     public byte readByte() {
963         checkReadableBytes(1);
964         int rIdx = readerIndex;
965         Component c = lastAccessed;
966         if (c == null) {
967             c = findIt(rIdx);
968         } else if (rIdx >= c.endOffset) {
969             c = findComponentForRead(rIdx);
970         } else if (rIdx < c.offset) {
971             c = findIt(rIdx);
972         }
973         readerIndex = rIdx + 1;
974         return c.abuf != null ? c.abuf._getByte(rIdx + c.adjustment) : c.buf.getByte(rIdx + c.adjustment);
975     }
976 
977     @Override
978     protected byte _getByte(int index) {
979         Component c = findComponent0(index);
980         return c.abuf != null ? c.abuf._getByte(c.idx(index)) : c.buf.getByte(c.idx(index));
981     }
982 
983     @Override
984     protected short _getShort(int index) {
985         Component c = findComponent0(index);
986         if (index + 2 <= c.endOffset) {
987             return c.abuf != null ? c.abuf._getShort(c.idx(index)) : c.buf.getShort(c.idx(index));
988         } else if (order() == ByteOrder.BIG_ENDIAN) {
989             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
990         } else {
991             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
992         }
993     }
994 
995     @Override
996     protected short _getShortLE(int index) {
997         Component c = findComponent0(index);
998         if (index + 2 <= c.endOffset) {
999             return c.abuf != null ? c.abuf._getShortLE(c.idx(index)) : c.buf.getShortLE(c.idx(index));
1000         } else if (order() == ByteOrder.BIG_ENDIAN) {
1001             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
1002         } else {
1003             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
1004         }
1005     }
1006 
1007     @Override
1008     protected int _getUnsignedMedium(int index) {
1009         Component c = findComponent0(index);
1010         if (index + 3 <= c.endOffset) {
1011             return c.abuf != null ? c.abuf._getUnsignedMedium(c.idx(index))
1012                     : c.buf.getUnsignedMedium(c.idx(index));
1013         } else if (order() == ByteOrder.BIG_ENDIAN) {
1014             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
1015         } else {
1016             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
1017         }
1018     }
1019 
1020     @Override
1021     protected int _getUnsignedMediumLE(int index) {
1022         Component c = findComponent0(index);
1023         if (index + 3 <= c.endOffset) {
1024             return c.abuf != null ? c.abuf._getUnsignedMediumLE(c.idx(index))
1025                     : c.buf.getUnsignedMediumLE(c.idx(index));
1026         } else if (order() == ByteOrder.BIG_ENDIAN) {
1027             return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16;
1028         } else {
1029             return (_getShortLE(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
1030         }
1031     }
1032 
1033     @Override
1034     protected int _getInt(int index) {
1035         Component c = findComponent0(index);
1036         if (index + 4 <= c.endOffset) {
1037             return c.abuf != null ? c.abuf._getInt(c.idx(index)) : c.buf.getInt(c.idx(index));
1038         } else if (order() == ByteOrder.BIG_ENDIAN) {
1039             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
1040         } else {
1041             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
1042         }
1043     }
1044 
1045     @Override
1046     protected int _getIntLE(int index) {
1047         Component c = findComponent0(index);
1048         if (index + 4 <= c.endOffset) {
1049             return c.abuf != null ? c.abuf._getIntLE(c.idx(index)) : c.buf.getIntLE(c.idx(index));
1050         } else if (order() == ByteOrder.BIG_ENDIAN) {
1051             return _getShortLE(index) & 0xffff | (_getShortLE(index + 2) & 0xffff) << 16;
1052         } else {
1053             return (_getShortLE(index) & 0xffff) << 16 | _getShortLE(index + 2) & 0xffff;
1054         }
1055     }
1056 
1057     @Override
1058     protected long _getLong(int index) {
1059         Component c = findComponent0(index);
1060         if (index + 8 <= c.endOffset) {
1061             return c.abuf != null ? c.abuf._getLong(c.idx(index)) : c.buf.getLong(c.idx(index));
1062         } else if (order() == ByteOrder.BIG_ENDIAN) {
1063             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
1064         } else {
1065             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
1066         }
1067     }
1068 
1069     @Override
1070     protected long _getLongLE(int index) {
1071         Component c = findComponent0(index);
1072         if (index + 8 <= c.endOffset) {
1073             return c.abuf != null ? c.abuf._getLongLE(c.idx(index)) : c.buf.getLongLE(c.idx(index));
1074         } else if (order() == ByteOrder.BIG_ENDIAN) {
1075             return _getIntLE(index) & 0xffffffffL | (_getIntLE(index + 4) & 0xffffffffL) << 32;
1076         } else {
1077             return (_getIntLE(index) & 0xffffffffL) << 32 | _getIntLE(index + 4) & 0xffffffffL;
1078         }
1079     }
1080 
1081     @Override
1082     public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
1083         checkDstIndex(index, length, dstIndex, dst.length);
1084         if (length == 0) {
1085             return this;
1086         }
1087 
1088         int i = toComponentIndex0(index);
1089         while (length > 0) {
1090             Component c = components[i];
1091             int localLength = Math.min(length, c.endOffset - index);
1092             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1093             index += localLength;
1094             dstIndex += localLength;
1095             length -= localLength;
1096             i ++;
1097         }
1098         return this;
1099     }
1100 
1101     @Override
1102     public CompositeByteBuf getBytes(int index, ByteBuffer dst) {
1103         int limit = dst.limit();
1104         int length = dst.remaining();
1105 
1106         checkIndex(index, length);
1107         if (length == 0) {
1108             return this;
1109         }
1110 
1111         int i = toComponentIndex0(index);
1112         try {
1113             while (length > 0) {
1114                 Component c = components[i];
1115                 int localLength = Math.min(length, c.endOffset - index);
1116                 dst.limit(dst.position() + localLength);
1117                 c.buf.getBytes(c.idx(index), dst);
1118                 index += localLength;
1119                 length -= localLength;
1120                 i ++;
1121             }
1122         } finally {
1123             dst.limit(limit);
1124         }
1125         return this;
1126     }
1127 
1128     @Override
1129     public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
1130         checkDstIndex(index, length, dstIndex, dst.capacity());
1131         if (length == 0) {
1132             return this;
1133         }
1134 
1135         int i = toComponentIndex0(index);
1136         while (length > 0) {
1137             Component c = components[i];
1138             int localLength = Math.min(length, c.endOffset - index);
1139             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1140             index += localLength;
1141             dstIndex += localLength;
1142             length -= localLength;
1143             i ++;
1144         }
1145         return this;
1146     }
1147 
1148     @Override
1149     public int getBytes(int index, GatheringByteChannel out, int length)
1150             throws IOException {
1151         int count = nioBufferCount();
1152         if (count == 1) {
1153             return out.write(internalNioBuffer(index, length));
1154         } else {
1155             long writtenBytes = out.write(nioBuffers(index, length));
1156             if (writtenBytes > Integer.MAX_VALUE) {
1157                 return Integer.MAX_VALUE;
1158             } else {
1159                 return (int) writtenBytes;
1160             }
1161         }
1162     }
1163 
1164     @Override
1165     public int getBytes(int index, FileChannel out, long position, int length)
1166             throws IOException {
1167         int count = nioBufferCount();
1168         if (count == 1) {
1169             return out.write(internalNioBuffer(index, length), position);
1170         } else {
1171             long writtenBytes = 0;
1172             for (ByteBuffer buf : nioBuffers(index, length)) {
1173                 writtenBytes += out.write(buf, position + writtenBytes);
1174             }
1175             if (writtenBytes > Integer.MAX_VALUE) {
1176                 return Integer.MAX_VALUE;
1177             }
1178             return (int) writtenBytes;
1179         }
1180     }
1181 
1182     @Override
1183     public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
1184         checkIndex(index, length);
1185         if (length == 0) {
1186             return this;
1187         }
1188 
1189         int i = toComponentIndex0(index);
1190         while (length > 0) {
1191             Component c = components[i];
1192             int localLength = Math.min(length, c.endOffset - index);
1193             c.buf.getBytes(c.idx(index), out, localLength);
1194             index += localLength;
1195             length -= localLength;
1196             i ++;
1197         }
1198         return this;
1199     }
1200 
1201     @Override
1202     public CompositeByteBuf setByte(int index, int value) {
1203         Component c = findComponent(index);
1204         if (c.abuf != null) {
1205             c.abuf._setByte(c.idx(index), value);
1206         } else {
1207             c.buf.setByte(c.idx(index), value);
1208         }
1209         return this;
1210     }
1211 
1212     @Override
1213     protected void _setByte(int index, int value) {
1214         Component c = findComponent0(index);
1215         if (c.abuf != null) {
1216             c.abuf._setByte(c.idx(index), value);
1217         } else {
1218             c.buf.setByte(c.idx(index), value);
1219         }
1220     }
1221 
1222     @Override
1223     public CompositeByteBuf setShort(int index, int value) {
1224         checkIndex(index, 2);
1225         _setShort(index, value);
1226         return this;
1227     }
1228 
1229     @Override
1230     protected void _setShort(int index, int value) {
1231         Component c = findComponent0(index);
1232         if (index + 2 <= c.endOffset) {
1233             if (c.abuf != null) {
1234                 c.abuf._setShort(c.idx(index), value);
1235             } else {
1236                 c.buf.setShort(c.idx(index), value);
1237             }
1238         } else if (order() == ByteOrder.BIG_ENDIAN) {
1239             _setByte(index, (byte) (value >>> 8));
1240             _setByte(index + 1, (byte) value);
1241         } else {
1242             _setByte(index, (byte) value);
1243             _setByte(index + 1, (byte) (value >>> 8));
1244         }
1245     }
1246 
1247     @Override
1248     protected void _setShortLE(int index, int value) {
1249         Component c = findComponent0(index);
1250         if (index + 2 <= c.endOffset) {
1251             if (c.abuf != null) {
1252                 c.abuf._setShortLE(c.idx(index), value);
1253             } else {
1254                 c.buf.setShortLE(c.idx(index), value);
1255             }
1256         } else if (order() == ByteOrder.BIG_ENDIAN) {
1257             _setByte(index, (byte) value);
1258             _setByte(index + 1, (byte) (value >>> 8));
1259         } else {
1260             _setByte(index, (byte) (value >>> 8));
1261             _setByte(index + 1, (byte) value);
1262         }
1263     }
1264 
1265     @Override
1266     public CompositeByteBuf setMedium(int index, int value) {
1267         checkIndex(index, 3);
1268         _setMedium(index, value);
1269         return this;
1270     }
1271 
1272     @Override
1273     protected void _setMedium(int index, int value) {
1274         Component c = findComponent0(index);
1275         if (index + 3 <= c.endOffset) {
1276             if (c.abuf != null) {
1277                 c.abuf._setMedium(c.idx(index), value);
1278             } else {
1279                 c.buf.setMedium(c.idx(index), value);
1280             }
1281         } else if (order() == ByteOrder.BIG_ENDIAN) {
1282             _setShort(index, (short) (value >> 8));
1283             _setByte(index + 2, (byte) value);
1284         } else {
1285             _setShort(index, (short) value);
1286             _setByte(index + 2, (byte) (value >>> 16));
1287         }
1288     }
1289 
1290     @Override
1291     protected void _setMediumLE(int index, int value) {
1292         Component c = findComponent0(index);
1293         if (index + 3 <= c.endOffset) {
1294             if (c.abuf != null) {
1295                 c.abuf._setMediumLE(c.idx(index), value);
1296             } else {
1297                 c.buf.setMediumLE(c.idx(index), value);
1298             }
1299         } else if (order() == ByteOrder.BIG_ENDIAN) {
1300             _setShortLE(index, (short) value);
1301             _setByte(index + 2, (byte) (value >>> 16));
1302         } else {
1303             _setShortLE(index, (short) (value >> 8));
1304             _setByte(index + 2, (byte) value);
1305         }
1306     }
1307 
1308     @Override
1309     public CompositeByteBuf setInt(int index, int value) {
1310         checkIndex(index, 4);
1311         _setInt(index, value);
1312         return this;
1313     }
1314 
1315     @Override
1316     protected void _setInt(int index, int value) {
1317         Component c = findComponent0(index);
1318         if (index + 4 <= c.endOffset) {
1319             if (c.abuf != null) {
1320                 c.abuf._setInt(c.idx(index), value);
1321             } else {
1322                 c.buf.setInt(c.idx(index), value);
1323             }
1324         } else if (order() == ByteOrder.BIG_ENDIAN) {
1325             _setShort(index, (short) (value >>> 16));
1326             _setShort(index + 2, (short) value);
1327         } else {
1328             _setShort(index, (short) value);
1329             _setShort(index + 2, (short) (value >>> 16));
1330         }
1331     }
1332 
1333     @Override
1334     protected void _setIntLE(int index, int value) {
1335         Component c = findComponent0(index);
1336         if (index + 4 <= c.endOffset) {
1337             if (c.abuf != null) {
1338                 c.abuf._setIntLE(c.idx(index), value);
1339             } else {
1340                 c.buf.setIntLE(c.idx(index), value);
1341             }
1342         } else if (order() == ByteOrder.BIG_ENDIAN) {
1343             _setShortLE(index, (short) value);
1344             _setShortLE(index + 2, (short) (value >>> 16));
1345         } else {
1346             _setShortLE(index, (short) (value >>> 16));
1347             _setShortLE(index + 2, (short) value);
1348         }
1349     }
1350 
1351     @Override
1352     public CompositeByteBuf setLong(int index, long value) {
1353         checkIndex(index, 8);
1354         _setLong(index, value);
1355         return this;
1356     }
1357 
1358     @Override
1359     protected void _setLong(int index, long value) {
1360         Component c = findComponent0(index);
1361         if (index + 8 <= c.endOffset) {
1362             if (c.abuf != null) {
1363                 c.abuf._setLong(c.idx(index), value);
1364             } else {
1365                 c.buf.setLong(c.idx(index), value);
1366             }
1367         } else if (order() == ByteOrder.BIG_ENDIAN) {
1368             _setInt(index, (int) (value >>> 32));
1369             _setInt(index + 4, (int) value);
1370         } else {
1371             _setInt(index, (int) value);
1372             _setInt(index + 4, (int) (value >>> 32));
1373         }
1374     }
1375 
1376     @Override
1377     protected void _setLongLE(int index, long value) {
1378         Component c = findComponent0(index);
1379         if (index + 8 <= c.endOffset) {
1380             if (c.abuf != null) {
1381                 c.abuf._setLongLE(c.idx(index), value);
1382             } else {
1383                 c.buf.setLongLE(c.idx(index), value);
1384             }
1385         } else if (order() == ByteOrder.BIG_ENDIAN) {
1386             _setIntLE(index, (int) value);
1387             _setIntLE(index + 4, (int) (value >>> 32));
1388         } else {
1389             _setIntLE(index, (int) (value >>> 32));
1390             _setIntLE(index + 4, (int) value);
1391         }
1392     }
1393 
1394     @Override
1395     public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
1396         checkSrcIndex(index, length, srcIndex, src.length);
1397         if (length == 0) {
1398             return this;
1399         }
1400 
1401         int i = toComponentIndex0(index);
1402         while (length > 0) {
1403             Component c = components[i];
1404             int localLength = Math.min(length, c.endOffset - index);
1405             c.buf.setBytes(c.idx(index), src, srcIndex, localLength);
1406             index += localLength;
1407             srcIndex += localLength;
1408             length -= localLength;
1409             i ++;
1410         }
1411         return this;
1412     }
1413 
1414     @Override
1415     public CompositeByteBuf setBytes(int index, ByteBuffer src) {
1416         int limit = src.limit();
1417         int length = src.remaining();
1418 
1419         checkIndex(index, length);
1420         if (length == 0) {
1421             return this;
1422         }
1423 
1424         int i = toComponentIndex0(index);
1425         try {
1426             while (length > 0) {
1427                 Component c = components[i];
1428                 int localLength = Math.min(length, c.endOffset - index);
1429                 src.limit(src.position() + localLength);
1430                 c.buf.setBytes(c.idx(index), src);
1431                 index += localLength;
1432                 length -= localLength;
1433                 i ++;
1434             }
1435         } finally {
1436             src.limit(limit);
1437         }
1438         return this;
1439     }
1440 
1441     @Override
1442     public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
1443         checkSrcIndex(index, length, srcIndex, src.capacity());
1444         if (length == 0) {
1445             return this;
1446         }
1447 
1448         int i = toComponentIndex0(index);
1449         while (length > 0) {
1450             Component c = components[i];
1451             int localLength = Math.min(length, c.endOffset - index);
1452             c.buf.setBytes(c.idx(index), src, srcIndex, localLength);
1453             index += localLength;
1454             srcIndex += localLength;
1455             length -= localLength;
1456             i ++;
1457         }
1458         return this;
1459     }
1460 
1461     @Override
1462     public int setBytes(int index, InputStream in, int length) throws IOException {
1463         checkIndex(index, length);
1464         if (length == 0) {
1465             return in.read(EmptyArrays.EMPTY_BYTES);
1466         }
1467 
1468         int i = toComponentIndex0(index);
1469         int readBytes = 0;
1470         do {
1471             Component c = components[i];
1472             int localLength = Math.min(length, c.endOffset - index);
1473             if (localLength == 0) {
1474                 // Skip empty buffer
1475                 i++;
1476                 continue;
1477             }
1478             int localReadBytes = c.buf.setBytes(c.idx(index), in, localLength);
1479             if (localReadBytes < 0) {
1480                 if (readBytes == 0) {
1481                     return -1;
1482                 } else {
1483                     break;
1484                 }
1485             }
1486 
1487             index += localReadBytes;
1488             length -= localReadBytes;
1489             readBytes += localReadBytes;
1490             if (localReadBytes == localLength) {
1491                 i ++;
1492             }
1493         } while (length > 0);
1494 
1495         return readBytes;
1496     }
1497 
1498     @Override
1499     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
1500         checkIndex(index, length);
1501         if (length == 0) {
1502             return in.read(EMPTY_NIO_BUFFER);
1503         }
1504 
1505         int i = toComponentIndex0(index);
1506         int readBytes = 0;
1507         do {
1508             Component c = components[i];
1509             int localLength = Math.min(length, c.endOffset - index);
1510             if (localLength == 0) {
1511                 // Skip empty buffer
1512                 i++;
1513                 continue;
1514             }
1515             int localReadBytes = c.buf.setBytes(c.idx(index), in, localLength);
1516 
1517             if (localReadBytes == 0) {
1518                 break;
1519             }
1520 
1521             if (localReadBytes < 0) {
1522                 if (readBytes == 0) {
1523                     return -1;
1524                 } else {
1525                     break;
1526                 }
1527             }
1528 
1529             index += localReadBytes;
1530             length -= localReadBytes;
1531             readBytes += localReadBytes;
1532             if (localReadBytes == localLength) {
1533                 i ++;
1534             }
1535         } while (length > 0);
1536 
1537         return readBytes;
1538     }
1539 
1540     @Override
1541     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
1542         checkIndex(index, length);
1543         if (length == 0) {
1544             return in.read(EMPTY_NIO_BUFFER, position);
1545         }
1546 
1547         int i = toComponentIndex0(index);
1548         int readBytes = 0;
1549         do {
1550             Component c = components[i];
1551             int localLength = Math.min(length, c.endOffset - index);
1552             if (localLength == 0) {
1553                 // Skip empty buffer
1554                 i++;
1555                 continue;
1556             }
1557             int localReadBytes = c.buf.setBytes(c.idx(index), in, position + readBytes, localLength);
1558 
1559             if (localReadBytes == 0) {
1560                 break;
1561             }
1562 
1563             if (localReadBytes < 0) {
1564                 if (readBytes == 0) {
1565                     return -1;
1566                 } else {
1567                     break;
1568                 }
1569             }
1570 
1571             index += localReadBytes;
1572             length -= localReadBytes;
1573             readBytes += localReadBytes;
1574             if (localReadBytes == localLength) {
1575                 i ++;
1576             }
1577         } while (length > 0);
1578 
1579         return readBytes;
1580     }
1581 
1582     @Override
1583     public ByteBuf copy(int index, int length) {
1584         checkIndex(index, length);
1585         ByteBuf dst = allocBuffer(length);
1586         if (length != 0) {
1587             copyTo(index, length, toComponentIndex0(index), dst);
1588         }
1589         return dst;
1590     }
1591 
1592     private void copyTo(int index, int length, int componentId, ByteBuf dst) {
1593         int dstIndex = 0;
1594         int i = componentId;
1595 
1596         while (length > 0) {
1597             Component c = components[i];
1598             int localLength = Math.min(length, c.endOffset - index);
1599             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1600             index += localLength;
1601             dstIndex += localLength;
1602             length -= localLength;
1603             i ++;
1604         }
1605 
1606         dst.writerIndex(dst.capacity());
1607     }
1608 
1609     /**
1610      * Return a duplicate of the {@link ByteBuf} on the specified component index.
1611      * <p>
1612      * Note that this method returns a shallow duplicate of the underlying component buffer.
1613      * The returned buffer's {@code readerIndex} and {@code writerIndex} will be independent of the
1614      * composite buffer's indices and will not be adjusted to reflect the component's view within
1615      * the composite buffer.
1616      * <p>
1617      * If you need a buffer that represents the component's readable view as seen from the composite
1618      * buffer, use {@link #componentSlice(int cIndex)} instead.
1619      *
1620      * @param cIndex the index for which the {@link ByteBuf} should be returned
1621      * @return a duplicate of the underlying {@link ByteBuf} on the specified index
1622      */
1623     public ByteBuf component(int cIndex) {
1624         checkComponentIndex(cIndex);
1625         return components[cIndex].duplicate();
1626     }
1627 
1628     /**
1629      * Return a slice of the {@link ByteBuf} on the specified component index.
1630      * <p>
1631      * This method provides a view of the component that reflects its state within the composite buffer.
1632      * The returned buffer's readable bytes will correspond to the bytes that this component
1633      * contributes to the composite buffer's capacity. The slice will have its own independent
1634      * {@code readerIndex} and {@code writerIndex}, starting at {@code 0}.
1635      *
1636      * @param cIndex the index for which the sliced {@link ByteBuf} should be returned
1637      * @return a sliced {@link ByteBuf} representing the component's view
1638      */
1639     public ByteBuf componentSlice(int cIndex) {
1640         checkComponentIndex(cIndex);
1641         return components[cIndex].slice();
1642     }
1643 
1644     /**
1645      * Return the {@link ByteBuf} on the specified index
1646      *
1647      * @param offset the offset for which the {@link ByteBuf} should be returned
1648      * @return the {@link ByteBuf} on the specified index
1649      */
1650     public ByteBuf componentAtOffset(int offset) {
1651         return findComponent(offset).duplicate();
1652     }
1653 
1654     /**
1655      * Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
1656      * buffer will lead to an undefined behavior of this buffer.
1657      *
1658      * @param cIndex the index for which the {@link ByteBuf} should be returned
1659      */
1660     public ByteBuf internalComponent(int cIndex) {
1661         checkComponentIndex(cIndex);
1662         return components[cIndex].slice();
1663     }
1664 
1665     /**
1666      * Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
1667      * buffer will lead to an undefined behavior of this buffer.
1668      *
1669      * @param offset the offset for which the {@link ByteBuf} should be returned
1670      */
1671     public ByteBuf internalComponentAtOffset(int offset) {
1672         return findComponent(offset).slice();
1673     }
1674 
1675     // weak cache - check it first when looking for component
1676     private Component lastAccessed;
1677     private int lastAccessedIndex;
1678 
1679     private Component findComponent(int offset) {
1680         Component la = lastAccessed;
1681         if (la != null && offset >= la.offset && offset < la.endOffset) {
1682            ensureAccessible();
1683            return la;
1684         }
1685         checkIndex(offset);
1686         return findIt(offset);
1687     }
1688 
1689     private Component findComponent0(int offset) {
1690         Component la = lastAccessed;
1691         if (la != null && offset >= la.offset && offset < la.endOffset) {
1692            return la;
1693         }
1694         return findIt(offset);
1695     }
1696 
1697     /**
1698      * Sequential-read fast path: try the next component(s) before falling back to binary search.
1699      */
1700     private Component findComponentForRead(int offset) {
1701         int cc = componentCount;
1702         for (int next = lastAccessedIndex + 1; next < cc; next++) {
1703             Component c = components[next];
1704             if (offset < c.endOffset) {
1705                 lastAccessed = c;
1706                 lastAccessedIndex = next;
1707                 return c;
1708             }
1709         }
1710         return findIt(offset);
1711     }
1712 
1713     private Component findIt(int offset) {
1714         for (int low = 0, high = componentCount; low <= high;) {
1715             int mid = low + high >>> 1;
1716             Component c = components[mid];
1717             if (c == null) {
1718                 throw new IllegalStateException("No component found for offset. " +
1719                         "Composite buffer layout might be outdated, e.g. from a discardReadBytes call.");
1720             }
1721             if (offset >= c.endOffset) {
1722                 low = mid + 1;
1723             } else if (offset < c.offset) {
1724                 high = mid - 1;
1725             } else {
1726                 lastAccessed = c;
1727                 lastAccessedIndex = mid;
1728                 return c;
1729             }
1730         }
1731 
1732         throw new Error("should not reach here");
1733     }
1734 
1735     @Override
1736     public int nioBufferCount() {
1737         int size = componentCount;
1738         switch (size) {
1739         case 0:
1740             return 1;
1741         case 1:
1742             return components[0].buf.nioBufferCount();
1743         default:
1744             int count = 0;
1745             for (int i = 0; i < size; i++) {
1746                 count += components[i].buf.nioBufferCount();
1747             }
1748             return count;
1749         }
1750     }
1751 
1752     @Override
1753     public ByteBuffer internalNioBuffer(int index, int length) {
1754         switch (componentCount) {
1755         case 0:
1756             return EMPTY_NIO_BUFFER;
1757         case 1:
1758             return components[0].internalNioBuffer(index, length);
1759         default:
1760             throw new UnsupportedOperationException();
1761         }
1762     }
1763 
1764     @Override
1765     public ByteBuffer nioBuffer(int index, int length) {
1766         checkIndex(index, length);
1767 
1768         switch (componentCount) {
1769         case 0:
1770             return EMPTY_NIO_BUFFER;
1771         case 1:
1772             Component c = components[0];
1773             ByteBuf buf = c.buf;
1774             if (buf.nioBufferCount() == 1) {
1775                 return buf.nioBuffer(c.idx(index), length);
1776             }
1777             break;
1778         default:
1779             break;
1780         }
1781 
1782         ByteBuffer[] buffers = nioBuffers(index, length);
1783 
1784         if (buffers.length == 1) {
1785             return buffers[0];
1786         }
1787 
1788         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
1789         for (ByteBuffer buf: buffers) {
1790             merged.put(buf);
1791         }
1792 
1793         merged.flip();
1794         return merged;
1795     }
1796 
1797     @Override
1798     public ByteBuffer[] nioBuffers(int index, int length) {
1799         checkIndex(index, length);
1800         if (length == 0) {
1801             return new ByteBuffer[] { EMPTY_NIO_BUFFER };
1802         }
1803 
1804         RecyclableArrayList buffers = RecyclableArrayList.newInstance(componentCount);
1805         try {
1806             int i = toComponentIndex0(index);
1807             while (length > 0) {
1808                 Component c = components[i];
1809                 ByteBuf s = c.buf;
1810                 int localLength = Math.min(length, c.endOffset - index);
1811                 switch (s.nioBufferCount()) {
1812                 case 0:
1813                     throw new UnsupportedOperationException();
1814                 case 1:
1815                     buffers.add(s.nioBuffer(c.idx(index), localLength));
1816                     break;
1817                 default:
1818                     Collections.addAll(buffers, s.nioBuffers(c.idx(index), localLength));
1819                 }
1820 
1821                 index += localLength;
1822                 length -= localLength;
1823                 i ++;
1824             }
1825 
1826             return buffers.toArray(EmptyArrays.EMPTY_BYTE_BUFFERS);
1827         } finally {
1828             buffers.recycle();
1829         }
1830     }
1831 
1832     /**
1833      * Consolidate the composed {@link ByteBuf}s
1834      */
1835     public CompositeByteBuf consolidate() {
1836         ensureAccessible();
1837         consolidate0(0, componentCount);
1838         return this;
1839     }
1840 
1841     /**
1842      * Consolidate the composed {@link ByteBuf}s
1843      *
1844      * @param cIndex the index on which to start to compose
1845      * @param numComponents the number of components to compose
1846      */
1847     public CompositeByteBuf consolidate(int cIndex, int numComponents) {
1848         checkComponentIndex(cIndex, numComponents);
1849         consolidate0(cIndex, numComponents);
1850         return this;
1851     }
1852 
1853     private void consolidate0(int cIndex, int numComponents) {
1854         if (numComponents <= 1) {
1855             return;
1856         }
1857 
1858         final int endCIndex = cIndex + numComponents;
1859         final int startOffset = cIndex != 0 ? components[cIndex].offset : 0;
1860         final int capacity = components[endCIndex - 1].endOffset - startOffset;
1861         final ByteBuf consolidated = allocBuffer(capacity);
1862 
1863         for (int i = cIndex; i < endCIndex; i ++) {
1864             components[i].transferTo(consolidated);
1865         }
1866         lastAccessed = null;
1867         lastAccessedIndex = 0;
1868         removeCompRange(cIndex + 1, endCIndex);
1869         components[cIndex] = newComponent(consolidated, 0);
1870         if (cIndex != 0 || numComponents != componentCount) {
1871             updateComponentOffsets(cIndex);
1872         }
1873     }
1874 
1875     /**
1876      * Discard all {@link ByteBuf}s which are read.
1877      */
1878     public CompositeByteBuf discardReadComponents() {
1879         ensureAccessible();
1880         final int readerIndex = readerIndex();
1881         if (readerIndex == 0) {
1882             return this;
1883         }
1884 
1885         // Discard everything if (readerIndex = writerIndex = capacity).
1886         int writerIndex = writerIndex();
1887         if (readerIndex == writerIndex && writerIndex == capacity()) {
1888             for (int i = 0, size = componentCount; i < size; i++) {
1889                 components[i].free();
1890             }
1891             lastAccessed = null;
1892             lastAccessedIndex = 0;
1893             clearComps();
1894             setIndex(0, 0);
1895             adjustMarkers(readerIndex);
1896             return this;
1897         }
1898 
1899         // Remove read components.
1900         int firstComponentId = 0;
1901         Component c = null;
1902         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1903             c = components[firstComponentId];
1904             if (c.endOffset > readerIndex) {
1905                 break;
1906             }
1907             c.free();
1908         }
1909         if (firstComponentId == 0) {
1910             return this; // Nothing to discard
1911         }
1912         Component la = lastAccessed;
1913         if (la != null && la.endOffset <= readerIndex) {
1914             lastAccessed = null;
1915             lastAccessedIndex = 0;
1916         }
1917         removeCompRange(0, firstComponentId);
1918 
1919         // Update indexes and markers.
1920         int offset = c.offset;
1921         updateComponentOffsets(0);
1922         setIndex(readerIndex - offset, writerIndex - offset);
1923         adjustMarkers(offset);
1924         return this;
1925     }
1926 
1927     @Override
1928     public CompositeByteBuf discardReadBytes() {
1929         ensureAccessible();
1930         final int readerIndex = readerIndex();
1931         if (readerIndex == 0) {
1932             return this;
1933         }
1934 
1935         // Discard everything if (readerIndex = writerIndex = capacity).
1936         int writerIndex = writerIndex();
1937         if (readerIndex == writerIndex && writerIndex == capacity()) {
1938             for (int i = 0, size = componentCount; i < size; i++) {
1939                 components[i].free();
1940             }
1941             lastAccessed = null;
1942             lastAccessedIndex = 0;
1943             clearComps();
1944             setIndex(0, 0);
1945             adjustMarkers(readerIndex);
1946             return this;
1947         }
1948 
1949         int firstComponentId = 0;
1950         Component c = null;
1951         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1952             c = components[firstComponentId];
1953             if (c.endOffset > readerIndex) {
1954                 break;
1955             }
1956             c.free();
1957         }
1958 
1959         // Replace the first readable component with a new slice.
1960         int trimmedBytes = readerIndex - c.offset;
1961         c.offset = 0;
1962         c.endOffset -= readerIndex;
1963         c.srcAdjustment += readerIndex;
1964         c.adjustment += readerIndex;
1965         ByteBuf slice = c.slice;
1966         if (slice != null) {
1967             // We must replace the cached slice with a derived one to ensure that
1968             // it can later be released properly in the case of PooledSlicedByteBuf.
1969             c.slice = slice.slice(trimmedBytes, c.length());
1970         }
1971         Component la = lastAccessed;
1972         if (la != null && la.endOffset <= readerIndex) {
1973             lastAccessed = null;
1974             lastAccessedIndex = 0;
1975         }
1976 
1977         removeCompRange(0, firstComponentId);
1978 
1979         // Update indexes and markers.
1980         updateComponentOffsets(0);
1981         setIndex(0, writerIndex - readerIndex);
1982         adjustMarkers(readerIndex);
1983         return this;
1984     }
1985 
1986     private ByteBuf allocBuffer(int capacity) {
1987         return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
1988     }
1989 
1990     @Override
1991     public String toString() {
1992         String result = super.toString();
1993         result = result.substring(0, result.length() - 1);
1994         return result + ", components=" + componentCount + ')';
1995     }
1996 
1997     private static final class Component {
1998         final ByteBuf srcBuf; // the originally added buffer
1999         final ByteBuf buf; // srcBuf unwrapped zero or more times
2000         final AbstractByteBuf abuf; // buf cast to AbstractByteBuf, or null if not an instance
2001 
2002         int srcAdjustment; // index of the start of this CompositeByteBuf relative to srcBuf
2003         int adjustment; // index of the start of this CompositeByteBuf relative to buf
2004 
2005         int offset; // offset of this component within this CompositeByteBuf
2006         int endOffset; // end offset of this component within this CompositeByteBuf
2007 
2008         private ByteBuf slice; // cached slice, may be null
2009 
2010         Component(ByteBuf srcBuf, int srcOffset, ByteBuf buf, int bufOffset,
2011                 int offset, int len, ByteBuf slice) {
2012             this.srcBuf = srcBuf;
2013             this.srcAdjustment = srcOffset - offset;
2014             this.buf = buf;
2015             this.abuf = buf instanceof AbstractByteBuf ? (AbstractByteBuf) buf : null;
2016             this.adjustment = bufOffset - offset;
2017             this.offset = offset;
2018             this.endOffset = offset + len;
2019             this.slice = slice;
2020         }
2021 
2022         int srcIdx(int index) {
2023             return index + srcAdjustment;
2024         }
2025 
2026         int idx(int index) {
2027             return index + adjustment;
2028         }
2029 
2030         int length() {
2031             return endOffset - offset;
2032         }
2033 
2034         void reposition(int newOffset) {
2035             int move = newOffset - offset;
2036             endOffset += move;
2037             srcAdjustment -= move;
2038             adjustment -= move;
2039             offset = newOffset;
2040         }
2041 
2042         // copy then release
2043         void transferTo(ByteBuf dst) {
2044             dst.writeBytes(buf, idx(offset), length());
2045             free();
2046         }
2047 
2048         ByteBuf slice() {
2049             ByteBuf s = slice;
2050             if (s == null) {
2051                 slice = s = srcBuf.slice(srcIdx(offset), length());
2052             }
2053             return s;
2054         }
2055 
2056         ByteBuf duplicate() {
2057             return srcBuf.duplicate();
2058         }
2059 
2060         ByteBuffer internalNioBuffer(int index, int length) {
2061             // Some buffers override this so we must use srcBuf
2062             return srcBuf.internalNioBuffer(srcIdx(index), length);
2063         }
2064 
2065         void free() {
2066             slice = null;
2067             // Release the original buffer since it may have a different
2068             // refcount to the unwrapped buf (e.g. if PooledSlicedByteBuf)
2069             srcBuf.release();
2070         }
2071     }
2072 
2073     @Override
2074     public CompositeByteBuf readerIndex(int readerIndex) {
2075         super.readerIndex(readerIndex);
2076         return this;
2077     }
2078 
2079     @Override
2080     public CompositeByteBuf writerIndex(int writerIndex) {
2081         super.writerIndex(writerIndex);
2082         return this;
2083     }
2084 
2085     @Override
2086     public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
2087         super.setIndex(readerIndex, writerIndex);
2088         return this;
2089     }
2090 
2091     @Override
2092     public CompositeByteBuf clear() {
2093         super.clear();
2094         return this;
2095     }
2096 
2097     @Override
2098     public CompositeByteBuf markReaderIndex() {
2099         super.markReaderIndex();
2100         return this;
2101     }
2102 
2103     @Override
2104     public CompositeByteBuf resetReaderIndex() {
2105         super.resetReaderIndex();
2106         return this;
2107     }
2108 
2109     @Override
2110     public CompositeByteBuf markWriterIndex() {
2111         super.markWriterIndex();
2112         return this;
2113     }
2114 
2115     @Override
2116     public CompositeByteBuf resetWriterIndex() {
2117         super.resetWriterIndex();
2118         return this;
2119     }
2120 
2121     @Override
2122     public CompositeByteBuf ensureWritable(int minWritableBytes) {
2123         super.ensureWritable(minWritableBytes);
2124         return this;
2125     }
2126 
2127     @Override
2128     public CompositeByteBuf getBytes(int index, ByteBuf dst) {
2129         return getBytes(index, dst, dst.writableBytes());
2130     }
2131 
2132     @Override
2133     public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
2134         getBytes(index, dst, dst.writerIndex(), length);
2135         dst.writerIndex(dst.writerIndex() + length);
2136         return this;
2137     }
2138 
2139     @Override
2140     public CompositeByteBuf getBytes(int index, byte[] dst) {
2141         return getBytes(index, dst, 0, dst.length);
2142     }
2143 
2144     @Override
2145     public CompositeByteBuf setBoolean(int index, boolean value) {
2146         return setByte(index, value? 1 : 0);
2147     }
2148 
2149     @Override
2150     public CompositeByteBuf setChar(int index, int value) {
2151         return setShort(index, value);
2152     }
2153 
2154     @Override
2155     public CompositeByteBuf setFloat(int index, float value) {
2156         return setInt(index, Float.floatToRawIntBits(value));
2157     }
2158 
2159     @Override
2160     public CompositeByteBuf setDouble(int index, double value) {
2161         return setLong(index, Double.doubleToRawLongBits(value));
2162     }
2163 
2164     @Override
2165     public CompositeByteBuf setBytes(int index, ByteBuf src) {
2166         super.setBytes(index, src, src.readableBytes());
2167         return this;
2168     }
2169 
2170     @Override
2171     public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
2172         super.setBytes(index, src, length);
2173         return this;
2174     }
2175 
2176     @Override
2177     public CompositeByteBuf setBytes(int index, byte[] src) {
2178         return setBytes(index, src, 0, src.length);
2179     }
2180 
2181     @Override
2182     public CompositeByteBuf setZero(int index, int length) {
2183         super.setZero(index, length);
2184         return this;
2185     }
2186 
2187     @Override
2188     public CompositeByteBuf readBytes(ByteBuf dst) {
2189         super.readBytes(dst, dst.writableBytes());
2190         return this;
2191     }
2192 
2193     @Override
2194     public CompositeByteBuf readBytes(ByteBuf dst, int length) {
2195         super.readBytes(dst, length);
2196         return this;
2197     }
2198 
2199     @Override
2200     public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
2201         super.readBytes(dst, dstIndex, length);
2202         return this;
2203     }
2204 
2205     @Override
2206     public CompositeByteBuf readBytes(byte[] dst) {
2207         super.readBytes(dst, 0, dst.length);
2208         return this;
2209     }
2210 
2211     @Override
2212     public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
2213         super.readBytes(dst, dstIndex, length);
2214         return this;
2215     }
2216 
2217     @Override
2218     public CompositeByteBuf readBytes(ByteBuffer dst) {
2219         super.readBytes(dst);
2220         return this;
2221     }
2222 
2223     @Override
2224     public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
2225         super.readBytes(out, length);
2226         return this;
2227     }
2228 
2229     @Override
2230     public CompositeByteBuf skipBytes(int length) {
2231         super.skipBytes(length);
2232         return this;
2233     }
2234 
2235     @Override
2236     public CompositeByteBuf writeBoolean(boolean value) {
2237         writeByte(value ? 1 : 0);
2238         return this;
2239     }
2240 
2241     @Override
2242     public CompositeByteBuf writeByte(int value) {
2243         ensureWritable0(1);
2244         _setByte(writerIndex++, value);
2245         return this;
2246     }
2247 
2248     @Override
2249     public CompositeByteBuf writeShort(int value) {
2250         super.writeShort(value);
2251         return this;
2252     }
2253 
2254     @Override
2255     public CompositeByteBuf writeMedium(int value) {
2256         super.writeMedium(value);
2257         return this;
2258     }
2259 
2260     @Override
2261     public CompositeByteBuf writeInt(int value) {
2262         super.writeInt(value);
2263         return this;
2264     }
2265 
2266     @Override
2267     public CompositeByteBuf writeLong(long value) {
2268         super.writeLong(value);
2269         return this;
2270     }
2271 
2272     @Override
2273     public CompositeByteBuf writeChar(int value) {
2274         super.writeShort(value);
2275         return this;
2276     }
2277 
2278     @Override
2279     public CompositeByteBuf writeFloat(float value) {
2280         super.writeInt(Float.floatToRawIntBits(value));
2281         return this;
2282     }
2283 
2284     @Override
2285     public CompositeByteBuf writeDouble(double value) {
2286         super.writeLong(Double.doubleToRawLongBits(value));
2287         return this;
2288     }
2289 
2290     @Override
2291     public CompositeByteBuf writeBytes(ByteBuf src) {
2292         super.writeBytes(src, src.readableBytes());
2293         return this;
2294     }
2295 
2296     @Override
2297     public CompositeByteBuf writeBytes(ByteBuf src, int length) {
2298         super.writeBytes(src, length);
2299         return this;
2300     }
2301 
2302     @Override
2303     public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
2304         super.writeBytes(src, srcIndex, length);
2305         return this;
2306     }
2307 
2308     @Override
2309     public CompositeByteBuf writeBytes(byte[] src) {
2310         super.writeBytes(src, 0, src.length);
2311         return this;
2312     }
2313 
2314     @Override
2315     public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
2316         super.writeBytes(src, srcIndex, length);
2317         return this;
2318     }
2319 
2320     @Override
2321     public CompositeByteBuf writeBytes(ByteBuffer src) {
2322         super.writeBytes(src);
2323         return this;
2324     }
2325 
2326     @Override
2327     public CompositeByteBuf writeZero(int length) {
2328         super.writeZero(length);
2329         return this;
2330     }
2331 
2332     @Override
2333     public CompositeByteBuf retain(int increment) {
2334         super.retain(increment);
2335         return this;
2336     }
2337 
2338     @Override
2339     public CompositeByteBuf retain() {
2340         super.retain();
2341         return this;
2342     }
2343 
2344     @Override
2345     public CompositeByteBuf touch() {
2346         return this;
2347     }
2348 
2349     @Override
2350     public CompositeByteBuf touch(Object hint) {
2351         return this;
2352     }
2353 
2354     @Override
2355     public ByteBuffer[] nioBuffers() {
2356         return nioBuffers(readerIndex(), readableBytes());
2357     }
2358 
2359     @Override
2360     public CompositeByteBuf discardSomeReadBytes() {
2361         return discardReadComponents();
2362     }
2363 
2364     @Override
2365     protected void deallocate() {
2366         if (freed) {
2367             return;
2368         }
2369 
2370         freed = true;
2371         // We're not using foreach to avoid creating an iterator.
2372         // see https://github.com/netty/netty/issues/2642
2373         for (int i = 0, size = componentCount; i < size; i++) {
2374             components[i].free();
2375         }
2376     }
2377 
2378     @Override
2379     boolean isAccessible() {
2380         return !freed;
2381     }
2382 
2383     @Override
2384     public ByteBuf unwrap() {
2385         return null;
2386     }
2387 
2388     private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
2389         private final int size = numComponents();
2390         private int index;
2391 
2392         @Override
2393         public boolean hasNext() {
2394             return size > index;
2395         }
2396 
2397         @Override
2398         public ByteBuf next() {
2399             if (size != numComponents()) {
2400                 throw new ConcurrentModificationException();
2401             }
2402             if (!hasNext()) {
2403                 throw new NoSuchElementException();
2404             }
2405             try {
2406                 return components[index++].slice();
2407             } catch (IndexOutOfBoundsException e) {
2408                 throw new ConcurrentModificationException();
2409             }
2410         }
2411 
2412         @Override
2413         public void remove() {
2414             throw new UnsupportedOperationException("Read-Only");
2415         }
2416     }
2417 
2418     // Component array manipulation - range checking omitted
2419 
2420     private void clearComps() {
2421         removeCompRange(0, componentCount);
2422     }
2423 
2424     private void removeComp(int i) {
2425         removeCompRange(i, i + 1);
2426     }
2427 
2428     private void removeCompRange(int from, int to) {
2429         if (from >= to) {
2430             return;
2431         }
2432         final int size = componentCount;
2433         assert from >= 0 && to <= size;
2434         if (to < size) {
2435             System.arraycopy(components, to, components, from, size - to);
2436         }
2437         int newSize = size - to + from;
2438         for (int i = newSize; i < size; i++) {
2439             components[i] = null;
2440         }
2441         componentCount = newSize;
2442     }
2443 
2444     private void addComp(int i, Component c) {
2445         shiftComps(i, 1);
2446         components[i] = c;
2447     }
2448 
2449     private void shiftComps(int i, int count) {
2450         final int size = componentCount, newSize = size + count;
2451         assert i >= 0 && i <= size && count > 0;
2452         if (newSize > components.length) {
2453             // grow the array
2454             int newArrSize = Math.max(size + (size >> 1), newSize);
2455             Component[] newArr;
2456             if (i == size) {
2457                 newArr = Arrays.copyOf(components, newArrSize, Component[].class);
2458             } else {
2459                 newArr = new Component[newArrSize];
2460                 if (i > 0) {
2461                     System.arraycopy(components, 0, newArr, 0, i);
2462                 }
2463                 if (i < size) {
2464                     System.arraycopy(components, i, newArr, i + count, size - i);
2465                 }
2466             }
2467             components = newArr;
2468         } else if (i < size) {
2469             System.arraycopy(components, i, components, i + count, size - i);
2470         }
2471         componentCount = newSize;
2472     }
2473 
2474     /**
2475      * Decreases the reference count by the specified {@code decrement} and deallocates this object if the reference
2476      * count reaches at {@code 0}. At this point it will also decrement the reference count of each internal
2477      * component by {@code 1}.
2478      *
2479      * @param decrement the number by which the reference count should be decreased
2480      * @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated
2481      */
2482     @Override
2483     public boolean release(final int decrement) {
2484         return super.release(decrement);
2485     }
2486 }