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