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