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 List<Component> 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 List<Component> newList(int maxNumComponents) {
113         return new ArrayList<Component>(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 = Collections.emptyList();
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         List<Component> toRemove = components.subList(cIndex, cIndex + numComponents);
489         boolean needsUpdate = false;
490         for (Component c: toRemove) {
491             if (c.length > 0) {
492                 needsUpdate = true;
493             }
494             c.freeIfNecessary();
495         }
496         toRemove.clear();
497 
498         if (needsUpdate) {
499             // Only need to call updateComponentOffsets if the length was > 0
500             updateComponentOffsets(cIndex);
501         }
502         return this;
503     }
504 
505     @Override
506     public Iterator<ByteBuf> iterator() {
507         ensureAccessible();
508         if (components.isEmpty()) {
509             return EMPTY_ITERATOR;
510         }
511         return new CompositeByteBufIterator();
512     }
513 
514     /**
515      * Same with {@link #slice(int, int)} except that this method returns a list.
516      */
517     public List<ByteBuf> decompose(int offset, int length) {
518         checkIndex(offset, length);
519         if (length == 0) {
520             return Collections.emptyList();
521         }
522 
523         int componentId = toComponentIndex(offset);
524         List<ByteBuf> slice = new ArrayList<ByteBuf>(components.size());
525 
526         // The first component
527         Component firstC = components.get(componentId);
528         ByteBuf first = firstC.buf.duplicate();
529         first.readerIndex(offset - firstC.offset);
530 
531         ByteBuf buf = first;
532         int bytesToSlice = length;
533         do {
534             int readableBytes = buf.readableBytes();
535             if (bytesToSlice <= readableBytes) {
536                 // Last component
537                 buf.writerIndex(buf.readerIndex() + bytesToSlice);
538                 slice.add(buf);
539                 break;
540             } else {
541                 // Not the last component
542                 slice.add(buf);
543                 bytesToSlice -= readableBytes;
544                 componentId ++;
545 
546                 // Fetch the next component.
547                 buf = components.get(componentId).buf.duplicate();
548             }
549         } while (bytesToSlice > 0);
550 
551         // Slice all components because only readable bytes are interesting.
552         for (int i = 0; i < slice.size(); i ++) {
553             slice.set(i, slice.get(i).slice());
554         }
555 
556         return slice;
557     }
558 
559     @Override
560     public boolean isDirect() {
561         int size = components.size();
562         if (size == 0) {
563             return false;
564         }
565         for (int i = 0; i < size; i++) {
566            if (!components.get(i).buf.isDirect()) {
567                return false;
568            }
569         }
570         return true;
571     }
572 
573     @Override
574     public boolean hasArray() {
575         switch (components.size()) {
576         case 0:
577             return true;
578         case 1:
579             return components.get(0).buf.hasArray();
580         default:
581             return false;
582         }
583     }
584 
585     @Override
586     public byte[] array() {
587         switch (components.size()) {
588         case 0:
589             return EmptyArrays.EMPTY_BYTES;
590         case 1:
591             return components.get(0).buf.array();
592         default:
593             throw new UnsupportedOperationException();
594         }
595     }
596 
597     @Override
598     public int arrayOffset() {
599         switch (components.size()) {
600         case 0:
601             return 0;
602         case 1:
603             return components.get(0).buf.arrayOffset();
604         default:
605             throw new UnsupportedOperationException();
606         }
607     }
608 
609     @Override
610     public boolean hasMemoryAddress() {
611         switch (components.size()) {
612         case 0:
613             return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
614         case 1:
615             return components.get(0).buf.hasMemoryAddress();
616         default:
617             return false;
618         }
619     }
620 
621     @Override
622     public long memoryAddress() {
623         switch (components.size()) {
624         case 0:
625             return Unpooled.EMPTY_BUFFER.memoryAddress();
626         case 1:
627             return components.get(0).buf.memoryAddress();
628         default:
629             throw new UnsupportedOperationException();
630         }
631     }
632 
633     @Override
634     public int capacity() {
635         final int numComponents = components.size();
636         if (numComponents == 0) {
637             return 0;
638         }
639         return components.get(numComponents - 1).endOffset;
640     }
641 
642     @Override
643     public CompositeByteBuf capacity(int newCapacity) {
644         checkNewCapacity(newCapacity);
645 
646         int oldCapacity = capacity();
647         if (newCapacity > oldCapacity) {
648             final int paddingLength = newCapacity - oldCapacity;
649             ByteBuf padding;
650             int nComponents = components.size();
651             if (nComponents < maxNumComponents) {
652                 padding = allocBuffer(paddingLength);
653                 padding.setIndex(0, paddingLength);
654                 addComponent0(false, components.size(), padding);
655             } else {
656                 padding = allocBuffer(paddingLength);
657                 padding.setIndex(0, paddingLength);
658                 // FIXME: No need to create a padding buffer and consolidate.
659                 // Just create a big single buffer and put the current content there.
660                 addComponent0(false, components.size(), padding);
661                 consolidateIfNeeded();
662             }
663         } else if (newCapacity < oldCapacity) {
664             int bytesToTrim = oldCapacity - newCapacity;
665             for (ListIterator<Component> i = components.listIterator(components.size()); i.hasPrevious();) {
666                 Component c = i.previous();
667                 if (bytesToTrim >= c.length) {
668                     bytesToTrim -= c.length;
669                     i.remove();
670                     continue;
671                 }
672 
673                 // Replace the last component with the trimmed slice.
674                 Component newC = new Component(c.buf.slice(0, c.length - bytesToTrim));
675                 newC.offset = c.offset;
676                 newC.endOffset = newC.offset + newC.length;
677                 i.set(newC);
678                 break;
679             }
680 
681             if (readerIndex() > newCapacity) {
682                 setIndex(newCapacity, newCapacity);
683             } else if (writerIndex() > newCapacity) {
684                 writerIndex(newCapacity);
685             }
686         }
687         return this;
688     }
689 
690     @Override
691     public ByteBufAllocator alloc() {
692         return alloc;
693     }
694 
695     @Override
696     public ByteOrder order() {
697         return ByteOrder.BIG_ENDIAN;
698     }
699 
700     /**
701      * Return the current number of {@link ByteBuf}'s that are composed in this instance
702      */
703     public int numComponents() {
704         return components.size();
705     }
706 
707     /**
708      * Return the max number of {@link ByteBuf}'s that are composed in this instance
709      */
710     public int maxNumComponents() {
711         return maxNumComponents;
712     }
713 
714     /**
715      * Return the index for the given offset
716      */
717     public int toComponentIndex(int offset) {
718         checkIndex(offset);
719 
720         for (int low = 0, high = components.size(); low <= high;) {
721             int mid = low + high >>> 1;
722             Component c = components.get(mid);
723             if (offset >= c.endOffset) {
724                 low = mid + 1;
725             } else if (offset < c.offset) {
726                 high = mid - 1;
727             } else {
728                 return mid;
729             }
730         }
731 
732         throw new Error("should not reach here");
733     }
734 
735     public int toByteIndex(int cIndex) {
736         checkComponentIndex(cIndex);
737         return components.get(cIndex).offset;
738     }
739 
740     @Override
741     public byte getByte(int index) {
742         return _getByte(index);
743     }
744 
745     @Override
746     protected byte _getByte(int index) {
747         Component c = findComponent(index);
748         return c.buf.getByte(index - c.offset);
749     }
750 
751     @Override
752     protected short _getShort(int index) {
753         Component c = findComponent(index);
754         if (index + 2 <= c.endOffset) {
755             return c.buf.getShort(index - c.offset);
756         } else if (order() == ByteOrder.BIG_ENDIAN) {
757             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
758         } else {
759             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
760         }
761     }
762 
763     @Override
764     protected int _getUnsignedMedium(int index) {
765         Component c = findComponent(index);
766         if (index + 3 <= c.endOffset) {
767             return c.buf.getUnsignedMedium(index - c.offset);
768         } else if (order() == ByteOrder.BIG_ENDIAN) {
769             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
770         } else {
771             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
772         }
773     }
774 
775     @Override
776     protected int _getInt(int index) {
777         Component c = findComponent(index);
778         if (index + 4 <= c.endOffset) {
779             return c.buf.getInt(index - c.offset);
780         } else if (order() == ByteOrder.BIG_ENDIAN) {
781             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
782         } else {
783             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
784         }
785     }
786 
787     @Override
788     protected long _getLong(int index) {
789         Component c = findComponent(index);
790         if (index + 8 <= c.endOffset) {
791             return c.buf.getLong(index - c.offset);
792         } else if (order() == ByteOrder.BIG_ENDIAN) {
793             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
794         } else {
795             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
796         }
797     }
798 
799     @Override
800     public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
801         checkDstIndex(index, length, dstIndex, dst.length);
802         if (length == 0) {
803             return this;
804         }
805 
806         int i = toComponentIndex(index);
807         while (length > 0) {
808             Component c = components.get(i);
809             ByteBuf s = c.buf;
810             int adjustment = c.offset;
811             int localLength = Math.min(length, s.capacity() - (index - adjustment));
812             s.getBytes(index - adjustment, dst, dstIndex, localLength);
813             index += localLength;
814             dstIndex += localLength;
815             length -= localLength;
816             i ++;
817         }
818         return this;
819     }
820 
821     @Override
822     public CompositeByteBuf getBytes(int index, ByteBuffer dst) {
823         int limit = dst.limit();
824         int length = dst.remaining();
825 
826         checkIndex(index, length);
827         if (length == 0) {
828             return this;
829         }
830 
831         int i = toComponentIndex(index);
832         try {
833             while (length > 0) {
834                 Component c = components.get(i);
835                 ByteBuf s = c.buf;
836                 int adjustment = c.offset;
837                 int localLength = Math.min(length, s.capacity() - (index - adjustment));
838                 dst.limit(dst.position() + localLength);
839                 s.getBytes(index - adjustment, dst);
840                 index += localLength;
841                 length -= localLength;
842                 i ++;
843             }
844         } finally {
845             dst.limit(limit);
846         }
847         return this;
848     }
849 
850     @Override
851     public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
852         checkDstIndex(index, length, dstIndex, dst.capacity());
853         if (length == 0) {
854             return this;
855         }
856 
857         int i = toComponentIndex(index);
858         while (length > 0) {
859             Component c = components.get(i);
860             ByteBuf s = c.buf;
861             int adjustment = c.offset;
862             int localLength = Math.min(length, s.capacity() - (index - adjustment));
863             s.getBytes(index - adjustment, dst, dstIndex, localLength);
864             index += localLength;
865             dstIndex += localLength;
866             length -= localLength;
867             i ++;
868         }
869         return this;
870     }
871 
872     @Override
873     public int getBytes(int index, GatheringByteChannel out, int length)
874             throws IOException {
875         int count = nioBufferCount();
876         if (count == 1) {
877             return out.write(internalNioBuffer(index, length));
878         } else {
879             long writtenBytes = out.write(nioBuffers(index, length));
880             if (writtenBytes > Integer.MAX_VALUE) {
881                 return Integer.MAX_VALUE;
882             } else {
883                 return (int) writtenBytes;
884             }
885         }
886     }
887 
888     @Override
889     public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
890         checkIndex(index, length);
891         if (length == 0) {
892             return this;
893         }
894 
895         int i = toComponentIndex(index);
896         while (length > 0) {
897             Component c = components.get(i);
898             ByteBuf s = c.buf;
899             int adjustment = c.offset;
900             int localLength = Math.min(length, s.capacity() - (index - adjustment));
901             s.getBytes(index - adjustment, out, localLength);
902             index += localLength;
903             length -= localLength;
904             i ++;
905         }
906         return this;
907     }
908 
909     @Override
910     public CompositeByteBuf setByte(int index, int value) {
911         Component c = findComponent(index);
912         c.buf.setByte(index - c.offset, value);
913         return this;
914     }
915 
916     @Override
917     protected void _setByte(int index, int value) {
918         setByte(index, value);
919     }
920 
921     @Override
922     public CompositeByteBuf setShort(int index, int value) {
923         return (CompositeByteBuf) super.setShort(index, value);
924     }
925 
926     @Override
927     protected void _setShort(int index, int value) {
928         Component c = findComponent(index);
929         if (index + 2 <= c.endOffset) {
930             c.buf.setShort(index - c.offset, value);
931         } else if (order() == ByteOrder.BIG_ENDIAN) {
932             _setByte(index, (byte) (value >>> 8));
933             _setByte(index + 1, (byte) value);
934         } else {
935             _setByte(index, (byte) value);
936             _setByte(index + 1, (byte) (value >>> 8));
937         }
938     }
939 
940     @Override
941     public CompositeByteBuf setMedium(int index, int value) {
942         return (CompositeByteBuf) super.setMedium(index, value);
943     }
944 
945     @Override
946     protected void _setMedium(int index, int value) {
947         Component c = findComponent(index);
948         if (index + 3 <= c.endOffset) {
949             c.buf.setMedium(index - c.offset, value);
950         } else if (order() == ByteOrder.BIG_ENDIAN) {
951             _setShort(index, (short) (value >> 8));
952             _setByte(index + 2, (byte) value);
953         } else {
954             _setShort(index, (short) value);
955             _setByte(index + 2, (byte) (value >>> 16));
956         }
957     }
958 
959     @Override
960     public CompositeByteBuf setInt(int index, int value) {
961         return (CompositeByteBuf) super.setInt(index, value);
962     }
963 
964     @Override
965     protected void _setInt(int index, int value) {
966         Component c = findComponent(index);
967         if (index + 4 <= c.endOffset) {
968             c.buf.setInt(index - c.offset, value);
969         } else if (order() == ByteOrder.BIG_ENDIAN) {
970             _setShort(index, (short) (value >>> 16));
971             _setShort(index + 2, (short) value);
972         } else {
973             _setShort(index, (short) value);
974             _setShort(index + 2, (short) (value >>> 16));
975         }
976     }
977 
978     @Override
979     public CompositeByteBuf setLong(int index, long value) {
980         return (CompositeByteBuf) super.setLong(index, value);
981     }
982 
983     @Override
984     protected void _setLong(int index, long value) {
985         Component c = findComponent(index);
986         if (index + 8 <= c.endOffset) {
987             c.buf.setLong(index - c.offset, value);
988         } else if (order() == ByteOrder.BIG_ENDIAN) {
989             _setInt(index, (int) (value >>> 32));
990             _setInt(index + 4, (int) value);
991         } else {
992             _setInt(index, (int) value);
993             _setInt(index + 4, (int) (value >>> 32));
994         }
995     }
996 
997     @Override
998     public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
999         checkSrcIndex(index, length, srcIndex, src.length);
1000         if (length == 0) {
1001             return this;
1002         }
1003 
1004         int i = toComponentIndex(index);
1005         while (length > 0) {
1006             Component c = components.get(i);
1007             ByteBuf s = c.buf;
1008             int adjustment = c.offset;
1009             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1010             s.setBytes(index - adjustment, src, srcIndex, localLength);
1011             index += localLength;
1012             srcIndex += localLength;
1013             length -= localLength;
1014             i ++;
1015         }
1016         return this;
1017     }
1018 
1019     @Override
1020     public CompositeByteBuf setBytes(int index, ByteBuffer src) {
1021         int limit = src.limit();
1022         int length = src.remaining();
1023 
1024         checkIndex(index, length);
1025         if (length == 0) {
1026             return this;
1027         }
1028 
1029         int i = toComponentIndex(index);
1030         try {
1031             while (length > 0) {
1032                 Component c = components.get(i);
1033                 ByteBuf s = c.buf;
1034                 int adjustment = c.offset;
1035                 int localLength = Math.min(length, s.capacity() - (index - adjustment));
1036                 src.limit(src.position() + localLength);
1037                 s.setBytes(index - adjustment, src);
1038                 index += localLength;
1039                 length -= localLength;
1040                 i ++;
1041             }
1042         } finally {
1043             src.limit(limit);
1044         }
1045         return this;
1046     }
1047 
1048     @Override
1049     public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
1050         checkSrcIndex(index, length, srcIndex, src.capacity());
1051         if (length == 0) {
1052             return this;
1053         }
1054 
1055         int i = toComponentIndex(index);
1056         while (length > 0) {
1057             Component c = components.get(i);
1058             ByteBuf s = c.buf;
1059             int adjustment = c.offset;
1060             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1061             s.setBytes(index - adjustment, src, srcIndex, localLength);
1062             index += localLength;
1063             srcIndex += localLength;
1064             length -= localLength;
1065             i ++;
1066         }
1067         return this;
1068     }
1069 
1070     @Override
1071     public int setBytes(int index, InputStream in, int length) throws IOException {
1072         checkIndex(index, length);
1073         if (length == 0) {
1074             return in.read(EmptyArrays.EMPTY_BYTES);
1075         }
1076 
1077         int i = toComponentIndex(index);
1078         int readBytes = 0;
1079 
1080         do {
1081             Component c = components.get(i);
1082             ByteBuf s = c.buf;
1083             int adjustment = c.offset;
1084             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1085             int localReadBytes = s.setBytes(index - adjustment, in, localLength);
1086             if (localReadBytes < 0) {
1087                 if (readBytes == 0) {
1088                     return -1;
1089                 } else {
1090                     break;
1091                 }
1092             }
1093 
1094             if (localReadBytes == localLength) {
1095                 index += localLength;
1096                 length -= localLength;
1097                 readBytes += localLength;
1098                 i ++;
1099             } else {
1100                 index += localReadBytes;
1101                 length -= localReadBytes;
1102                 readBytes += localReadBytes;
1103             }
1104         } while (length > 0);
1105 
1106         return readBytes;
1107     }
1108 
1109     @Override
1110     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
1111         checkIndex(index, length);
1112         if (length == 0) {
1113             return in.read(EMPTY_NIO_BUFFER);
1114         }
1115 
1116         int i = toComponentIndex(index);
1117         int readBytes = 0;
1118         do {
1119             Component c = components.get(i);
1120             ByteBuf s = c.buf;
1121             int adjustment = c.offset;
1122             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1123             int localReadBytes = s.setBytes(index - adjustment, in, localLength);
1124 
1125             if (localReadBytes == 0) {
1126                 break;
1127             }
1128 
1129             if (localReadBytes < 0) {
1130                 if (readBytes == 0) {
1131                     return -1;
1132                 } else {
1133                     break;
1134                 }
1135             }
1136 
1137             if (localReadBytes == localLength) {
1138                 index += localLength;
1139                 length -= localLength;
1140                 readBytes += localLength;
1141                 i ++;
1142             } else {
1143                 index += localReadBytes;
1144                 length -= localReadBytes;
1145                 readBytes += localReadBytes;
1146             }
1147         } while (length > 0);
1148 
1149         return readBytes;
1150     }
1151 
1152     @Override
1153     public ByteBuf copy(int index, int length) {
1154         checkIndex(index, length);
1155         ByteBuf dst = allocBuffer(length);
1156         if (length != 0) {
1157             copyTo(index, length, toComponentIndex(index), dst);
1158         }
1159         return dst;
1160     }
1161 
1162     private void copyTo(int index, int length, int componentId, ByteBuf dst) {
1163         int dstIndex = 0;
1164         int i = componentId;
1165 
1166         while (length > 0) {
1167             Component c = components.get(i);
1168             ByteBuf s = c.buf;
1169             int adjustment = c.offset;
1170             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1171             s.getBytes(index - adjustment, dst, dstIndex, localLength);
1172             index += localLength;
1173             dstIndex += localLength;
1174             length -= localLength;
1175             i ++;
1176         }
1177 
1178         dst.writerIndex(dst.capacity());
1179     }
1180 
1181     /**
1182      * Return the {@link ByteBuf} on the specified index
1183      *
1184      * @param cIndex the index for which the {@link ByteBuf} should be returned
1185      * @return buf the {@link ByteBuf} on the specified index
1186      */
1187     public ByteBuf component(int cIndex) {
1188         return internalComponent(cIndex).duplicate();
1189     }
1190 
1191     /**
1192      * Return the {@link ByteBuf} on the specified index
1193      *
1194      * @param offset the offset for which the {@link ByteBuf} should be returned
1195      * @return the {@link ByteBuf} on the specified index
1196      */
1197     public ByteBuf componentAtOffset(int offset) {
1198         return internalComponentAtOffset(offset).duplicate();
1199     }
1200 
1201     /**
1202      * Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
1203      * buffer will lead to an undefined behavior of this buffer.
1204      *
1205      * @param cIndex the index for which the {@link ByteBuf} should be returned
1206      */
1207     public ByteBuf internalComponent(int cIndex) {
1208         checkComponentIndex(cIndex);
1209         return components.get(cIndex).buf;
1210     }
1211 
1212     /**
1213      * Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
1214      * buffer will lead to an undefined behavior of this buffer.
1215      *
1216      * @param offset the offset for which the {@link ByteBuf} should be returned
1217      */
1218     public ByteBuf internalComponentAtOffset(int offset) {
1219         return findComponent(offset).buf;
1220     }
1221 
1222     private Component findComponent(int offset) {
1223         checkIndex(offset);
1224 
1225         for (int low = 0, high = components.size(); low <= high;) {
1226             int mid = low + high >>> 1;
1227             Component c = components.get(mid);
1228             if (offset >= c.endOffset) {
1229                 low = mid + 1;
1230             } else if (offset < c.offset) {
1231                 high = mid - 1;
1232             } else {
1233                 assert c.length != 0;
1234                 return c;
1235             }
1236         }
1237 
1238         throw new Error("should not reach here");
1239     }
1240 
1241     @Override
1242     public int nioBufferCount() {
1243         switch (components.size()) {
1244         case 0:
1245             return 1;
1246         case 1:
1247             return components.get(0).buf.nioBufferCount();
1248         default:
1249             int count = 0;
1250             int componentsCount = components.size();
1251             for (int i = 0; i < componentsCount; i++) {
1252                 Component c = components.get(i);
1253                 count += c.buf.nioBufferCount();
1254             }
1255             return count;
1256         }
1257     }
1258 
1259     @Override
1260     public ByteBuffer internalNioBuffer(int index, int length) {
1261         switch (components.size()) {
1262         case 0:
1263             return EMPTY_NIO_BUFFER;
1264         case 1:
1265             return components.get(0).buf.internalNioBuffer(index, length);
1266         default:
1267             throw new UnsupportedOperationException();
1268         }
1269     }
1270 
1271     @Override
1272     public ByteBuffer nioBuffer(int index, int length) {
1273         checkIndex(index, length);
1274 
1275         switch (components.size()) {
1276         case 0:
1277             return EMPTY_NIO_BUFFER;
1278         case 1:
1279             ByteBuf buf = components.get(0).buf;
1280             if (buf.nioBufferCount() == 1) {
1281                 return components.get(0).buf.nioBuffer(index, length);
1282             }
1283         }
1284 
1285         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
1286         ByteBuffer[] buffers = nioBuffers(index, length);
1287 
1288         for (ByteBuffer buf: buffers) {
1289             merged.put(buf);
1290         }
1291 
1292         merged.flip();
1293         return merged;
1294     }
1295 
1296     @Override
1297     public ByteBuffer[] nioBuffers(int index, int length) {
1298         checkIndex(index, length);
1299         if (length == 0) {
1300             return new ByteBuffer[] { EMPTY_NIO_BUFFER };
1301         }
1302 
1303         List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.size());
1304         int i = toComponentIndex(index);
1305         while (length > 0) {
1306             Component c = components.get(i);
1307             ByteBuf s = c.buf;
1308             int adjustment = c.offset;
1309             int localLength = Math.min(length, s.capacity() - (index - adjustment));
1310             switch (s.nioBufferCount()) {
1311                 case 0:
1312                     throw new UnsupportedOperationException();
1313                 case 1:
1314                     buffers.add(s.nioBuffer(index - adjustment, localLength));
1315                     break;
1316                 default:
1317                     Collections.addAll(buffers, s.nioBuffers(index - adjustment, localLength));
1318             }
1319 
1320             index += localLength;
1321             length -= localLength;
1322             i ++;
1323         }
1324 
1325         return buffers.toArray(new ByteBuffer[buffers.size()]);
1326     }
1327 
1328     /**
1329      * Consolidate the composed {@link ByteBuf}s
1330      */
1331     public CompositeByteBuf consolidate() {
1332         ensureAccessible();
1333         final int numComponents = numComponents();
1334         if (numComponents <= 1) {
1335             return this;
1336         }
1337 
1338         final Component last = components.get(numComponents - 1);
1339         final int capacity = last.endOffset;
1340         final ByteBuf consolidated = allocBuffer(capacity);
1341 
1342         for (int i = 0; i < numComponents; i ++) {
1343             Component c = components.get(i);
1344             ByteBuf b = c.buf;
1345             consolidated.writeBytes(b);
1346             c.freeIfNecessary();
1347         }
1348 
1349         components.clear();
1350         components.add(new Component(consolidated));
1351         updateComponentOffsets(0);
1352         return this;
1353     }
1354 
1355     /**
1356      * Consolidate the composed {@link ByteBuf}s
1357      *
1358      * @param cIndex the index on which to start to compose
1359      * @param numComponents the number of components to compose
1360      */
1361     public CompositeByteBuf consolidate(int cIndex, int numComponents) {
1362         checkComponentIndex(cIndex, numComponents);
1363         if (numComponents <= 1) {
1364             return this;
1365         }
1366 
1367         final int endCIndex = cIndex + numComponents;
1368         final Component last = components.get(endCIndex - 1);
1369         final int capacity = last.endOffset - components.get(cIndex).offset;
1370         final ByteBuf consolidated = allocBuffer(capacity);
1371 
1372         for (int i = cIndex; i < endCIndex; i ++) {
1373             Component c = components.get(i);
1374             ByteBuf b = c.buf;
1375             consolidated.writeBytes(b);
1376             c.freeIfNecessary();
1377         }
1378 
1379         components.subList(cIndex + 1, endCIndex).clear();
1380         components.set(cIndex, new Component(consolidated));
1381         updateComponentOffsets(cIndex);
1382         return this;
1383     }
1384 
1385     /**
1386      * Discard all {@link ByteBuf}s which are read.
1387      */
1388     public CompositeByteBuf discardReadComponents() {
1389         ensureAccessible();
1390         final int readerIndex = readerIndex();
1391         if (readerIndex == 0) {
1392             return this;
1393         }
1394 
1395         // Discard everything if (readerIndex = writerIndex = capacity).
1396         int writerIndex = writerIndex();
1397         if (readerIndex == writerIndex && writerIndex == capacity()) {
1398             for (Component c: components) {
1399                 c.freeIfNecessary();
1400             }
1401             components.clear();
1402             setIndex(0, 0);
1403             adjustMarkers(readerIndex);
1404             return this;
1405         }
1406 
1407         // Remove read components.
1408         int firstComponentId = toComponentIndex(readerIndex);
1409         for (int i = 0; i < firstComponentId; i ++) {
1410             components.get(i).freeIfNecessary();
1411         }
1412         components.subList(0, firstComponentId).clear();
1413 
1414         // Update indexes and markers.
1415         Component first = components.get(0);
1416         int offset = first.offset;
1417         updateComponentOffsets(0);
1418         setIndex(readerIndex - offset, writerIndex - offset);
1419         adjustMarkers(offset);
1420         return this;
1421     }
1422 
1423     @Override
1424     public CompositeByteBuf discardReadBytes() {
1425         ensureAccessible();
1426         final int readerIndex = readerIndex();
1427         if (readerIndex == 0) {
1428             return this;
1429         }
1430 
1431         // Discard everything if (readerIndex = writerIndex = capacity).
1432         int writerIndex = writerIndex();
1433         if (readerIndex == writerIndex && writerIndex == capacity()) {
1434             for (Component c: components) {
1435                 c.freeIfNecessary();
1436             }
1437             components.clear();
1438             setIndex(0, 0);
1439             adjustMarkers(readerIndex);
1440             return this;
1441         }
1442 
1443         // Remove read components.
1444         int firstComponentId = toComponentIndex(readerIndex);
1445         for (int i = 0; i < firstComponentId; i ++) {
1446             components.get(i).freeIfNecessary();
1447         }
1448         components.subList(0, firstComponentId).clear();
1449 
1450         // Remove or replace the first readable component with a new slice.
1451         Component c = components.get(0);
1452         int adjustment = readerIndex - c.offset;
1453         if (adjustment == c.length) {
1454             // new slice would be empty, so remove instead
1455             components.remove(0);
1456         } else {
1457             Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment));
1458             components.set(0, newC);
1459         }
1460 
1461         // Update indexes and markers.
1462         updateComponentOffsets(0);
1463         setIndex(0, writerIndex - readerIndex);
1464         adjustMarkers(readerIndex);
1465         return this;
1466     }
1467 
1468     private ByteBuf allocBuffer(int capacity) {
1469         return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
1470     }
1471 
1472     @Override
1473     public String toString() {
1474         String result = super.toString();
1475         result = result.substring(0, result.length() - 1);
1476         return result + ", components=" + components.size() + ')';
1477     }
1478 
1479     private static final class Component {
1480         final ByteBuf buf;
1481         final int length;
1482         int offset;
1483         int endOffset;
1484 
1485         Component(ByteBuf buf) {
1486             this.buf = buf;
1487             length = buf.readableBytes();
1488         }
1489 
1490         void freeIfNecessary() {
1491             buf.release(); // We should not get a NPE here. If so, it must be a bug.
1492         }
1493     }
1494 
1495     @Override
1496     public CompositeByteBuf readerIndex(int readerIndex) {
1497         return (CompositeByteBuf) super.readerIndex(readerIndex);
1498     }
1499 
1500     @Override
1501     public CompositeByteBuf writerIndex(int writerIndex) {
1502         return (CompositeByteBuf) super.writerIndex(writerIndex);
1503     }
1504 
1505     @Override
1506     public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
1507         return (CompositeByteBuf) super.setIndex(readerIndex, writerIndex);
1508     }
1509 
1510     @Override
1511     public CompositeByteBuf clear() {
1512         return (CompositeByteBuf) super.clear();
1513     }
1514 
1515     @Override
1516     public CompositeByteBuf markReaderIndex() {
1517         return (CompositeByteBuf) super.markReaderIndex();
1518     }
1519 
1520     @Override
1521     public CompositeByteBuf resetReaderIndex() {
1522         return (CompositeByteBuf) super.resetReaderIndex();
1523     }
1524 
1525     @Override
1526     public CompositeByteBuf markWriterIndex() {
1527         return (CompositeByteBuf) super.markWriterIndex();
1528     }
1529 
1530     @Override
1531     public CompositeByteBuf resetWriterIndex() {
1532         return (CompositeByteBuf) super.resetWriterIndex();
1533     }
1534 
1535     @Override
1536     public CompositeByteBuf ensureWritable(int minWritableBytes) {
1537         return (CompositeByteBuf) super.ensureWritable(minWritableBytes);
1538     }
1539 
1540     @Override
1541     public CompositeByteBuf getBytes(int index, ByteBuf dst) {
1542         return (CompositeByteBuf) super.getBytes(index, dst);
1543     }
1544 
1545     @Override
1546     public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
1547         return (CompositeByteBuf) super.getBytes(index, dst, length);
1548     }
1549 
1550     @Override
1551     public CompositeByteBuf getBytes(int index, byte[] dst) {
1552         return (CompositeByteBuf) super.getBytes(index, dst);
1553     }
1554 
1555     @Override
1556     public CompositeByteBuf setBoolean(int index, boolean value) {
1557         return (CompositeByteBuf) super.setBoolean(index, value);
1558     }
1559 
1560     @Override
1561     public CompositeByteBuf setChar(int index, int value) {
1562         return (CompositeByteBuf) super.setChar(index, value);
1563     }
1564 
1565     @Override
1566     public CompositeByteBuf setFloat(int index, float value) {
1567         return (CompositeByteBuf) super.setFloat(index, value);
1568     }
1569 
1570     @Override
1571     public CompositeByteBuf setDouble(int index, double value) {
1572         return (CompositeByteBuf) super.setDouble(index, value);
1573     }
1574 
1575     @Override
1576     public CompositeByteBuf setBytes(int index, ByteBuf src) {
1577         return (CompositeByteBuf) super.setBytes(index, src);
1578     }
1579 
1580     @Override
1581     public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
1582         return (CompositeByteBuf) super.setBytes(index, src, length);
1583     }
1584 
1585     @Override
1586     public CompositeByteBuf setBytes(int index, byte[] src) {
1587         return (CompositeByteBuf) super.setBytes(index, src);
1588     }
1589 
1590     @Override
1591     public CompositeByteBuf setZero(int index, int length) {
1592         return (CompositeByteBuf) super.setZero(index, length);
1593     }
1594 
1595     @Override
1596     public CompositeByteBuf readBytes(ByteBuf dst) {
1597         return (CompositeByteBuf) super.readBytes(dst);
1598     }
1599 
1600     @Override
1601     public CompositeByteBuf readBytes(ByteBuf dst, int length) {
1602         return (CompositeByteBuf) super.readBytes(dst, length);
1603     }
1604 
1605     @Override
1606     public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
1607         return (CompositeByteBuf) super.readBytes(dst, dstIndex, length);
1608     }
1609 
1610     @Override
1611     public CompositeByteBuf readBytes(byte[] dst) {
1612         return (CompositeByteBuf) super.readBytes(dst);
1613     }
1614 
1615     @Override
1616     public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
1617         return (CompositeByteBuf) super.readBytes(dst, dstIndex, length);
1618     }
1619 
1620     @Override
1621     public CompositeByteBuf readBytes(ByteBuffer dst) {
1622         return (CompositeByteBuf) super.readBytes(dst);
1623     }
1624 
1625     @Override
1626     public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
1627         return (CompositeByteBuf) super.readBytes(out, length);
1628     }
1629 
1630     @Override
1631     public CompositeByteBuf skipBytes(int length) {
1632         return (CompositeByteBuf) super.skipBytes(length);
1633     }
1634 
1635     @Override
1636     public CompositeByteBuf writeBoolean(boolean value) {
1637         return (CompositeByteBuf) super.writeBoolean(value);
1638     }
1639 
1640     @Override
1641     public CompositeByteBuf writeByte(int value) {
1642         return (CompositeByteBuf) super.writeByte(value);
1643     }
1644 
1645     @Override
1646     public CompositeByteBuf writeShort(int value) {
1647         return (CompositeByteBuf) super.writeShort(value);
1648     }
1649 
1650     @Override
1651     public CompositeByteBuf writeMedium(int value) {
1652         return (CompositeByteBuf) super.writeMedium(value);
1653     }
1654 
1655     @Override
1656     public CompositeByteBuf writeInt(int value) {
1657         return (CompositeByteBuf) super.writeInt(value);
1658     }
1659 
1660     @Override
1661     public CompositeByteBuf writeLong(long value) {
1662         return (CompositeByteBuf) super.writeLong(value);
1663     }
1664 
1665     @Override
1666     public CompositeByteBuf writeChar(int value) {
1667         return (CompositeByteBuf) super.writeChar(value);
1668     }
1669 
1670     @Override
1671     public CompositeByteBuf writeFloat(float value) {
1672         return (CompositeByteBuf) super.writeFloat(value);
1673     }
1674 
1675     @Override
1676     public CompositeByteBuf writeDouble(double value) {
1677         return (CompositeByteBuf) super.writeDouble(value);
1678     }
1679 
1680     @Override
1681     public CompositeByteBuf writeBytes(ByteBuf src) {
1682         return (CompositeByteBuf) super.writeBytes(src);
1683     }
1684 
1685     @Override
1686     public CompositeByteBuf writeBytes(ByteBuf src, int length) {
1687         return (CompositeByteBuf) super.writeBytes(src, length);
1688     }
1689 
1690     @Override
1691     public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
1692         return (CompositeByteBuf) super.writeBytes(src, srcIndex, length);
1693     }
1694 
1695     @Override
1696     public CompositeByteBuf writeBytes(byte[] src) {
1697         return (CompositeByteBuf) super.writeBytes(src);
1698     }
1699 
1700     @Override
1701     public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
1702         return (CompositeByteBuf) super.writeBytes(src, srcIndex, length);
1703     }
1704 
1705     @Override
1706     public CompositeByteBuf writeBytes(ByteBuffer src) {
1707         return (CompositeByteBuf) super.writeBytes(src);
1708     }
1709 
1710     @Override
1711     public CompositeByteBuf writeZero(int length) {
1712         return (CompositeByteBuf) super.writeZero(length);
1713     }
1714 
1715     @Override
1716     public CompositeByteBuf retain(int increment) {
1717         return (CompositeByteBuf) super.retain(increment);
1718     }
1719 
1720     @Override
1721     public CompositeByteBuf retain() {
1722         return (CompositeByteBuf) super.retain();
1723     }
1724 
1725     @Override
1726     public ByteBuffer[] nioBuffers() {
1727         return nioBuffers(readerIndex(), readableBytes());
1728     }
1729 
1730     @Override
1731     public CompositeByteBuf discardSomeReadBytes() {
1732         return discardReadComponents();
1733     }
1734 
1735     @Override
1736     protected void deallocate() {
1737         if (freed) {
1738             return;
1739         }
1740 
1741         freed = true;
1742         int size = components.size();
1743         // We're not using foreach to avoid creating an iterator.
1744         // see https://github.com/netty/netty/issues/2642
1745         for (int i = 0; i < size; i++) {
1746             components.get(i).freeIfNecessary();
1747         }
1748     }
1749 
1750     @Override
1751     public ByteBuf unwrap() {
1752         return null;
1753     }
1754 
1755     private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
1756         private final int size = components.size();
1757         private int index;
1758 
1759         @Override
1760         public boolean hasNext() {
1761             return size > index;
1762         }
1763 
1764         @Override
1765         public ByteBuf next() {
1766             if (size != components.size()) {
1767                 throw new ConcurrentModificationException();
1768             }
1769             if (!hasNext()) {
1770                 throw new NoSuchElementException();
1771             }
1772             try {
1773                 return components.get(index++).buf;
1774             } catch (IndexOutOfBoundsException e) {
1775                 throw new ConcurrentModificationException();
1776             }
1777         }
1778 
1779         @Override
1780         public void remove() {
1781             throw new UnsupportedOperationException("Read-Only");
1782         }
1783     }
1784 }