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    *   http://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.internal.EmptyArrays;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.nio.ByteBuffer;
24  import java.nio.ByteOrder;
25  import java.nio.channels.GatheringByteChannel;
26  import java.nio.channels.ScatteringByteChannel;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.ConcurrentModificationException;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.ListIterator;
34  import java.util.NoSuchElementException;
35  
36  import static io.netty.util.internal.ObjectUtil.checkNotNull;
37  
38  /**
39   * A virtual buffer which shows multiple buffers as a single merged buffer.  It is recommended to use
40   * {@link ByteBufAllocator#compositeBuffer()} or {@link Unpooled#wrappedBuffer(ByteBuf...)} instead of calling the
41   * constructor explicitly.
42   */
43  public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf> {
44  
45      private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
46      private static final Iterator<ByteBuf> EMPTY_ITERATOR = Collections.<ByteBuf>emptyList().iterator();
47  
48      private final ByteBufAllocator alloc;
49      private final boolean direct;
50      private final ComponentList components;
51      private final int maxNumComponents;
52  
53      private boolean freed;
54  
55      public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) {
56          super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
57          if (alloc == null) {
58              throw new NullPointerException("alloc");
59          }
60          this.alloc = alloc;
61          this.direct = direct;
62          this.maxNumComponents = maxNumComponents;
63          components = newList(maxNumComponents);
64      }
65  
66      public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf... buffers) {
67          this(alloc, direct, maxNumComponents, buffers, 0, buffers.length);
68      }
69  
70      CompositeByteBuf(
71              ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf[] buffers, int offset, int len) {
72          super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
73          if (alloc == null) {
74              throw new NullPointerException("alloc");
75          }
76          if (maxNumComponents < 2) {
77              throw new IllegalArgumentException(
78                      "maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
79          }
80  
81          this.alloc = alloc;
82          this.direct = direct;
83          this.maxNumComponents = maxNumComponents;
84          components = newList(maxNumComponents);
85  
86          addComponents0(false, 0, buffers, offset, len);
87          consolidateIfNeeded();
88          setIndex(0, capacity());
89      }
90  
91      public CompositeByteBuf(
92              ByteBufAllocator alloc, boolean direct, int maxNumComponents, Iterable<ByteBuf> buffers) {
93          super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
94          if (alloc == null) {
95              throw new NullPointerException("alloc");
96          }
97          if (maxNumComponents < 2) {
98              throw new IllegalArgumentException(
99                      "maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
100         }
101 
102         this.alloc = alloc;
103         this.direct = direct;
104         this.maxNumComponents = maxNumComponents;
105         components = newList(maxNumComponents);
106 
107         addComponents0(false, 0, buffers);
108         consolidateIfNeeded();
109         setIndex(0, capacity());
110     }
111 
112     private static ComponentList newList(int maxNumComponents) {
113         return new ComponentList(Math.min(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS, maxNumComponents));
114     }
115 
116     // Special constructor used by WrappedCompositeByteBuf
117     CompositeByteBuf(ByteBufAllocator alloc) {
118         super(Integer.MAX_VALUE);
119         this.alloc = alloc;
120         direct = false;
121         maxNumComponents = 0;
122         components = null;
123     }
124 
125     /**
126      * Add the given {@link ByteBuf}.
127      * <p>
128      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
129      * If you need to have it increased use {@link #addComponent(boolean, ByteBuf)}.
130      * <p>
131      * {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}.
132      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this
133      * {@link CompositeByteBuf}.
134      */
135     public CompositeByteBuf addComponent(ByteBuf buffer) {
136         return addComponent(false, buffer);
137     }
138 
139     /**
140      * Add the given {@link ByteBuf}s.
141      * <p>
142      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
143      * If you need to have it increased use {@link #addComponents(boolean, ByteBuf[])}.
144      * <p>
145      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
146      * {@link CompositeByteBuf}.
147      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
148      * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
149      */
150     public CompositeByteBuf addComponents(ByteBuf... buffers) {
151         return addComponents(false, buffers);
152     }
153 
154     /**
155      * Add the given {@link ByteBuf}s.
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 #addComponents(boolean, Iterable)}.
159      * <p>
160      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
161      * {@link CompositeByteBuf}.
162      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
163      * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
164      */
165     public CompositeByteBuf addComponents(Iterable<ByteBuf> buffers) {
166         return addComponents(false, buffers);
167     }
168 
169     /**
170      * Add the given {@link ByteBuf} on the specific index.
171      * <p>
172      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
173      * If you need to have it increased use {@link #addComponent(boolean, int, ByteBuf)}.
174      * <p>
175      * {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}.
176      * @param cIndex the index on which the {@link ByteBuf} will be added.
177      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this
178      * {@link CompositeByteBuf}.
179      */
180     public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
181         return addComponent(false, cIndex, buffer);
182     }
183 
184     /**
185      * Add the given {@link ByteBuf} and increase the {@code writerIndex} if {@code increaseWriterIndex} is
186      * {@code true}.
187      *
188      * {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}.
189      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this
190      * {@link CompositeByteBuf}.
191      */
192     public CompositeByteBuf addComponent(boolean increaseWriterIndex, ByteBuf buffer) {
193         checkNotNull(buffer, "buffer");
194         addComponent0(increaseWriterIndex, components.size(), buffer);
195         consolidateIfNeeded();
196         return this;
197     }
198 
199     /**
200      * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is
201      * {@code true}.
202      *
203      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
204      * {@link CompositeByteBuf}.
205      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
206      * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
207      */
208     public CompositeByteBuf addComponents(boolean increaseWriterIndex, ByteBuf... buffers) {
209         addComponents0(increaseWriterIndex, components.size(), buffers, 0, buffers.length);
210         consolidateIfNeeded();
211         return this;
212     }
213 
214     /**
215      * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is
216      * {@code true}.
217      *
218      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
219      * {@link CompositeByteBuf}.
220      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
221      * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
222      */
223     public CompositeByteBuf addComponents(boolean increaseWriterIndex, Iterable<ByteBuf> buffers) {
224         addComponents0(increaseWriterIndex, components.size(), buffers);
225         consolidateIfNeeded();
226         return this;
227     }
228 
229     /**
230      * Add the given {@link ByteBuf} on the specific index and increase the {@code writerIndex}
231      * if {@code increaseWriterIndex} is {@code true}.
232      *
233      * {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}.
234      * @param cIndex the index on which the {@link ByteBuf} will be added.
235      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this
236      * {@link CompositeByteBuf}.
237      */
238     public CompositeByteBuf addComponent(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
239         checkNotNull(buffer, "buffer");
240         addComponent0(increaseWriterIndex, cIndex, buffer);
241         consolidateIfNeeded();
242         return this;
243     }
244 
245     /**
246      * Precondition is that {@code buffer != null}.
247      */
248     private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
249         assert buffer != null;
250         boolean wasAdded = false;
251         try {
252             checkComponentIndex(cIndex);
253 
254             int readableBytes = buffer.readableBytes();
255 
256             // No need to consolidate - just add a component to the list.
257             @SuppressWarnings("deprecation")
258             Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
259             if (cIndex == components.size()) {
260                 wasAdded = components.add(c);
261                 if (cIndex == 0) {
262                     c.endOffset = readableBytes;
263                 } else {
264                     Component prev = components.get(cIndex - 1);
265                     c.offset = prev.endOffset;
266                     c.endOffset = c.offset + readableBytes;
267                 }
268             } else {
269                 components.add(cIndex, c);
270                 wasAdded = true;
271                 if (readableBytes != 0) {
272                     updateComponentOffsets(cIndex);
273                 }
274             }
275             if (increaseWriterIndex) {
276                 writerIndex(writerIndex() + buffer.readableBytes());
277             }
278             return cIndex;
279         } finally {
280             if (!wasAdded) {
281                 buffer.release();
282             }
283         }
284     }
285 
286     /**
287      * Add the given {@link ByteBuf}s on the specific index
288      * <p>
289      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
290      * If you need to have it increased you need to handle it by your own.
291      * <p>
292      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
293      * {@link CompositeByteBuf}.
294      * @param cIndex the index on which the {@link ByteBuf} will be added. {@link ByteBuf#release()} ownership of all
295      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transfered to this
296      * {@link CompositeByteBuf}.
297      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
298      * ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
299      */
300     public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) {
301         addComponents0(false, cIndex, buffers, 0, buffers.length);
302         consolidateIfNeeded();
303         return this;
304     }
305 
306     private int addComponents0(boolean increaseWriterIndex, int cIndex, ByteBuf[] buffers, int offset, int len) {
307         checkNotNull(buffers, "buffers");
308         int i = offset;
309         try {
310             checkComponentIndex(cIndex);
311 
312             // No need for consolidation
313             while (i < len) {
314                 // Increment i now to prepare for the next iteration and prevent a duplicate release (addComponent0
315                 // will release if an exception occurs, and we also release in the finally block here).
316                 ByteBuf b = buffers[i++];
317                 if (b == null) {
318                     break;
319                 }
320                 cIndex = addComponent0(increaseWriterIndex, cIndex, b) + 1;
321                 int size = components.size();
322                 if (cIndex > size) {
323                     cIndex = size;
324                 }
325             }
326             return cIndex;
327         } finally {
328             for (; i < len; ++i) {
329                 ByteBuf b = buffers[i];
330                 if (b != null) {
331                     try {
332                         b.release();
333                     } catch (Throwable ignored) {
334                         // ignore
335                     }
336                 }
337             }
338         }
339     }
340 
341     /**
342      * Add the given {@link ByteBuf}s on the specific index
343      *
344      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
345      * If you need to have it increased you need to handle it by your own.
346      * <p>
347      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
348      * {@link CompositeByteBuf}.
349      * @param cIndex the index on which the {@link ByteBuf} will be added.
350      * @param buffers the {@link ByteBuf}s to add.  {@link ByteBuf#release()} ownership of all
351      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transfered to this
352      * {@link CompositeByteBuf}.
353      */
354     public CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers) {
355         addComponents0(false, cIndex, buffers);
356         consolidateIfNeeded();
357         return this;
358     }
359 
360     private int addComponents0(boolean increaseIndex, int cIndex, Iterable<ByteBuf> buffers) {
361         if (buffers instanceof ByteBuf) {
362             // If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf).
363             return addComponent0(increaseIndex, cIndex, (ByteBuf) buffers);
364         }
365         checkNotNull(buffers, "buffers");
366 
367         if (!(buffers instanceof Collection)) {
368             List<ByteBuf> list = new ArrayList<ByteBuf>();
369             try {
370                 for (ByteBuf b: buffers) {
371                     list.add(b);
372                 }
373                 buffers = list;
374             } finally {
375                 if (buffers != list) {
376                     for (ByteBuf b: buffers) {
377                         if (b != null) {
378                             try {
379                                 b.release();
380                             } catch (Throwable ignored) {
381                                 // ignore
382                             }
383                         }
384                     }
385                 }
386             }
387         }
388 
389         Collection<ByteBuf> col = (Collection<ByteBuf>) buffers;
390         return addComponents0(increaseIndex, cIndex, col.toArray(new ByteBuf[col.size()]), 0 , col.size());
391     }
392 
393     /**
394      * This should only be called as last operation from a method as this may adjust the underlying
395      * array of components and so affect the index etc.
396      */
397     private void consolidateIfNeeded() {
398         // Consolidate if the number of components will exceed the allowed maximum by the current
399         // operation.
400         final int numComponents = components.size();
401         if (numComponents > maxNumComponents) {
402             final int capacity = components.get(numComponents - 1).endOffset;
403 
404             ByteBuf consolidated = allocBuffer(capacity);
405 
406             // We're not using foreach to avoid creating an iterator.
407             for (int i = 0; i < numComponents; i ++) {
408                 Component c = components.get(i);
409                 ByteBuf b = c.buf;
410                 consolidated.writeBytes(b);
411                 c.freeIfNecessary();
412             }
413             Component c = new Component(consolidated);
414             c.endOffset = c.length;
415             components.clear();
416             components.add(c);
417         }
418     }
419 
420     private void checkComponentIndex(int cIndex) {
421         ensureAccessible();
422         if (cIndex < 0 || cIndex > components.size()) {
423             throw new IndexOutOfBoundsException(String.format(
424                     "cIndex: %d (expected: >= 0 && <= numComponents(%d))",
425                     cIndex, components.size()));
426         }
427     }
428 
429     private void checkComponentIndex(int cIndex, int numComponents) {
430         ensureAccessible();
431         if (cIndex < 0 || cIndex + numComponents > components.size()) {
432             throw new IndexOutOfBoundsException(String.format(
433                     "cIndex: %d, numComponents: %d " +
434                     "(expected: cIndex >= 0 && cIndex + numComponents <= totalNumComponents(%d))",
435                     cIndex, numComponents, components.size()));
436         }
437     }
438 
439     private void updateComponentOffsets(int cIndex) {
440         int size = components.size();
441         if (size <= cIndex) {
442             return;
443         }
444 
445         Component c = components.get(cIndex);
446         if (cIndex == 0) {
447             c.offset = 0;
448             c.endOffset = c.length;
449             cIndex ++;
450         }
451 
452         for (int i = cIndex; i < size; i ++) {
453             Component prev = components.get(i - 1);
454             Component cur = components.get(i);
455             cur.offset = prev.endOffset;
456             cur.endOffset = cur.offset + cur.length;
457         }
458     }
459 
460     /**
461      * Remove the {@link ByteBuf} from the given index.
462      *
463      * @param cIndex the index on from which the {@link ByteBuf} will be remove
464      */
465     public CompositeByteBuf removeComponent(int cIndex) {
466         checkComponentIndex(cIndex);
467         Component comp = components.remove(cIndex);
468         comp.freeIfNecessary();
469         if (comp.length > 0) {
470             // Only need to call updateComponentOffsets if the length was > 0
471             updateComponentOffsets(cIndex);
472         }
473         return this;
474     }
475 
476     /**
477      * Remove the number of {@link ByteBuf}s starting from the given index.
478      *
479      * @param cIndex the index on which the {@link ByteBuf}s will be started to removed
480      * @param numComponents the number of components to remove
481      */
482     public CompositeByteBuf removeComponents(int cIndex, int numComponents) {
483         checkComponentIndex(cIndex, numComponents);
484 
485         if (numComponents == 0) {
486             return this;
487         }
488         int endIndex = cIndex + numComponents;
489         boolean needsUpdate = false;
490         for (int i = cIndex; i < endIndex; ++i) {
491             Component c = components.get(i);
492             if (c.length > 0) {
493                 needsUpdate = true;
494             }
495             c.freeIfNecessary();
496         }
497         components.removeRange(cIndex, endIndex);
498 
499         if (needsUpdate) {
500             // Only need to call updateComponentOffsets if the length was > 0
501             updateComponentOffsets(cIndex);
502         }
503         return this;
504     }
505 
506     @Override
507     public Iterator<ByteBuf> iterator() {
508         ensureAccessible();
509         if (components.isEmpty()) {
510             return EMPTY_ITERATOR;
511         }
512         return new CompositeByteBufIterator();
513     }
514 
515     /**
516      * Same with {@link #slice(int, int)} except that this method returns a list.
517      */
518     public List<ByteBuf> decompose(int offset, int length) {
519         checkIndex(offset, length);
520         if (length == 0) {
521             return Collections.emptyList();
522         }
523 
524         int componentId = toComponentIndex(offset);
525         List<ByteBuf> slice = new ArrayList<ByteBuf>(components.size());
526 
527         // The first component
528         Component firstC = components.get(componentId);
529         ByteBuf first = firstC.buf.duplicate();
530         first.readerIndex(offset - firstC.offset);
531 
532         ByteBuf buf = first;
533         int bytesToSlice = length;
534         do {
535             int readableBytes = buf.readableBytes();
536             if (bytesToSlice <= readableBytes) {
537                 // Last component
538                 buf.writerIndex(buf.readerIndex() + bytesToSlice);
539                 slice.add(buf);
540                 break;
541             } else {
542                 // Not the last component
543                 slice.add(buf);
544                 bytesToSlice -= readableBytes;
545                 componentId ++;
546 
547                 // Fetch the next component.
548                 buf = components.get(componentId).buf.duplicate();
549             }
550         } while (bytesToSlice > 0);
551 
552         // Slice all components because only readable bytes are interesting.
553         for (int i = 0; i < slice.size(); i ++) {
554             slice.set(i, slice.get(i).slice());
555         }
556 
557         return slice;
558     }
559 
560     @Override
561     public boolean isDirect() {
562         int size = components.size();
563         if (size == 0) {
564             return false;
565         }
566         for (int i = 0; i < size; i++) {
567            if (!components.get(i).buf.isDirect()) {
568                return false;
569            }
570         }
571         return true;
572     }
573 
574     @Override
575     public boolean hasArray() {
576         switch (components.size()) {
577         case 0:
578             return true;
579         case 1:
580             return components.get(0).buf.hasArray();
581         default:
582             return false;
583         }
584     }
585 
586     @Override
587     public byte[] array() {
588         switch (components.size()) {
589         case 0:
590             return EmptyArrays.EMPTY_BYTES;
591         case 1:
592             return components.get(0).buf.array();
593         default:
594             throw new UnsupportedOperationException();
595         }
596     }
597 
598     @Override
599     public int arrayOffset() {
600         switch (components.size()) {
601         case 0:
602             return 0;
603         case 1:
604             return components.get(0).buf.arrayOffset();
605         default:
606             throw new UnsupportedOperationException();
607         }
608     }
609 
610     @Override
611     public boolean hasMemoryAddress() {
612         switch (components.size()) {
613         case 0:
614             return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
615         case 1:
616             return components.get(0).buf.hasMemoryAddress();
617         default:
618             return false;
619         }
620     }
621 
622     @Override
623     public long memoryAddress() {
624         switch (components.size()) {
625         case 0:
626             return Unpooled.EMPTY_BUFFER.memoryAddress();
627         case 1:
628             return components.get(0).buf.memoryAddress();
629         default:
630             throw new UnsupportedOperationException();
631         }
632     }
633 
634     @Override
635     public int capacity() {
636         final int numComponents = components.size();
637         if (numComponents == 0) {
638             return 0;
639         }
640         return components.get(numComponents - 1).endOffset;
641     }
642 
643     @Override
644     public CompositeByteBuf capacity(int newCapacity) {
645         checkNewCapacity(newCapacity);
646 
647         int oldCapacity = capacity();
648         if (newCapacity > oldCapacity) {
649             final int paddingLength = newCapacity - oldCapacity;
650             ByteBuf padding;
651             int nComponents = components.size();
652             if (nComponents < maxNumComponents) {
653                 padding = allocBuffer(paddingLength);
654                 padding.setIndex(0, paddingLength);
655                 addComponent0(false, components.size(), padding);
656             } else {
657                 padding = allocBuffer(paddingLength);
658                 padding.setIndex(0, paddingLength);
659                 // FIXME: No need to create a padding buffer and consolidate.
660                 // Just create a big single buffer and put the current content there.
661                 addComponent0(false, components.size(), padding);
662                 consolidateIfNeeded();
663             }
664         } else if (newCapacity < oldCapacity) {
665             int bytesToTrim = oldCapacity - newCapacity;
666             for (ListIterator<Component> i = components.listIterator(components.size()); i.hasPrevious();) {
667                 Component c = i.previous();
668                 if (bytesToTrim >= c.length) {
669                     bytesToTrim -= c.length;
670                     i.remove();
671                     continue;
672                 }
673 
674                 // Replace the last component with the trimmed slice.
675                 Component newC = new Component(c.buf.slice(0, c.length - bytesToTrim));
676                 newC.offset = c.offset;
677                 newC.endOffset = newC.offset + newC.length;
678                 i.set(newC);
679                 break;
680             }
681 
682             if (readerIndex() > newCapacity) {
683                 setIndex(newCapacity, newCapacity);
684             } else if (writerIndex() > newCapacity) {
685                 writerIndex(newCapacity);
686             }
687         }
688         return this;
689     }
690 
691     @Override
692     public ByteBufAllocator alloc() {
693         return alloc;
694     }
695 
696     @Override
697     public ByteOrder order() {
698         return ByteOrder.BIG_ENDIAN;
699     }
700 
701     /**
702      * Return the current number of {@link ByteBuf}'s that are composed in this instance
703      */
704     public int numComponents() {
705         return components.size();
706     }
707 
708     /**
709      * Return the max number of {@link ByteBuf}'s that are composed in this instance
710      */
711     public int maxNumComponents() {
712         return maxNumComponents;
713     }
714 
715     /**
716      * Return the index for the given offset
717      */
718     public int toComponentIndex(int offset) {
719         checkIndex(offset);
720 
721         for (int low = 0, high = components.size(); low <= high;) {
722             int mid = low + high >>> 1;
723             Component c = components.get(mid);
724             if (offset >= c.endOffset) {
725                 low = mid + 1;
726             } else if (offset < c.offset) {
727                 high = mid - 1;
728             } else {
729                 return mid;
730             }
731         }
732 
733         throw new Error("should not reach here");
734     }
735 
736     public int toByteIndex(int cIndex) {
737         checkComponentIndex(cIndex);
738         return components.get(cIndex).offset;
739     }
740 
741     @Override
742     public byte getByte(int index) {
743         return _getByte(index);
744     }
745 
746     @Override
747     protected byte _getByte(int index) {
748         Component c = findComponent(index);
749         return c.buf.getByte(index - c.offset);
750     }
751 
752     @Override
753     protected short _getShort(int index) {
754         Component c = findComponent(index);
755         if (index + 2 <= c.endOffset) {
756             return c.buf.getShort(index - c.offset);
757         } else if (order() == ByteOrder.BIG_ENDIAN) {
758             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
759         } else {
760             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
761         }
762     }
763 
764     @Override
765     protected int _getUnsignedMedium(int index) {
766         Component c = findComponent(index);
767         if (index + 3 <= c.endOffset) {
768             return c.buf.getUnsignedMedium(index - c.offset);
769         } else if (order() == ByteOrder.BIG_ENDIAN) {
770             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
771         } else {
772             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
773         }
774     }
775 
776     @Override
777     protected int _getInt(int index) {
778         Component c = findComponent(index);
779         if (index + 4 <= c.endOffset) {
780             return c.buf.getInt(index - c.offset);
781         } else if (order() == ByteOrder.BIG_ENDIAN) {
782             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
783         } else {
784             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
785         }
786     }
787 
788     @Override
789     protected long _getLong(int index) {
790         Component c = findComponent(index);
791         if (index + 8 <= c.endOffset) {
792             return c.buf.getLong(index - c.offset);
793         } else if (order() == ByteOrder.BIG_ENDIAN) {
794             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
795         } else {
796             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
797         }
798     }
799 
800     @Override
801     public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
802         checkDstIndex(index, length, dstIndex, dst.length);
803         if (length == 0) {
804             return this;
805         }
806 
807         int i = toComponentIndex(index);
808         while (length > 0) {
809             Component c = components.get(i);
810             ByteBuf s = c.buf;
811             int adjustment = c.offset;
812             int localLength = Math.min(length, s.capacity() - (index - adjustment));
813             s.getBytes(index - adjustment, dst, dstIndex, localLength);
814             index += localLength;
815             dstIndex += localLength;
816             length -= localLength;
817             i ++;
818         }
819         return this;
820     }
821 
822     @Override
823     public CompositeByteBuf getBytes(int index, ByteBuffer dst) {
824         int limit = dst.limit();
825         int length = dst.remaining();
826 
827         checkIndex(index, length);
828         if (length == 0) {
829             return this;
830         }
831 
832         int i = toComponentIndex(index);
833         try {
834             while (length > 0) {
835                 Component c = components.get(i);
836                 ByteBuf s = c.buf;
837                 int adjustment = c.offset;
838                 int localLength = Math.min(length, s.capacity() - (index - adjustment));
839                 dst.limit(dst.position() + localLength);
840                 s.getBytes(index - adjustment, dst);
841                 index += localLength;
842                 length -= localLength;
843                 i ++;
844             }
845         } finally {
846             dst.limit(limit);
847         }
848         return this;
849     }
850 
851     @Override
852     public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
853         checkDstIndex(index, length, dstIndex, dst.capacity());
854         if (length == 0) {
855             return this;
856         }
857 
858         int i = toComponentIndex(index);
859         while (length > 0) {
860             Component c = components.get(i);
861             ByteBuf s = c.buf;
862             int adjustment = c.offset;
863             int localLength = Math.min(length, s.capacity() - (index - adjustment));
864             s.getBytes(index - adjustment, dst, dstIndex, localLength);
865             index += localLength;
866             dstIndex += localLength;
867             length -= localLength;
868             i ++;
869         }
870         return this;
871     }
872 
873     @Override
874     public int getBytes(int index, GatheringByteChannel out, int length)
875             throws IOException {
876         int count = nioBufferCount();
877         if (count == 1) {
878             return out.write(internalNioBuffer(index, length));
879         } else {
880             long writtenBytes = out.write(nioBuffers(index, length));
881             if (writtenBytes > Integer.MAX_VALUE) {
882                 return Integer.MAX_VALUE;
883             } else {
884                 return (int) writtenBytes;
885             }
886         }
887     }
888 
889     @Override
890     public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
891         checkIndex(index, length);
892         if (length == 0) {
893             return this;
894         }
895 
896         int i = toComponentIndex(index);
897         while (length > 0) {
898             Component c = components.get(i);
899             ByteBuf s = c.buf;
900             int adjustment = c.offset;
901             int localLength = Math.min(length, s.capacity() - (index - adjustment));
902             s.getBytes(index - adjustment, out, localLength);
903             index += localLength;
904             length -= localLength;
905             i ++;
906         }
907         return this;
908     }
909 
910     @Override
911     public CompositeByteBuf setByte(int index, int value) {
912         Component c = findComponent(index);
913         c.buf.setByte(index - c.offset, value);
914         return this;
915     }
916 
917     @Override
918     protected void _setByte(int index, int value) {
919         setByte(index, value);
920     }
921 
922     @Override
923     public CompositeByteBuf setShort(int index, int value) {
924         return (CompositeByteBuf) super.setShort(index, value);
925     }
926 
927     @Override
928     protected void _setShort(int index, int value) {
929         Component c = findComponent(index);
930         if (index + 2 <= c.endOffset) {
931             c.buf.setShort(index - c.offset, value);
932         } else if (order() == ByteOrder.BIG_ENDIAN) {
933             _setByte(index, (byte) (value >>> 8));
934             _setByte(index + 1, (byte) value);
935         } else {
936             _setByte(index, (byte) value);
937             _setByte(index + 1, (byte) (value >>> 8));
938         }
939     }
940 
941     @Override
942     public CompositeByteBuf setMedium(int index, int value) {
943         return (CompositeByteBuf) super.setMedium(index, value);
944     }
945 
946     @Override
947     protected void _setMedium(int index, int value) {
948         Component c = findComponent(index);
949         if (index + 3 <= c.endOffset) {
950             c.buf.setMedium(index - c.offset, value);
951         } else if (order() == ByteOrder.BIG_ENDIAN) {
952             _setShort(index, (short) (value >> 8));
953             _setByte(index + 2, (byte) value);
954         } else {
955             _setShort(index, (short) value);
956             _setByte(index + 2, (byte) (value >>> 16));
957         }
958     }
959 
960     @Override
961     public CompositeByteBuf setInt(int index, int value) {
962         return (CompositeByteBuf) super.setInt(index, value);
963     }
964 
965     @Override
966     protected void _setInt(int index, int value) {
967         Component c = findComponent(index);
968         if (index + 4 <= c.endOffset) {
969             c.buf.setInt(index - c.offset, value);
970         } else if (order() == ByteOrder.BIG_ENDIAN) {
971             _setShort(index, (short) (value >>> 16));
972             _setShort(index + 2, (short) value);
973         } else {
974             _setShort(index, (short) value);
975             _setShort(index + 2, (short) (value >>> 16));
976         }
977     }
978 
979     @Override
980     public CompositeByteBuf setLong(int index, long value) {
981         return (CompositeByteBuf) super.setLong(index, value);
982     }
983 
984     @Override
985     protected void _setLong(int index, long value) {
986         Component c = findComponent(index);
987         if (index + 8 <= c.endOffset) {
988             c.buf.setLong(index - c.offset, value);
989         } else if (order() == ByteOrder.BIG_ENDIAN) {
990             _setInt(index, (int) (value >>> 32));
991             _setInt(index + 4, (int) value);
992         } else {
993             _setInt(index, (int) value);
994             _setInt(index + 4, (int) (value >>> 32));
995         }
996     }
997 
998     @Override
999     public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
1000         checkSrcIndex(index, length, srcIndex, src.length);
1001         if (length == 0) {
1002             return this;
1003         }
1004 
1005         int i = toComponentIndex(index);
1006         while (length > 0) {
1007             Component c = components.get(i);
1008             ByteBuf s = c.buf;
1009             int adjustment = c.offset;
1010             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1011             s.setBytes(index - adjustment, src, srcIndex, localLength);
1012             index += localLength;
1013             srcIndex += localLength;
1014             length -= localLength;
1015             i ++;
1016         }
1017         return this;
1018     }
1019 
1020     @Override
1021     public CompositeByteBuf setBytes(int index, ByteBuffer src) {
1022         int limit = src.limit();
1023         int length = src.remaining();
1024 
1025         checkIndex(index, length);
1026         if (length == 0) {
1027             return this;
1028         }
1029 
1030         int i = toComponentIndex(index);
1031         try {
1032             while (length > 0) {
1033                 Component c = components.get(i);
1034                 ByteBuf s = c.buf;
1035                 int adjustment = c.offset;
1036                 int localLength = Math.min(length, s.capacity() - (index - adjustment));
1037                 src.limit(src.position() + localLength);
1038                 s.setBytes(index - adjustment, src);
1039                 index += localLength;
1040                 length -= localLength;
1041                 i ++;
1042             }
1043         } finally {
1044             src.limit(limit);
1045         }
1046         return this;
1047     }
1048 
1049     @Override
1050     public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
1051         checkSrcIndex(index, length, srcIndex, src.capacity());
1052         if (length == 0) {
1053             return this;
1054         }
1055 
1056         int i = toComponentIndex(index);
1057         while (length > 0) {
1058             Component c = components.get(i);
1059             ByteBuf s = c.buf;
1060             int adjustment = c.offset;
1061             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1062             s.setBytes(index - adjustment, src, srcIndex, localLength);
1063             index += localLength;
1064             srcIndex += localLength;
1065             length -= localLength;
1066             i ++;
1067         }
1068         return this;
1069     }
1070 
1071     @Override
1072     public int setBytes(int index, InputStream in, int length) throws IOException {
1073         checkIndex(index, length);
1074         if (length == 0) {
1075             return in.read(EmptyArrays.EMPTY_BYTES);
1076         }
1077 
1078         int i = toComponentIndex(index);
1079         int readBytes = 0;
1080 
1081         do {
1082             Component c = components.get(i);
1083             ByteBuf s = c.buf;
1084             int adjustment = c.offset;
1085             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1086             int localReadBytes = s.setBytes(index - adjustment, in, localLength);
1087             if (localReadBytes < 0) {
1088                 if (readBytes == 0) {
1089                     return -1;
1090                 } else {
1091                     break;
1092                 }
1093             }
1094 
1095             if (localReadBytes == localLength) {
1096                 index += localLength;
1097                 length -= localLength;
1098                 readBytes += localLength;
1099                 i ++;
1100             } else {
1101                 index += localReadBytes;
1102                 length -= localReadBytes;
1103                 readBytes += localReadBytes;
1104             }
1105         } while (length > 0);
1106 
1107         return readBytes;
1108     }
1109 
1110     @Override
1111     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
1112         checkIndex(index, length);
1113         if (length == 0) {
1114             return in.read(EMPTY_NIO_BUFFER);
1115         }
1116 
1117         int i = toComponentIndex(index);
1118         int readBytes = 0;
1119         do {
1120             Component c = components.get(i);
1121             ByteBuf s = c.buf;
1122             int adjustment = c.offset;
1123             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1124             int localReadBytes = s.setBytes(index - adjustment, in, localLength);
1125 
1126             if (localReadBytes == 0) {
1127                 break;
1128             }
1129 
1130             if (localReadBytes < 0) {
1131                 if (readBytes == 0) {
1132                     return -1;
1133                 } else {
1134                     break;
1135                 }
1136             }
1137 
1138             if (localReadBytes == localLength) {
1139                 index += localLength;
1140                 length -= localLength;
1141                 readBytes += localLength;
1142                 i ++;
1143             } else {
1144                 index += localReadBytes;
1145                 length -= localReadBytes;
1146                 readBytes += localReadBytes;
1147             }
1148         } while (length > 0);
1149 
1150         return readBytes;
1151     }
1152 
1153     @Override
1154     public ByteBuf copy(int index, int length) {
1155         checkIndex(index, length);
1156         ByteBuf dst = allocBuffer(length);
1157         if (length != 0) {
1158             copyTo(index, length, toComponentIndex(index), dst);
1159         }
1160         return dst;
1161     }
1162 
1163     private void copyTo(int index, int length, int componentId, ByteBuf dst) {
1164         int dstIndex = 0;
1165         int i = componentId;
1166 
1167         while (length > 0) {
1168             Component c = components.get(i);
1169             ByteBuf s = c.buf;
1170             int adjustment = c.offset;
1171             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1172             s.getBytes(index - adjustment, dst, dstIndex, localLength);
1173             index += localLength;
1174             dstIndex += localLength;
1175             length -= localLength;
1176             i ++;
1177         }
1178 
1179         dst.writerIndex(dst.capacity());
1180     }
1181 
1182     /**
1183      * Return the {@link ByteBuf} on the specified index
1184      *
1185      * @param cIndex the index for which the {@link ByteBuf} should be returned
1186      * @return buf the {@link ByteBuf} on the specified index
1187      */
1188     public ByteBuf component(int cIndex) {
1189         return internalComponent(cIndex).duplicate();
1190     }
1191 
1192     /**
1193      * Return the {@link ByteBuf} on the specified index
1194      *
1195      * @param offset the offset for which the {@link ByteBuf} should be returned
1196      * @return the {@link ByteBuf} on the specified index
1197      */
1198     public ByteBuf componentAtOffset(int offset) {
1199         return internalComponentAtOffset(offset).duplicate();
1200     }
1201 
1202     /**
1203      * Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
1204      * buffer will lead to an undefined behavior of this buffer.
1205      *
1206      * @param cIndex the index for which the {@link ByteBuf} should be returned
1207      */
1208     public ByteBuf internalComponent(int cIndex) {
1209         checkComponentIndex(cIndex);
1210         return components.get(cIndex).buf;
1211     }
1212 
1213     /**
1214      * Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
1215      * buffer will lead to an undefined behavior of this buffer.
1216      *
1217      * @param offset the offset for which the {@link ByteBuf} should be returned
1218      */
1219     public ByteBuf internalComponentAtOffset(int offset) {
1220         return findComponent(offset).buf;
1221     }
1222 
1223     private Component findComponent(int offset) {
1224         checkIndex(offset);
1225 
1226         for (int low = 0, high = components.size(); low <= high;) {
1227             int mid = low + high >>> 1;
1228             Component c = components.get(mid);
1229             if (offset >= c.endOffset) {
1230                 low = mid + 1;
1231             } else if (offset < c.offset) {
1232                 high = mid - 1;
1233             } else {
1234                 assert c.length != 0;
1235                 return c;
1236             }
1237         }
1238 
1239         throw new Error("should not reach here");
1240     }
1241 
1242     @Override
1243     public int nioBufferCount() {
1244         switch (components.size()) {
1245         case 0:
1246             return 1;
1247         case 1:
1248             return components.get(0).buf.nioBufferCount();
1249         default:
1250             int count = 0;
1251             int componentsCount = components.size();
1252             for (int i = 0; i < componentsCount; i++) {
1253                 Component c = components.get(i);
1254                 count += c.buf.nioBufferCount();
1255             }
1256             return count;
1257         }
1258     }
1259 
1260     @Override
1261     public ByteBuffer internalNioBuffer(int index, int length) {
1262         switch (components.size()) {
1263         case 0:
1264             return EMPTY_NIO_BUFFER;
1265         case 1:
1266             return components.get(0).buf.internalNioBuffer(index, length);
1267         default:
1268             throw new UnsupportedOperationException();
1269         }
1270     }
1271 
1272     @Override
1273     public ByteBuffer nioBuffer(int index, int length) {
1274         checkIndex(index, length);
1275 
1276         switch (components.size()) {
1277         case 0:
1278             return EMPTY_NIO_BUFFER;
1279         case 1:
1280             ByteBuf buf = components.get(0).buf;
1281             if (buf.nioBufferCount() == 1) {
1282                 return components.get(0).buf.nioBuffer(index, length);
1283             }
1284         }
1285 
1286         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
1287         ByteBuffer[] buffers = nioBuffers(index, length);
1288 
1289         for (ByteBuffer buf: buffers) {
1290             merged.put(buf);
1291         }
1292 
1293         merged.flip();
1294         return merged;
1295     }
1296 
1297     @Override
1298     public ByteBuffer[] nioBuffers(int index, int length) {
1299         checkIndex(index, length);
1300         if (length == 0) {
1301             return new ByteBuffer[] { EMPTY_NIO_BUFFER };
1302         }
1303 
1304         List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.size());
1305         int i = toComponentIndex(index);
1306         while (length > 0) {
1307             Component c = components.get(i);
1308             ByteBuf s = c.buf;
1309             int adjustment = c.offset;
1310             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1311             switch (s.nioBufferCount()) {
1312                 case 0:
1313                     throw new UnsupportedOperationException();
1314                 case 1:
1315                     buffers.add(s.nioBuffer(index - adjustment, localLength));
1316                     break;
1317                 default:
1318                     Collections.addAll(buffers, s.nioBuffers(index - adjustment, localLength));
1319             }
1320 
1321             index += localLength;
1322             length -= localLength;
1323             i ++;
1324         }
1325 
1326         return buffers.toArray(new ByteBuffer[buffers.size()]);
1327     }
1328 
1329     /**
1330      * Consolidate the composed {@link ByteBuf}s
1331      */
1332     public CompositeByteBuf consolidate() {
1333         ensureAccessible();
1334         final int numComponents = numComponents();
1335         if (numComponents <= 1) {
1336             return this;
1337         }
1338 
1339         final Component last = components.get(numComponents - 1);
1340         final int capacity = last.endOffset;
1341         final ByteBuf consolidated = allocBuffer(capacity);
1342 
1343         for (int i = 0; i < numComponents; i ++) {
1344             Component c = components.get(i);
1345             ByteBuf b = c.buf;
1346             consolidated.writeBytes(b);
1347             c.freeIfNecessary();
1348         }
1349 
1350         components.clear();
1351         components.add(new Component(consolidated));
1352         updateComponentOffsets(0);
1353         return this;
1354     }
1355 
1356     /**
1357      * Consolidate the composed {@link ByteBuf}s
1358      *
1359      * @param cIndex the index on which to start to compose
1360      * @param numComponents the number of components to compose
1361      */
1362     public CompositeByteBuf consolidate(int cIndex, int numComponents) {
1363         checkComponentIndex(cIndex, numComponents);
1364         if (numComponents <= 1) {
1365             return this;
1366         }
1367 
1368         final int endCIndex = cIndex + numComponents;
1369         final Component last = components.get(endCIndex - 1);
1370         final int capacity = last.endOffset - components.get(cIndex).offset;
1371         final ByteBuf consolidated = allocBuffer(capacity);
1372 
1373         for (int i = cIndex; i < endCIndex; i ++) {
1374             Component c = components.get(i);
1375             ByteBuf b = c.buf;
1376             consolidated.writeBytes(b);
1377             c.freeIfNecessary();
1378         }
1379 
1380         components.removeRange(cIndex + 1, endCIndex);
1381         components.set(cIndex, new Component(consolidated));
1382         updateComponentOffsets(cIndex);
1383         return this;
1384     }
1385 
1386     /**
1387      * Discard all {@link ByteBuf}s which are read.
1388      */
1389     public CompositeByteBuf discardReadComponents() {
1390         ensureAccessible();
1391         final int readerIndex = readerIndex();
1392         if (readerIndex == 0) {
1393             return this;
1394         }
1395 
1396         // Discard everything if (readerIndex = writerIndex = capacity).
1397         int writerIndex = writerIndex();
1398         if (readerIndex == writerIndex && writerIndex == capacity()) {
1399             int size = components.size();
1400             for (int i = 0; i < size; i++) {
1401                 components.get(i).freeIfNecessary();
1402             }
1403             components.clear();
1404             setIndex(0, 0);
1405             adjustMarkers(readerIndex);
1406             return this;
1407         }
1408 
1409         // Remove read components.
1410         int firstComponentId = toComponentIndex(readerIndex);
1411         for (int i = 0; i < firstComponentId; i ++) {
1412             components.get(i).freeIfNecessary();
1413         }
1414         components.removeRange(0, firstComponentId);
1415 
1416         // Update indexes and markers.
1417         Component first = components.get(0);
1418         int offset = first.offset;
1419         updateComponentOffsets(0);
1420         setIndex(readerIndex - offset, writerIndex - offset);
1421         adjustMarkers(offset);
1422         return this;
1423     }
1424 
1425     @Override
1426     public CompositeByteBuf discardReadBytes() {
1427         ensureAccessible();
1428         final int readerIndex = readerIndex();
1429         if (readerIndex == 0) {
1430             return this;
1431         }
1432 
1433         // Discard everything if (readerIndex = writerIndex = capacity).
1434         int writerIndex = writerIndex();
1435         if (readerIndex == writerIndex && writerIndex == capacity()) {
1436             int size = components.size();
1437             for (int i = 0; i < size; i++) {
1438                 components.get(i).freeIfNecessary();
1439             }
1440             components.clear();
1441             setIndex(0, 0);
1442             adjustMarkers(readerIndex);
1443             return this;
1444         }
1445 
1446         // Remove read components.
1447         int firstComponentId = toComponentIndex(readerIndex);
1448         for (int i = 0; i < firstComponentId; i ++) {
1449             components.get(i).freeIfNecessary();
1450         }
1451 
1452         // Remove or replace the first readable component with a new slice.
1453         Component c = components.get(firstComponentId);
1454         int adjustment = readerIndex - c.offset;
1455         if (adjustment == c.length) {
1456             // new slice would be empty, so remove instead
1457             firstComponentId++;
1458         } else {
1459             Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment));
1460             components.set(firstComponentId, newC);
1461         }
1462 
1463         components.removeRange(0, firstComponentId);
1464 
1465         // Update indexes and markers.
1466         updateComponentOffsets(0);
1467         setIndex(0, writerIndex - readerIndex);
1468         adjustMarkers(readerIndex);
1469         return this;
1470     }
1471 
1472     private ByteBuf allocBuffer(int capacity) {
1473         return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
1474     }
1475 
1476     @Override
1477     public String toString() {
1478         String result = super.toString();
1479         result = result.substring(0, result.length() - 1);
1480         return result + ", components=" + components.size() + ')';
1481     }
1482 
1483     private static final class Component {
1484         final ByteBuf buf;
1485         final int length;
1486         int offset;
1487         int endOffset;
1488 
1489         Component(ByteBuf buf) {
1490             this.buf = buf;
1491             length = buf.readableBytes();
1492         }
1493 
1494         void freeIfNecessary() {
1495             buf.release(); // We should not get a NPE here. If so, it must be a bug.
1496         }
1497     }
1498 
1499     @Override
1500     public CompositeByteBuf readerIndex(int readerIndex) {
1501         return (CompositeByteBuf) super.readerIndex(readerIndex);
1502     }
1503 
1504     @Override
1505     public CompositeByteBuf writerIndex(int writerIndex) {
1506         return (CompositeByteBuf) super.writerIndex(writerIndex);
1507     }
1508 
1509     @Override
1510     public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
1511         return (CompositeByteBuf) super.setIndex(readerIndex, writerIndex);
1512     }
1513 
1514     @Override
1515     public CompositeByteBuf clear() {
1516         return (CompositeByteBuf) super.clear();
1517     }
1518 
1519     @Override
1520     public CompositeByteBuf markReaderIndex() {
1521         return (CompositeByteBuf) super.markReaderIndex();
1522     }
1523 
1524     @Override
1525     public CompositeByteBuf resetReaderIndex() {
1526         return (CompositeByteBuf) super.resetReaderIndex();
1527     }
1528 
1529     @Override
1530     public CompositeByteBuf markWriterIndex() {
1531         return (CompositeByteBuf) super.markWriterIndex();
1532     }
1533 
1534     @Override
1535     public CompositeByteBuf resetWriterIndex() {
1536         return (CompositeByteBuf) super.resetWriterIndex();
1537     }
1538 
1539     @Override
1540     public CompositeByteBuf ensureWritable(int minWritableBytes) {
1541         return (CompositeByteBuf) super.ensureWritable(minWritableBytes);
1542     }
1543 
1544     @Override
1545     public CompositeByteBuf getBytes(int index, ByteBuf dst) {
1546         return (CompositeByteBuf) super.getBytes(index, dst);
1547     }
1548 
1549     @Override
1550     public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
1551         return (CompositeByteBuf) super.getBytes(index, dst, length);
1552     }
1553 
1554     @Override
1555     public CompositeByteBuf getBytes(int index, byte[] dst) {
1556         return (CompositeByteBuf) super.getBytes(index, dst);
1557     }
1558 
1559     @Override
1560     public CompositeByteBuf setBoolean(int index, boolean value) {
1561         return (CompositeByteBuf) super.setBoolean(index, value);
1562     }
1563 
1564     @Override
1565     public CompositeByteBuf setChar(int index, int value) {
1566         return (CompositeByteBuf) super.setChar(index, value);
1567     }
1568 
1569     @Override
1570     public CompositeByteBuf setFloat(int index, float value) {
1571         return (CompositeByteBuf) super.setFloat(index, value);
1572     }
1573 
1574     @Override
1575     public CompositeByteBuf setDouble(int index, double value) {
1576         return (CompositeByteBuf) super.setDouble(index, value);
1577     }
1578 
1579     @Override
1580     public CompositeByteBuf setBytes(int index, ByteBuf src) {
1581         return (CompositeByteBuf) super.setBytes(index, src);
1582     }
1583 
1584     @Override
1585     public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
1586         return (CompositeByteBuf) super.setBytes(index, src, length);
1587     }
1588 
1589     @Override
1590     public CompositeByteBuf setBytes(int index, byte[] src) {
1591         return (CompositeByteBuf) super.setBytes(index, src);
1592     }
1593 
1594     @Override
1595     public CompositeByteBuf setZero(int index, int length) {
1596         return (CompositeByteBuf) super.setZero(index, length);
1597     }
1598 
1599     @Override
1600     public CompositeByteBuf readBytes(ByteBuf dst) {
1601         return (CompositeByteBuf) super.readBytes(dst);
1602     }
1603 
1604     @Override
1605     public CompositeByteBuf readBytes(ByteBuf dst, int length) {
1606         return (CompositeByteBuf) super.readBytes(dst, length);
1607     }
1608 
1609     @Override
1610     public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
1611         return (CompositeByteBuf) super.readBytes(dst, dstIndex, length);
1612     }
1613 
1614     @Override
1615     public CompositeByteBuf readBytes(byte[] dst) {
1616         return (CompositeByteBuf) super.readBytes(dst);
1617     }
1618 
1619     @Override
1620     public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
1621         return (CompositeByteBuf) super.readBytes(dst, dstIndex, length);
1622     }
1623 
1624     @Override
1625     public CompositeByteBuf readBytes(ByteBuffer dst) {
1626         return (CompositeByteBuf) super.readBytes(dst);
1627     }
1628 
1629     @Override
1630     public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
1631         return (CompositeByteBuf) super.readBytes(out, length);
1632     }
1633 
1634     @Override
1635     public CompositeByteBuf skipBytes(int length) {
1636         return (CompositeByteBuf) super.skipBytes(length);
1637     }
1638 
1639     @Override
1640     public CompositeByteBuf writeBoolean(boolean value) {
1641         return (CompositeByteBuf) super.writeBoolean(value);
1642     }
1643 
1644     @Override
1645     public CompositeByteBuf writeByte(int value) {
1646         return (CompositeByteBuf) super.writeByte(value);
1647     }
1648 
1649     @Override
1650     public CompositeByteBuf writeShort(int value) {
1651         return (CompositeByteBuf) super.writeShort(value);
1652     }
1653 
1654     @Override
1655     public CompositeByteBuf writeMedium(int value) {
1656         return (CompositeByteBuf) super.writeMedium(value);
1657     }
1658 
1659     @Override
1660     public CompositeByteBuf writeInt(int value) {
1661         return (CompositeByteBuf) super.writeInt(value);
1662     }
1663 
1664     @Override
1665     public CompositeByteBuf writeLong(long value) {
1666         return (CompositeByteBuf) super.writeLong(value);
1667     }
1668 
1669     @Override
1670     public CompositeByteBuf writeChar(int value) {
1671         return (CompositeByteBuf) super.writeChar(value);
1672     }
1673 
1674     @Override
1675     public CompositeByteBuf writeFloat(float value) {
1676         return (CompositeByteBuf) super.writeFloat(value);
1677     }
1678 
1679     @Override
1680     public CompositeByteBuf writeDouble(double value) {
1681         return (CompositeByteBuf) super.writeDouble(value);
1682     }
1683 
1684     @Override
1685     public CompositeByteBuf writeBytes(ByteBuf src) {
1686         return (CompositeByteBuf) super.writeBytes(src);
1687     }
1688 
1689     @Override
1690     public CompositeByteBuf writeBytes(ByteBuf src, int length) {
1691         return (CompositeByteBuf) super.writeBytes(src, length);
1692     }
1693 
1694     @Override
1695     public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
1696         return (CompositeByteBuf) super.writeBytes(src, srcIndex, length);
1697     }
1698 
1699     @Override
1700     public CompositeByteBuf writeBytes(byte[] src) {
1701         return (CompositeByteBuf) super.writeBytes(src);
1702     }
1703 
1704     @Override
1705     public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
1706         return (CompositeByteBuf) super.writeBytes(src, srcIndex, length);
1707     }
1708 
1709     @Override
1710     public CompositeByteBuf writeBytes(ByteBuffer src) {
1711         return (CompositeByteBuf) super.writeBytes(src);
1712     }
1713 
1714     @Override
1715     public CompositeByteBuf writeZero(int length) {
1716         return (CompositeByteBuf) super.writeZero(length);
1717     }
1718 
1719     @Override
1720     public CompositeByteBuf retain(int increment) {
1721         return (CompositeByteBuf) super.retain(increment);
1722     }
1723 
1724     @Override
1725     public CompositeByteBuf retain() {
1726         return (CompositeByteBuf) super.retain();
1727     }
1728 
1729     @Override
1730     public ByteBuffer[] nioBuffers() {
1731         return nioBuffers(readerIndex(), readableBytes());
1732     }
1733 
1734     @Override
1735     public CompositeByteBuf discardSomeReadBytes() {
1736         return discardReadComponents();
1737     }
1738 
1739     @Override
1740     protected void deallocate() {
1741         if (freed) {
1742             return;
1743         }
1744 
1745         freed = true;
1746         int size = components.size();
1747         // We're not using foreach to avoid creating an iterator.
1748         // see https://github.com/netty/netty/issues/2642
1749         for (int i = 0; i < size; i++) {
1750             components.get(i).freeIfNecessary();
1751         }
1752     }
1753 
1754     @Override
1755     public ByteBuf unwrap() {
1756         return null;
1757     }
1758 
1759     private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
1760         private final int size = components.size();
1761         private int index;
1762 
1763         @Override
1764         public boolean hasNext() {
1765             return size > index;
1766         }
1767 
1768         @Override
1769         public ByteBuf next() {
1770             if (size != components.size()) {
1771                 throw new ConcurrentModificationException();
1772             }
1773             if (!hasNext()) {
1774                 throw new NoSuchElementException();
1775             }
1776             try {
1777                 return components.get(index++).buf;
1778             } catch (IndexOutOfBoundsException e) {
1779                 throw new ConcurrentModificationException();
1780             }
1781         }
1782 
1783         @Override
1784         public void remove() {
1785             throw new UnsupportedOperationException("Read-Only");
1786         }
1787     }
1788 
1789     private static final class ComponentList extends ArrayList<Component> {
1790 
1791         ComponentList(int initialCapacity) {
1792             super(initialCapacity);
1793         }
1794 
1795         // Expose this methods so we not need to create a new subList just to remove a range of elements.
1796         @Override
1797         public void removeRange(int fromIndex, int toIndex) {
1798             super.removeRange(fromIndex, toIndex);
1799         }
1800     }
1801 }