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.ByteProcessor;
19 import io.netty.util.IllegalReferenceCountException;
20 import io.netty.util.ReferenceCountUtil;
21 import io.netty.util.internal.EmptyArrays;
22 import io.netty.util.internal.ObjectUtil;
23 import io.netty.util.internal.RecyclableArrayList;
24
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.nio.ByteBuffer;
29 import java.nio.ByteOrder;
30 import java.nio.channels.FileChannel;
31 import java.nio.channels.GatheringByteChannel;
32 import java.nio.channels.ScatteringByteChannel;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.ConcurrentModificationException;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.NoSuchElementException;
41
42 import static io.netty.util.internal.ObjectUtil.checkNotNull;
43
44 /**
45  * A virtual buffer which shows multiple buffers as a single merged buffer.  It is recommended to use
46  * {@link ByteBufAllocator#compositeBuffer()} or {@link Unpooled#wrappedBuffer(ByteBuf...)} instead of calling the
47  * constructor explicitly.
48  */

49 public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf> {
50
51     private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
52     private static final Iterator<ByteBuf> EMPTY_ITERATOR = Collections.<ByteBuf>emptyList().iterator();
53
54     private final ByteBufAllocator alloc;
55     private final boolean direct;
56     private final int maxNumComponents;
57
58     private int componentCount;
59     private Component[] components; // resized when needed
60
61     private boolean freed;
62
63     private CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, int initSize) {
64         super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
65
66         this.alloc = ObjectUtil.checkNotNull(alloc, "alloc");
67         if (maxNumComponents < 1) {
68             throw new IllegalArgumentException(
69                     "maxNumComponents: " + maxNumComponents + " (expected: >= 1)");
70         }
71
72         this.direct = direct;
73         this.maxNumComponents = maxNumComponents;
74         components = newCompArray(initSize, maxNumComponents);
75     }
76
77     public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) {
78         this(alloc, direct, maxNumComponents, 0);
79     }
80
81     public CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents, ByteBuf... buffers) {
82         this(alloc, direct, maxNumComponents, buffers, 0);
83     }
84
85     CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents,
86             ByteBuf[] buffers, int offset) {
87         this(alloc, direct, maxNumComponents, buffers.length - offset);
88
89         addComponents0(false, 0, buffers, offset);
90         consolidateIfNeeded();
91         setIndex0(0, capacity());
92     }
93
94     public CompositeByteBuf(
95             ByteBufAllocator alloc, boolean direct, int maxNumComponents, Iterable<ByteBuf> buffers) {
96         this(alloc, direct, maxNumComponents,
97                 buffers instanceof Collection ? ((Collection<ByteBuf>) buffers).size() : 0);
98
99         addComponents(false, 0, buffers);
100         setIndex(0, capacity());
101     }
102
103     // support passing arrays of other types instead of having to copy to a ByteBuf[] first
104     interface ByteWrapper<T> {
105         ByteBuf wrap(T bytes);
106         boolean isEmpty(T bytes);
107     }
108
109     static final ByteWrapper<byte[]> BYTE_ARRAY_WRAPPER = new ByteWrapper<byte[]>() {
110         @Override
111         public ByteBuf wrap(byte[] bytes) {
112             return Unpooled.wrappedBuffer(bytes);
113         }
114         @Override
115         public boolean isEmpty(byte[] bytes) {
116             return bytes.length == 0;
117         }
118     };
119
120     static final ByteWrapper<ByteBuffer> BYTE_BUFFER_WRAPPER = new ByteWrapper<ByteBuffer>() {
121         @Override
122         public ByteBuf wrap(ByteBuffer bytes) {
123             return Unpooled.wrappedBuffer(bytes);
124         }
125         @Override
126         public boolean isEmpty(ByteBuffer bytes) {
127             return !bytes.hasRemaining();
128         }
129     };
130
131     <T> CompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents,
132             ByteWrapper<T> wrapper, T[] buffers, int offset) {
133         this(alloc, direct, maxNumComponents, buffers.length - offset);
134
135         addComponents0(false, 0, wrapper, buffers, offset);
136         consolidateIfNeeded();
137         setIndex(0, capacity());
138     }
139
140     private static Component[] newCompArray(int initComponents, int maxNumComponents) {
141         int capacityGuess = Math.min(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS, maxNumComponents);
142         return new Component[Math.max(initComponents, capacityGuess)];
143     }
144
145     // Special constructor used by WrappedCompositeByteBuf
146     CompositeByteBuf(ByteBufAllocator alloc) {
147         super(Integer.MAX_VALUE);
148         this.alloc = alloc;
149         direct = false;
150         maxNumComponents = 0;
151         components = null;
152     }
153
154     /**
155      * Add the given {@link ByteBuf}.
156      * <p>
157      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
158      * If you need to have it increased use {@link #addComponent(boolean, ByteBuf)}.
159      * <p>
160      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
161      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
162      * {@link CompositeByteBuf}.
163      */

164     public CompositeByteBuf addComponent(ByteBuf buffer) {
165         return addComponent(false, buffer);
166     }
167
168     /**
169      * Add the given {@link ByteBuf}s.
170      * <p>
171      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
172      * If you need to have it increased use {@link #addComponents(boolean, ByteBuf[])}.
173      * <p>
174      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
175      * {@link CompositeByteBuf}.
176      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
177      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
178      */

179     public CompositeByteBuf addComponents(ByteBuf... buffers) {
180         return addComponents(false, buffers);
181     }
182
183     /**
184      * Add the given {@link ByteBuf}s.
185      * <p>
186      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
187      * If you need to have it increased use {@link #addComponents(boolean, Iterable)}.
188      * <p>
189      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
190      * {@link CompositeByteBuf}.
191      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
192      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
193      */

194     public CompositeByteBuf addComponents(Iterable<ByteBuf> buffers) {
195         return addComponents(false, buffers);
196     }
197
198     /**
199      * Add the given {@link ByteBuf} on the specific index.
200      * <p>
201      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
202      * If you need to have it increased use {@link #addComponent(booleanint, ByteBuf)}.
203      * <p>
204      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
205      * @param cIndex the index on which the {@link ByteBuf} will be added.
206      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
207      * {@link CompositeByteBuf}.
208      */

209     public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
210         return addComponent(false, cIndex, buffer);
211     }
212
213     /**
214      * Add the given {@link ByteBuf} and increase the {@code writerIndex} if {@code increaseWriterIndex} is
215      * {@code true}.
216      *
217      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
218      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
219      * {@link CompositeByteBuf}.
220      */

221     public CompositeByteBuf addComponent(boolean increaseWriterIndex, ByteBuf buffer) {
222         return addComponent(increaseWriterIndex, componentCount, buffer);
223     }
224
225     /**
226      * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is
227      * {@code true}.
228      *
229      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
230      * {@link CompositeByteBuf}.
231      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
232      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
233      */

234     public CompositeByteBuf addComponents(boolean increaseWriterIndex, ByteBuf... buffers) {
235         checkNotNull(buffers, "buffers");
236         addComponents0(increaseWriterIndex, componentCount, buffers, 0);
237         consolidateIfNeeded();
238         return this;
239     }
240
241     /**
242      * Add the given {@link ByteBuf}s and increase the {@code writerIndex} if {@code increaseWriterIndex} is
243      * {@code true}.
244      *
245      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
246      * {@link CompositeByteBuf}.
247      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
248      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
249      */

250     public CompositeByteBuf addComponents(boolean increaseWriterIndex, Iterable<ByteBuf> buffers) {
251         return addComponents(increaseWriterIndex, componentCount, buffers);
252     }
253
254     /**
255      * Add the given {@link ByteBuf} on the specific index and increase the {@code writerIndex}
256      * if {@code increaseWriterIndex} is {@code true}.
257      *
258      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
259      * @param cIndex the index on which the {@link ByteBuf} will be added.
260      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
261      * {@link CompositeByteBuf}.
262      */

263     public CompositeByteBuf addComponent(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
264         checkNotNull(buffer, "buffer");
265         addComponent0(increaseWriterIndex, cIndex, buffer);
266         consolidateIfNeeded();
267         return this;
268     }
269
270     private static void checkForOverflow(int capacity, int readableBytes) {
271         if (capacity + readableBytes < 0) {
272             throw new IllegalArgumentException("Can't increase by " + readableBytes + " as capacity(" + capacity + ")" +
273                     " would overflow " + Integer.MAX_VALUE);
274         }
275     }
276
277     /**
278      * Precondition is that {@code buffer != null}.
279      */

280     private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
281         assert buffer != null;
282         boolean wasAdded = false;
283         try {
284             checkComponentIndex(cIndex);
285
286             // No need to consolidate - just add a component to the list.
287             Component c = newComponent(ensureAccessible(buffer), 0);
288             int readableBytes = c.length();
289
290             // Check if we would overflow.
291             // See https://github.com/netty/netty/issues/10194
292             checkForOverflow(capacity(), readableBytes);
293
294             addComp(cIndex, c);
295             wasAdded = true;
296             if (readableBytes > 0 && cIndex < componentCount - 1) {
297                 updateComponentOffsets(cIndex);
298             } else if (cIndex > 0) {
299                 c.reposition(components[cIndex - 1].endOffset);
300             }
301             if (increaseWriterIndex) {
302                 writerIndex += readableBytes;
303             }
304             return cIndex;
305         } finally {
306             if (!wasAdded) {
307                 buffer.release();
308             }
309         }
310     }
311
312     private static ByteBuf ensureAccessible(final ByteBuf buf) {
313         if (checkAccessible && !buf.isAccessible()) {
314             throw new IllegalReferenceCountException(0);
315         }
316         return buf;
317     }
318
319     @SuppressWarnings("deprecation")
320     private Component newComponent(final ByteBuf buf, final int offset) {
321         final int srcIndex = buf.readerIndex();
322         final int len = buf.readableBytes();
323
324         // unpeel any intermediate outer layers (UnreleasableByteBuf, LeakAwareByteBufs, SwappedByteBuf)
325         ByteBuf unwrapped = buf;
326         int unwrappedIndex = srcIndex;
327         while (unwrapped instanceof WrappedByteBuf || unwrapped instanceof SwappedByteBuf) {
328             unwrapped = unwrapped.unwrap();
329         }
330
331         // unwrap if already sliced
332         if (unwrapped instanceof AbstractUnpooledSlicedByteBuf) {
333             unwrappedIndex += ((AbstractUnpooledSlicedByteBuf) unwrapped).idx(0);
334             unwrapped = unwrapped.unwrap();
335         } else if (unwrapped instanceof PooledSlicedByteBuf) {
336             unwrappedIndex += ((PooledSlicedByteBuf) unwrapped).adjustment;
337             unwrapped = unwrapped.unwrap();
338         } else if (unwrapped instanceof DuplicatedByteBuf || unwrapped instanceof PooledDuplicatedByteBuf) {
339             unwrapped = unwrapped.unwrap();
340         }
341
342         // We don't need to slice later to expose the internal component if the readable range
343         // is already the entire buffer
344         final ByteBuf slice = buf.capacity() == len ? buf : null;
345
346         return new Component(buf.order(ByteOrder.BIG_ENDIAN), srcIndex,
347                 unwrapped.order(ByteOrder.BIG_ENDIAN), unwrappedIndex, offset, len, slice);
348     }
349
350     /**
351      * Add the given {@link ByteBuf}s on the specific index
352      * <p>
353      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
354      * If you need to have it increased you need to handle it by your own.
355      * <p>
356      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
357      * {@link CompositeByteBuf}.
358      * @param cIndex the index on which the {@link ByteBuf} will be added. {@link ByteBuf#release()} ownership of all
359      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transferred to this
360      * {@link CompositeByteBuf}.
361      * @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
362      * ownership of all {@link ByteBuf} objects is transferred to this {@link CompositeByteBuf}.
363      */

364     public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) {
365         checkNotNull(buffers, "buffers");
366         addComponents0(false, cIndex, buffers, 0);
367         consolidateIfNeeded();
368         return this;
369     }
370
371     private CompositeByteBuf addComponents0(boolean increaseWriterIndex,
372             final int cIndex, ByteBuf[] buffers, int arrOffset) {
373         final int len = buffers.length, count = len - arrOffset;
374
375         int readableBytes = 0;
376         int capacity = capacity();
377         for (int i = 0; i < buffers.length; i++) {
378             readableBytes += buffers[i].readableBytes();
379
380             // Check if we would overflow.
381             // See https://github.com/netty/netty/issues/10194
382             checkForOverflow(capacity, readableBytes);
383         }
384         // only set ci after we've shifted so that finally block logic is always correct
385         int ci = Integer.MAX_VALUE;
386         try {
387             checkComponentIndex(cIndex);
388             shiftComps(cIndex, count); // will increase componentCount
389             int nextOffset = cIndex > 0 ? components[cIndex - 1].endOffset : 0;
390             for (ci = cIndex; arrOffset < len; arrOffset++, ci++) {
391                 ByteBuf b = buffers[arrOffset];
392                 if (b == null) {
393                     break;
394                 }
395                 Component c = newComponent(ensureAccessible(b), nextOffset);
396                 components[ci] = c;
397                 nextOffset = c.endOffset;
398             }
399             return this;
400         } finally {
401             // ci is now the index following the last successfully added component
402             if (ci < componentCount) {
403                 if (ci < cIndex + count) {
404                     // we bailed early
405                     removeCompRange(ci, cIndex + count);
406                     for (; arrOffset < len; ++arrOffset) {
407                         ReferenceCountUtil.safeRelease(buffers[arrOffset]);
408                     }
409                 }
410                 updateComponentOffsets(ci); // only need to do this here for components after the added ones
411             }
412             if (increaseWriterIndex && ci > cIndex && ci <= componentCount) {
413                 writerIndex += components[ci - 1].endOffset - components[cIndex].offset;
414             }
415         }
416     }
417
418     private <T> int addComponents0(boolean increaseWriterIndex, int cIndex,
419             ByteWrapper<T> wrapper, T[] buffers, int offset) {
420         checkComponentIndex(cIndex);
421
422         // No need for consolidation
423         for (int i = offset, len = buffers.length; i < len; i++) {
424             T b = buffers[i];
425             if (b == null) {
426                 break;
427             }
428             if (!wrapper.isEmpty(b)) {
429                 cIndex = addComponent0(increaseWriterIndex, cIndex, wrapper.wrap(b)) + 1;
430                 int size = componentCount;
431                 if (cIndex > size) {
432                     cIndex = size;
433                 }
434             }
435         }
436         return cIndex;
437     }
438
439     /**
440      * Add the given {@link ByteBuf}s on the specific index
441      *
442      * Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
443      * If you need to have it increased you need to handle it by your own.
444      * <p>
445      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transferred to this
446      * {@link CompositeByteBuf}.
447      * @param cIndex the index on which the {@link ByteBuf} will be added.
448      * @param buffers the {@link ByteBuf}s to add.  {@link ByteBuf#release()} ownership of all
449      * {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transferred to this
450      * {@link CompositeByteBuf}.
451      */

452     public CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers) {
453         return addComponents(false, cIndex, buffers);
454     }
455
456     /**
457      * Add the given {@link ByteBuf} and increase the {@code writerIndex} if {@code increaseWriterIndex} is
458      * {@code true}. If the provided buffer is a {@link CompositeByteBuf} itself, a "shallow copy" of its
459      * readable components will be performed. Thus the actual number of new components added may vary
460      * and in particular will be zero if the provided buffer is not readable.
461      * <p>
462      * {@link ByteBuf#release()} ownership of {@code buffer} is transferred to this {@link CompositeByteBuf}.
463      * @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transferred to this
464      * {@link CompositeByteBuf}.
465      */

466     public CompositeByteBuf addFlattenedComponents(boolean increaseWriterIndex, ByteBuf buffer) {
467         checkNotNull(buffer, "buffer");
468         final int ridx = buffer.readerIndex();
469         final int widx = buffer.writerIndex();
470         if (ridx == widx) {
471             buffer.release();
472             return this;
473         }
474         if (!(buffer instanceof CompositeByteBuf)) {
475             addComponent0(increaseWriterIndex, componentCount, buffer);
476             consolidateIfNeeded();
477             return this;
478         }
479         final CompositeByteBuf from;
480         if (buffer instanceof WrappedCompositeByteBuf) {
481             from = (CompositeByteBuf) buffer.unwrap();
482         } else {
483             from = (CompositeByteBuf) buffer;
484         }
485         from.checkIndex(ridx, widx - ridx);
486         final Component[] fromComponents = from.components;
487         final int compCountBefore = componentCount;
488         final int writerIndexBefore = writerIndex;
489         try {
490             for (int cidx = from.toComponentIndex0(ridx), newOffset = capacity();; cidx++) {
491                 final Component component = fromComponents[cidx];
492                 final int compOffset = component.offset;
493                 final int fromIdx = Math.max(ridx, compOffset);
494                 final int toIdx = Math.min(widx, component.endOffset);
495                 final int len = toIdx - fromIdx;
496                 if (len > 0) { // skip empty components
497                     addComp(componentCount, new Component(
498                             component.srcBuf.retain(), component.srcIdx(fromIdx),
499                             component.buf, component.idx(fromIdx), newOffset, len, null));
500                 }
501                 if (widx == toIdx) {
502                     break;
503                 }
504                 newOffset += len;
505             }
506             if (increaseWriterIndex) {
507                 writerIndex = writerIndexBefore + (widx - ridx);
508             }
509             consolidateIfNeeded();
510             buffer.release();
511             buffer = null;
512             return this;
513         } finally {
514             if (buffer != null) {
515                 // if we did not succeed, attempt to rollback any components that were added
516                 if (increaseWriterIndex) {
517                     writerIndex = writerIndexBefore;
518                 }
519                 for (int cidx = componentCount - 1; cidx >= compCountBefore; cidx--) {
520                     components[cidx].free();
521                     removeComp(cidx);
522                 }
523             }
524         }
525     }
526
527     // TODO optimize further, similar to ByteBuf[] version
528     // (difference here is that we don't know *always* know precise size increase in advance,
529     // but we do in the most common case that the Iterable is a Collection)
530     private CompositeByteBuf addComponents(boolean increaseIndex, int cIndex, Iterable<ByteBuf> buffers) {
531         if (buffers instanceof ByteBuf) {
532             // If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf).
533             return addComponent(increaseIndex, cIndex, (ByteBuf) buffers);
534         }
535         checkNotNull(buffers, "buffers");
536         Iterator<ByteBuf> it = buffers.iterator();
537         try {
538             checkComponentIndex(cIndex);
539
540             // No need for consolidation
541             while (it.hasNext()) {
542                 ByteBuf b = it.next();
543                 if (b == null) {
544                     break;
545                 }
546                 cIndex = addComponent0(increaseIndex, cIndex, b) + 1;
547                 cIndex = Math.min(cIndex, componentCount);
548             }
549         } finally {
550             while (it.hasNext()) {
551                 ReferenceCountUtil.safeRelease(it.next());
552             }
553         }
554         consolidateIfNeeded();
555         return this;
556     }
557
558     /**
559      * This should only be called as last operation from a method as this may adjust the underlying
560      * array of components and so affect the index etc.
561      */

562     private void consolidateIfNeeded() {
563         // Consolidate if the number of components will exceed the allowed maximum by the current
564         // operation.
565         int size = componentCount;
566         if (size > maxNumComponents) {
567             consolidate0(0, size);
568         }
569     }
570
571     private void checkComponentIndex(int cIndex) {
572         ensureAccessible();
573         if (cIndex < 0 || cIndex > componentCount) {
574             throw new IndexOutOfBoundsException(String.format(
575                     "cIndex: %d (expected: >= 0 && <= numComponents(%d))",
576                     cIndex, componentCount));
577         }
578     }
579
580     private void checkComponentIndex(int cIndex, int numComponents) {
581         ensureAccessible();
582         if (cIndex < 0 || cIndex + numComponents > componentCount) {
583             throw new IndexOutOfBoundsException(String.format(
584                     "cIndex: %d, numComponents: %d " +
585                     "(expected: cIndex >= 0 && cIndex + numComponents <= totalNumComponents(%d))",
586                     cIndex, numComponents, componentCount));
587         }
588     }
589
590     private void updateComponentOffsets(int cIndex) {
591         int size = componentCount;
592         if (size <= cIndex) {
593             return;
594         }
595
596         int nextIndex = cIndex > 0 ? components[cIndex - 1].endOffset : 0;
597         for (; cIndex < size; cIndex++) {
598             Component c = components[cIndex];
599             c.reposition(nextIndex);
600             nextIndex = c.endOffset;
601         }
602     }
603
604     /**
605      * Remove the {@link ByteBuf} from the given index.
606      *
607      * @param cIndex the index on from which the {@link ByteBuf} will be remove
608      */

609     public CompositeByteBuf removeComponent(int cIndex) {
610         checkComponentIndex(cIndex);
611         Component comp = components[cIndex];
612         if (lastAccessed == comp) {
613             lastAccessed = null;
614         }
615         comp.free();
616         removeComp(cIndex);
617         if (comp.length() > 0) {
618             // Only need to call updateComponentOffsets if the length was > 0
619             updateComponentOffsets(cIndex);
620         }
621         return this;
622     }
623
624     /**
625      * Remove the number of {@link ByteBuf}s starting from the given index.
626      *
627      * @param cIndex the index on which the {@link ByteBuf}s will be started to removed
628      * @param numComponents the number of components to remove
629      */

630     public CompositeByteBuf removeComponents(int cIndex, int numComponents) {
631         checkComponentIndex(cIndex, numComponents);
632
633         if (numComponents == 0) {
634             return this;
635         }
636         int endIndex = cIndex + numComponents;
637         boolean needsUpdate = false;
638         for (int i = cIndex; i < endIndex; ++i) {
639             Component c = components[i];
640             if (c.length() > 0) {
641                 needsUpdate = true;
642             }
643             if (lastAccessed == c) {
644                 lastAccessed = null;
645             }
646             c.free();
647         }
648         removeCompRange(cIndex, endIndex);
649
650         if (needsUpdate) {
651             // Only need to call updateComponentOffsets if the length was > 0
652             updateComponentOffsets(cIndex);
653         }
654         return this;
655     }
656
657     @Override
658     public Iterator<ByteBuf> iterator() {
659         ensureAccessible();
660         return componentCount == 0 ? EMPTY_ITERATOR : new CompositeByteBufIterator();
661     }
662
663     @Override
664     protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
665         if (end <= start) {
666             return -1;
667         }
668         for (int i = toComponentIndex0(start), length = end - start; length > 0; i++) {
669             Component c = components[i];
670             if (c.offset == c.endOffset) {
671                 continue// empty
672             }
673             ByteBuf s = c.buf;
674             int localStart = c.idx(start);
675             int localLength = Math.min(length, c.endOffset - start);
676             // avoid additional checks in AbstractByteBuf case
677             int result = s instanceof AbstractByteBuf
678                 ? ((AbstractByteBuf) s).forEachByteAsc0(localStart, localStart + localLength, processor)
679                 : s.forEachByte(localStart, localLength, processor);
680             if (result != -1) {
681                 return result - c.adjustment;
682             }
683             start += localLength;
684             length -= localLength;
685         }
686         return -1;
687     }
688
689     @Override
690     protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) throws Exception {
691         if (rEnd > rStart) { // rStart *and* rEnd are inclusive
692             return -1;
693         }
694         for (int i = toComponentIndex0(rStart), length = 1 + rStart - rEnd; length > 0; i--) {
695             Component c = components[i];
696             if (c.offset == c.endOffset) {
697                 continue// empty
698             }
699             ByteBuf s = c.buf;
700             int localRStart = c.idx(length + rEnd);
701             int localLength = Math.min(length, localRStart), localIndex = localRStart - localLength;
702             // avoid additional checks in AbstractByteBuf case
703             int result = s instanceof AbstractByteBuf
704                 ? ((AbstractByteBuf) s).forEachByteDesc0(localRStart - 1, localIndex, processor)
705                 : s.forEachByteDesc(localIndex, localLength, processor);
706
707             if (result != -1) {
708                 return result - c.adjustment;
709             }
710             length -= localLength;
711         }
712         return -1;
713     }
714
715     /**
716      * Same with {@link #slice(intint)} except that this method returns a list.
717      */

718     public List<ByteBuf> decompose(int offset, int length) {
719         checkIndex(offset, length);
720         if (length == 0) {
721             return Collections.emptyList();
722         }
723
724         int componentId = toComponentIndex0(offset);
725         int bytesToSlice = length;
726         // The first component
727         Component firstC = components[componentId];
728
729         ByteBuf slice = firstC.buf.slice(firstC.idx(offset), Math.min(firstC.endOffset - offset, bytesToSlice));
730         bytesToSlice -= slice.readableBytes();
731
732         if (bytesToSlice == 0) {
733             return Collections.singletonList(slice);
734         }
735
736         List<ByteBuf> sliceList = new ArrayList<ByteBuf>(componentCount - componentId);
737         sliceList.add(slice);
738
739         // Add all the slices until there is nothing more left and then return the List.
740         do {
741             Component component = components[++componentId];
742             slice = component.buf.slice(component.idx(component.offset), Math.min(component.length(), bytesToSlice));
743             bytesToSlice -= slice.readableBytes();
744             sliceList.add(slice);
745         } while (bytesToSlice > 0);
746
747         return sliceList;
748     }
749
750     @Override
751     public boolean isDirect() {
752         int size = componentCount;
753         if (size == 0) {
754             return false;
755         }
756         for (int i = 0; i < size; i++) {
757            if (!components[i].buf.isDirect()) {
758                return false;
759            }
760         }
761         return true;
762     }
763
764     @Override
765     public boolean hasArray() {
766         switch (componentCount) {
767         case 0:
768             return true;
769         case 1:
770             return components[0].buf.hasArray();
771         default:
772             return false;
773         }
774     }
775
776     @Override
777     public byte[] array() {
778         switch (componentCount) {
779         case 0:
780             return EmptyArrays.EMPTY_BYTES;
781         case 1:
782             return components[0].buf.array();
783         default:
784             throw new UnsupportedOperationException();
785         }
786     }
787
788     @Override
789     public int arrayOffset() {
790         switch (componentCount) {
791         case 0:
792             return 0;
793         case 1:
794             Component c = components[0];
795             return c.idx(c.buf.arrayOffset());
796         default:
797             throw new UnsupportedOperationException();
798         }
799     }
800
801     @Override
802     public boolean hasMemoryAddress() {
803         switch (componentCount) {
804         case 0:
805             return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
806         case 1:
807             return components[0].buf.hasMemoryAddress();
808         default:
809             return false;
810         }
811     }
812
813     @Override
814     public long memoryAddress() {
815         switch (componentCount) {
816         case 0:
817             return Unpooled.EMPTY_BUFFER.memoryAddress();
818         case 1:
819             Component c = components[0];
820             return c.buf.memoryAddress() + c.adjustment;
821         default:
822             throw new UnsupportedOperationException();
823         }
824     }
825
826     @Override
827     public int capacity() {
828         int size = componentCount;
829         return size > 0 ? components[size - 1].endOffset : 0;
830     }
831
832     @Override
833     public CompositeByteBuf capacity(int newCapacity) {
834         checkNewCapacity(newCapacity);
835
836         final int size = componentCount, oldCapacity = capacity();
837         if (newCapacity > oldCapacity) {
838             final int paddingLength = newCapacity - oldCapacity;
839             ByteBuf padding = allocBuffer(paddingLength).setIndex(0, paddingLength);
840             addComponent0(false, size, padding);
841             if (componentCount >= maxNumComponents) {
842                 // FIXME: No need to create a padding buffer and consolidate.
843                 // Just create a big single buffer and put the current content there.
844                 consolidateIfNeeded();
845             }
846         } else if (newCapacity < oldCapacity) {
847             lastAccessed = null;
848             int i = size - 1;
849             for (int bytesToTrim = oldCapacity - newCapacity; i >= 0; i--) {
850                 Component c = components[i];
851                 final int cLength = c.length();
852                 if (bytesToTrim < cLength) {
853                     // Trim the last component
854                     c.endOffset -= bytesToTrim;
855                     ByteBuf slice = c.slice;
856                     if (slice != null) {
857                         // We must replace the cached slice with a derived one to ensure that
858                         // it can later be released properly in the case of PooledSlicedByteBuf.
859                         c.slice = slice.slice(0, c.length());
860                     }
861                     break;
862                 }
863                 c.free();
864                 bytesToTrim -= cLength;
865             }
866             removeCompRange(i + 1, size);
867
868             if (readerIndex() > newCapacity) {
869                 setIndex0(newCapacity, newCapacity);
870             } else if (writerIndex > newCapacity) {
871                 writerIndex = newCapacity;
872             }
873         }
874         return this;
875     }
876
877     @Override
878     public ByteBufAllocator alloc() {
879         return alloc;
880     }
881
882     @Override
883     public ByteOrder order() {
884         return ByteOrder.BIG_ENDIAN;
885     }
886
887     /**
888      * Return the current number of {@link ByteBuf}'s that are composed in this instance
889      */

890     public int numComponents() {
891         return componentCount;
892     }
893
894     /**
895      * Return the max number of {@link ByteBuf}'s that are composed in this instance
896      */

897     public int maxNumComponents() {
898         return maxNumComponents;
899     }
900
901     /**
902      * Return the index for the given offset
903      */

904     public int toComponentIndex(int offset) {
905         checkIndex(offset);
906         return toComponentIndex0(offset);
907     }
908
909     private int toComponentIndex0(int offset) {
910         int size = componentCount;
911         if (offset == 0) { // fast-path zero offset
912             for (int i = 0; i < size; i++) {
913                 if (components[i].endOffset > 0) {
914                     return i;
915                 }
916             }
917         }
918         if (size <= 2) { // fast-path for 1 and 2 component count
919             return size == 1 || offset < components[0].endOffset ? 0 : 1;
920         }
921         for (int low = 0, high = size; low <= high;) {
922             int mid = low + high >>> 1;
923             Component c = components[mid];
924             if (offset >= c.endOffset) {
925                 low = mid + 1;
926             } else if (offset < c.offset) {
927                 high = mid - 1;
928             } else {
929                 return mid;
930             }
931         }
932
933         throw new Error("should not reach here");
934     }
935
936     public int toByteIndex(int cIndex) {
937         checkComponentIndex(cIndex);
938         return components[cIndex].offset;
939     }
940
941     @Override
942     public byte getByte(int index) {
943         Component c = findComponent(index);
944         return c.buf.getByte(c.idx(index));
945     }
946
947     @Override
948     protected byte _getByte(int index) {
949         Component c = findComponent0(index);
950         return c.buf.getByte(c.idx(index));
951     }
952
953     @Override
954     protected short _getShort(int index) {
955         Component c = findComponent0(index);
956         if (index + 2 <= c.endOffset) {
957             return c.buf.getShort(c.idx(index));
958         } else if (order() == ByteOrder.BIG_ENDIAN) {
959             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
960         } else {
961             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
962         }
963     }
964
965     @Override
966     protected short _getShortLE(int index) {
967         Component c = findComponent0(index);
968         if (index + 2 <= c.endOffset) {
969             return c.buf.getShortLE(c.idx(index));
970         } else if (order() == ByteOrder.BIG_ENDIAN) {
971             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
972         } else {
973             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
974         }
975     }
976
977     @Override
978     protected int _getUnsignedMedium(int index) {
979         Component c = findComponent0(index);
980         if (index + 3 <= c.endOffset) {
981             return c.buf.getUnsignedMedium(c.idx(index));
982         } else if (order() == ByteOrder.BIG_ENDIAN) {
983             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
984         } else {
985             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
986         }
987     }
988
989     @Override
990     protected int _getUnsignedMediumLE(int index) {
991         Component c = findComponent0(index);
992         if (index + 3 <= c.endOffset) {
993             return c.buf.getUnsignedMediumLE(c.idx(index));
994         } else if (order() == ByteOrder.BIG_ENDIAN) {
995             return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16;
996         } else {
997             return (_getShortLE(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
998         }
999     }
1000
1001     @Override
1002     protected int _getInt(int index) {
1003         Component c = findComponent0(index);
1004         if (index + 4 <= c.endOffset) {
1005             return c.buf.getInt(c.idx(index));
1006         } else if (order() == ByteOrder.BIG_ENDIAN) {
1007             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
1008         } else {
1009             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
1010         }
1011     }
1012
1013     @Override
1014     protected int _getIntLE(int index) {
1015         Component c = findComponent0(index);
1016         if (index + 4 <= c.endOffset) {
1017             return c.buf.getIntLE(c.idx(index));
1018         } else if (order() == ByteOrder.BIG_ENDIAN) {
1019             return _getShortLE(index) & 0xffff | (_getShortLE(index + 2) & 0xffff) << 16;
1020         } else {
1021             return (_getShortLE(index) & 0xffff) << 16 | _getShortLE(index + 2) & 0xffff;
1022         }
1023     }
1024
1025     @Override
1026     protected long _getLong(int index) {
1027         Component c = findComponent0(index);
1028         if (index + 8 <= c.endOffset) {
1029             return c.buf.getLong(c.idx(index));
1030         } else if (order() == ByteOrder.BIG_ENDIAN) {
1031             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
1032         } else {
1033             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
1034         }
1035     }
1036
1037     @Override
1038     protected long _getLongLE(int index) {
1039         Component c = findComponent0(index);
1040         if (index + 8 <= c.endOffset) {
1041             return c.buf.getLongLE(c.idx(index));
1042         } else if (order() == ByteOrder.BIG_ENDIAN) {
1043             return _getIntLE(index) & 0xffffffffL | (_getIntLE(index + 4) & 0xffffffffL) << 32;
1044         } else {
1045             return (_getIntLE(index) & 0xffffffffL) << 32 | _getIntLE(index + 4) & 0xffffffffL;
1046         }
1047     }
1048
1049     @Override
1050     public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
1051         checkDstIndex(index, length, dstIndex, dst.length);
1052         if (length == 0) {
1053             return this;
1054         }
1055
1056         int i = toComponentIndex0(index);
1057         while (length > 0) {
1058             Component c = components[i];
1059             int localLength = Math.min(length, c.endOffset - index);
1060             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1061             index += localLength;
1062             dstIndex += localLength;
1063             length -= localLength;
1064             i ++;
1065         }
1066         return this;
1067     }
1068
1069     @Override
1070     public CompositeByteBuf getBytes(int index, ByteBuffer dst) {
1071         int limit = dst.limit();
1072         int length = dst.remaining();
1073
1074         checkIndex(index, length);
1075         if (length == 0) {
1076             return this;
1077         }
1078
1079         int i = toComponentIndex0(index);
1080         try {
1081             while (length > 0) {
1082                 Component c = components[i];
1083                 int localLength = Math.min(length, c.endOffset - index);
1084                 dst.limit(dst.position() + localLength);
1085                 c.buf.getBytes(c.idx(index), dst);
1086                 index += localLength;
1087                 length -= localLength;
1088                 i ++;
1089             }
1090         } finally {
1091             dst.limit(limit);
1092         }
1093         return this;
1094     }
1095
1096     @Override
1097     public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
1098         checkDstIndex(index, length, dstIndex, dst.capacity());
1099         if (length == 0) {
1100             return this;
1101         }
1102
1103         int i = toComponentIndex0(index);
1104         while (length > 0) {
1105             Component c = components[i];
1106             int localLength = Math.min(length, c.endOffset - index);
1107             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1108             index += localLength;
1109             dstIndex += localLength;
1110             length -= localLength;
1111             i ++;
1112         }
1113         return this;
1114     }
1115
1116     @Override
1117     public int getBytes(int index, GatheringByteChannel out, int length)
1118             throws IOException {
1119         int count = nioBufferCount();
1120         if (count == 1) {
1121             return out.write(internalNioBuffer(index, length));
1122         } else {
1123             long writtenBytes = out.write(nioBuffers(index, length));
1124             if (writtenBytes > Integer.MAX_VALUE) {
1125                 return Integer.MAX_VALUE;
1126             } else {
1127                 return (int) writtenBytes;
1128             }
1129         }
1130     }
1131
1132     @Override
1133     public int getBytes(int index, FileChannel out, long position, int length)
1134             throws IOException {
1135         int count = nioBufferCount();
1136         if (count == 1) {
1137             return out.write(internalNioBuffer(index, length), position);
1138         } else {
1139             long writtenBytes = 0;
1140             for (ByteBuffer buf : nioBuffers(index, length)) {
1141                 writtenBytes += out.write(buf, position + writtenBytes);
1142             }
1143             if (writtenBytes > Integer.MAX_VALUE) {
1144                 return Integer.MAX_VALUE;
1145             }
1146             return (int) writtenBytes;
1147         }
1148     }
1149
1150     @Override
1151     public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
1152         checkIndex(index, length);
1153         if (length == 0) {
1154             return this;
1155         }
1156
1157         int i = toComponentIndex0(index);
1158         while (length > 0) {
1159             Component c = components[i];
1160             int localLength = Math.min(length, c.endOffset - index);
1161             c.buf.getBytes(c.idx(index), out, localLength);
1162             index += localLength;
1163             length -= localLength;
1164             i ++;
1165         }
1166         return this;
1167     }
1168
1169     @Override
1170     public CompositeByteBuf setByte(int index, int value) {
1171         Component c = findComponent(index);
1172         c.buf.setByte(c.idx(index), value);
1173         return this;
1174     }
1175
1176     @Override
1177     protected void _setByte(int index, int value) {
1178         Component c = findComponent0(index);
1179         c.buf.setByte(c.idx(index), value);
1180     }
1181
1182     @Override
1183     public CompositeByteBuf setShort(int index, int value) {
1184         checkIndex(index, 2);
1185         _setShort(index, value);
1186         return this;
1187     }
1188
1189     @Override
1190     protected void _setShort(int index, int value) {
1191         Component c = findComponent0(index);
1192         if (index + 2 <= c.endOffset) {
1193             c.buf.setShort(c.idx(index), value);
1194         } else if (order() == ByteOrder.BIG_ENDIAN) {
1195             _setByte(index, (byte) (value >>> 8));
1196             _setByte(index + 1, (byte) value);
1197         } else {
1198             _setByte(index, (byte) value);
1199             _setByte(index + 1, (byte) (value >>> 8));
1200         }
1201     }
1202
1203     @Override
1204     protected void _setShortLE(int index, int value) {
1205         Component c = findComponent0(index);
1206         if (index + 2 <= c.endOffset) {
1207             c.buf.setShortLE(c.idx(index), value);
1208         } else if (order() == ByteOrder.BIG_ENDIAN) {
1209             _setByte(index, (byte) value);
1210             _setByte(index + 1, (byte) (value >>> 8));
1211         } else {
1212             _setByte(index, (byte) (value >>> 8));
1213             _setByte(index + 1, (byte) value);
1214         }
1215     }
1216
1217     @Override
1218     public CompositeByteBuf setMedium(int index, int value) {
1219         checkIndex(index, 3);
1220         _setMedium(index, value);
1221         return this;
1222     }
1223
1224     @Override
1225     protected void _setMedium(int index, int value) {
1226         Component c = findComponent0(index);
1227         if (index + 3 <= c.endOffset) {
1228             c.buf.setMedium(c.idx(index), value);
1229         } else if (order() == ByteOrder.BIG_ENDIAN) {
1230             _setShort(index, (short) (value >> 8));
1231             _setByte(index + 2, (byte) value);
1232         } else {
1233             _setShort(index, (short) value);
1234             _setByte(index + 2, (byte) (value >>> 16));
1235         }
1236     }
1237
1238     @Override
1239     protected void _setMediumLE(int index, int value) {
1240         Component c = findComponent0(index);
1241         if (index + 3 <= c.endOffset) {
1242             c.buf.setMediumLE(c.idx(index), value);
1243         } else if (order() == ByteOrder.BIG_ENDIAN) {
1244             _setShortLE(index, (short) value);
1245             _setByte(index + 2, (byte) (value >>> 16));
1246         } else {
1247             _setShortLE(index, (short) (value >> 8));
1248             _setByte(index + 2, (byte) value);
1249         }
1250     }
1251
1252     @Override
1253     public CompositeByteBuf setInt(int index, int value) {
1254         checkIndex(index, 4);
1255         _setInt(index, value);
1256         return this;
1257     }
1258
1259     @Override
1260     protected void _setInt(int index, int value) {
1261         Component c = findComponent0(index);
1262         if (index + 4 <= c.endOffset) {
1263             c.buf.setInt(c.idx(index), value);
1264         } else if (order() == ByteOrder.BIG_ENDIAN) {
1265             _setShort(index, (short) (value >>> 16));
1266             _setShort(index + 2, (short) value);
1267         } else {
1268             _setShort(index, (short) value);
1269             _setShort(index + 2, (short) (value >>> 16));
1270         }
1271     }
1272
1273     @Override
1274     protected void _setIntLE(int index, int value) {
1275         Component c = findComponent0(index);
1276         if (index + 4 <= c.endOffset) {
1277             c.buf.setIntLE(c.idx(index), value);
1278         } else if (order() == ByteOrder.BIG_ENDIAN) {
1279             _setShortLE(index, (short) value);
1280             _setShortLE(index + 2, (short) (value >>> 16));
1281         } else {
1282             _setShortLE(index, (short) (value >>> 16));
1283             _setShortLE(index + 2, (short) value);
1284         }
1285     }
1286
1287     @Override
1288     public CompositeByteBuf setLong(int index, long value) {
1289         checkIndex(index, 8);
1290         _setLong(index, value);
1291         return this;
1292     }
1293
1294     @Override
1295     protected void _setLong(int index, long value) {
1296         Component c = findComponent0(index);
1297         if (index + 8 <= c.endOffset) {
1298             c.buf.setLong(c.idx(index), value);
1299         } else if (order() == ByteOrder.BIG_ENDIAN) {
1300             _setInt(index, (int) (value >>> 32));
1301             _setInt(index + 4, (int) value);
1302         } else {
1303             _setInt(index, (int) value);
1304             _setInt(index + 4, (int) (value >>> 32));
1305         }
1306     }
1307
1308     @Override
1309     protected void _setLongLE(int index, long value) {
1310         Component c = findComponent0(index);
1311         if (index + 8 <= c.endOffset) {
1312             c.buf.setLongLE(c.idx(index), value);
1313         } else if (order() == ByteOrder.BIG_ENDIAN) {
1314             _setIntLE(index, (int) value);
1315             _setIntLE(index + 4, (int) (value >>> 32));
1316         } else {
1317             _setIntLE(index, (int) (value >>> 32));
1318             _setIntLE(index + 4, (int) value);
1319         }
1320     }
1321
1322     @Override
1323     public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
1324         checkSrcIndex(index, length, srcIndex, src.length);
1325         if (length == 0) {
1326             return this;
1327         }
1328
1329         int i = toComponentIndex0(index);
1330         while (length > 0) {
1331             Component c = components[i];
1332             int localLength = Math.min(length, c.endOffset - index);
1333             c.buf.setBytes(c.idx(index), src, srcIndex, localLength);
1334             index += localLength;
1335             srcIndex += localLength;
1336             length -= localLength;
1337             i ++;
1338         }
1339         return this;
1340     }
1341
1342     @Override
1343     public CompositeByteBuf setBytes(int index, ByteBuffer src) {
1344         int limit = src.limit();
1345         int length = src.remaining();
1346
1347         checkIndex(index, length);
1348         if (length == 0) {
1349             return this;
1350         }
1351
1352         int i = toComponentIndex0(index);
1353         try {
1354             while (length > 0) {
1355                 Component c = components[i];
1356                 int localLength = Math.min(length, c.endOffset - index);
1357                 src.limit(src.position() + localLength);
1358                 c.buf.setBytes(c.idx(index), src);
1359                 index += localLength;
1360                 length -= localLength;
1361                 i ++;
1362             }
1363         } finally {
1364             src.limit(limit);
1365         }
1366         return this;
1367     }
1368
1369     @Override
1370     public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
1371         checkSrcIndex(index, length, srcIndex, src.capacity());
1372         if (length == 0) {
1373             return this;
1374         }
1375
1376         int i = toComponentIndex0(index);
1377         while (length > 0) {
1378             Component c = components[i];
1379             int localLength = Math.min(length, c.endOffset - index);
1380             c.buf.setBytes(c.idx(index), src, srcIndex, localLength);
1381             index += localLength;
1382             srcIndex += localLength;
1383             length -= localLength;
1384             i ++;
1385         }
1386         return this;
1387     }
1388
1389     @Override
1390     public int setBytes(int index, InputStream in, int length) throws IOException {
1391         checkIndex(index, length);
1392         if (length == 0) {
1393             return in.read(EmptyArrays.EMPTY_BYTES);
1394         }
1395
1396         int i = toComponentIndex0(index);
1397         int readBytes = 0;
1398         do {
1399             Component c = components[i];
1400             int localLength = Math.min(length, c.endOffset - index);
1401             if (localLength == 0) {
1402                 // Skip empty buffer
1403                 i++;
1404                 continue;
1405             }
1406             int localReadBytes = c.buf.setBytes(c.idx(index), in, localLength);
1407             if (localReadBytes < 0) {
1408                 if (readBytes == 0) {
1409                     return -1;
1410                 } else {
1411                     break;
1412                 }
1413             }
1414
1415             index += localReadBytes;
1416             length -= localReadBytes;
1417             readBytes += localReadBytes;
1418             if (localReadBytes == localLength) {
1419                 i ++;
1420             }
1421         } while (length > 0);
1422
1423         return readBytes;
1424     }
1425
1426     @Override
1427     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
1428         checkIndex(index, length);
1429         if (length == 0) {
1430             return in.read(EMPTY_NIO_BUFFER);
1431         }
1432
1433         int i = toComponentIndex0(index);
1434         int readBytes = 0;
1435         do {
1436             Component c = components[i];
1437             int localLength = Math.min(length, c.endOffset - index);
1438             if (localLength == 0) {
1439                 // Skip empty buffer
1440                 i++;
1441                 continue;
1442             }
1443             int localReadBytes = c.buf.setBytes(c.idx(index), in, localLength);
1444
1445             if (localReadBytes == 0) {
1446                 break;
1447             }
1448
1449             if (localReadBytes < 0) {
1450                 if (readBytes == 0) {
1451                     return -1;
1452                 } else {
1453                     break;
1454                 }
1455             }
1456
1457             index += localReadBytes;
1458             length -= localReadBytes;
1459             readBytes += localReadBytes;
1460             if (localReadBytes == localLength) {
1461                 i ++;
1462             }
1463         } while (length > 0);
1464
1465         return readBytes;
1466     }
1467
1468     @Override
1469     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
1470         checkIndex(index, length);
1471         if (length == 0) {
1472             return in.read(EMPTY_NIO_BUFFER, position);
1473         }
1474
1475         int i = toComponentIndex0(index);
1476         int readBytes = 0;
1477         do {
1478             Component c = components[i];
1479             int localLength = Math.min(length, c.endOffset - index);
1480             if (localLength == 0) {
1481                 // Skip empty buffer
1482                 i++;
1483                 continue;
1484             }
1485             int localReadBytes = c.buf.setBytes(c.idx(index), in, position + readBytes, localLength);
1486
1487             if (localReadBytes == 0) {
1488                 break;
1489             }
1490
1491             if (localReadBytes < 0) {
1492                 if (readBytes == 0) {
1493                     return -1;
1494                 } else {
1495                     break;
1496                 }
1497             }
1498
1499             index += localReadBytes;
1500             length -= localReadBytes;
1501             readBytes += localReadBytes;
1502             if (localReadBytes == localLength) {
1503                 i ++;
1504             }
1505         } while (length > 0);
1506
1507         return readBytes;
1508     }
1509
1510     @Override
1511     public ByteBuf copy(int index, int length) {
1512         checkIndex(index, length);
1513         ByteBuf dst = allocBuffer(length);
1514         if (length != 0) {
1515             copyTo(index, length, toComponentIndex0(index), dst);
1516         }
1517         return dst;
1518     }
1519
1520     private void copyTo(int index, int length, int componentId, ByteBuf dst) {
1521         int dstIndex = 0;
1522         int i = componentId;
1523
1524         while (length > 0) {
1525             Component c = components[i];
1526             int localLength = Math.min(length, c.endOffset - index);
1527             c.buf.getBytes(c.idx(index), dst, dstIndex, localLength);
1528             index += localLength;
1529             dstIndex += localLength;
1530             length -= localLength;
1531             i ++;
1532         }
1533
1534         dst.writerIndex(dst.capacity());
1535     }
1536
1537     /**
1538      * Return the {@link ByteBuf} on the specified index
1539      *
1540      * @param cIndex the index for which the {@link ByteBuf} should be returned
1541      * @return buf the {@link ByteBuf} on the specified index
1542      */

1543     public ByteBuf component(int cIndex) {
1544         checkComponentIndex(cIndex);
1545         return components[cIndex].duplicate();
1546     }
1547
1548     /**
1549      * Return the {@link ByteBuf} on the specified index
1550      *
1551      * @param offset the offset for which the {@link ByteBuf} should be returned
1552      * @return the {@link ByteBuf} on the specified index
1553      */

1554     public ByteBuf componentAtOffset(int offset) {
1555         return findComponent(offset).duplicate();
1556     }
1557
1558     /**
1559      * Return the internal {@link ByteBuf} on the specified index. Note that updating the indexes of the returned
1560      * buffer will lead to an undefined behavior of this buffer.
1561      *
1562      * @param cIndex the index for which the {@link ByteBuf} should be returned
1563      */

1564     public ByteBuf internalComponent(int cIndex) {
1565         checkComponentIndex(cIndex);
1566         return components[cIndex].slice();
1567     }
1568
1569     /**
1570      * Return the internal {@link ByteBuf} on the specified offset. Note that updating the indexes of the returned
1571      * buffer will lead to an undefined behavior of this buffer.
1572      *
1573      * @param offset the offset for which the {@link ByteBuf} should be returned
1574      */

1575     public ByteBuf internalComponentAtOffset(int offset) {
1576         return findComponent(offset).slice();
1577     }
1578
1579     // weak cache - check it first when looking for component
1580     private Component lastAccessed;
1581
1582     private Component findComponent(int offset) {
1583         Component la = lastAccessed;
1584         if (la != null && offset >= la.offset && offset < la.endOffset) {
1585            ensureAccessible();
1586            return la;
1587         }
1588         checkIndex(offset);
1589         return findIt(offset);
1590     }
1591
1592     private Component findComponent0(int offset) {
1593         Component la = lastAccessed;
1594         if (la != null && offset >= la.offset && offset < la.endOffset) {
1595            return la;
1596         }
1597         return findIt(offset);
1598     }
1599
1600     private Component findIt(int offset) {
1601         for (int low = 0, high = componentCount; low <= high;) {
1602             int mid = low + high >>> 1;
1603             Component c = components[mid];
1604             if (offset >= c.endOffset) {
1605                 low = mid + 1;
1606             } else if (offset < c.offset) {
1607                 high = mid - 1;
1608             } else {
1609                 lastAccessed = c;
1610                 return c;
1611             }
1612         }
1613
1614         throw new Error("should not reach here");
1615     }
1616
1617     @Override
1618     public int nioBufferCount() {
1619         int size = componentCount;
1620         switch (size) {
1621         case 0:
1622             return 1;
1623         case 1:
1624             return components[0].buf.nioBufferCount();
1625         default:
1626             int count = 0;
1627             for (int i = 0; i < size; i++) {
1628                 count += components[i].buf.nioBufferCount();
1629             }
1630             return count;
1631         }
1632     }
1633
1634     @Override
1635     public ByteBuffer internalNioBuffer(int index, int length) {
1636         switch (componentCount) {
1637         case 0:
1638             return EMPTY_NIO_BUFFER;
1639         case 1:
1640             return components[0].internalNioBuffer(index, length);
1641         default:
1642             throw new UnsupportedOperationException();
1643         }
1644     }
1645
1646     @Override
1647     public ByteBuffer nioBuffer(int index, int length) {
1648         checkIndex(index, length);
1649
1650         switch (componentCount) {
1651         case 0:
1652             return EMPTY_NIO_BUFFER;
1653         case 1:
1654             Component c = components[0];
1655             ByteBuf buf = c.buf;
1656             if (buf.nioBufferCount() == 1) {
1657                 return buf.nioBuffer(c.idx(index), length);
1658             }
1659         }
1660
1661         ByteBuffer[] buffers = nioBuffers(index, length);
1662
1663         if (buffers.length == 1) {
1664             return buffers[0];
1665         }
1666
1667         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
1668         for (ByteBuffer buf: buffers) {
1669             merged.put(buf);
1670         }
1671
1672         merged.flip();
1673         return merged;
1674     }
1675
1676     @Override
1677     public ByteBuffer[] nioBuffers(int index, int length) {
1678         checkIndex(index, length);
1679         if (length == 0) {
1680             return new ByteBuffer[] { EMPTY_NIO_BUFFER };
1681         }
1682
1683         RecyclableArrayList buffers = RecyclableArrayList.newInstance(componentCount);
1684         try {
1685             int i = toComponentIndex0(index);
1686             while (length > 0) {
1687                 Component c = components[i];
1688                 ByteBuf s = c.buf;
1689                 int localLength = Math.min(length, c.endOffset - index);
1690                 switch (s.nioBufferCount()) {
1691                 case 0:
1692                     throw new UnsupportedOperationException();
1693                 case 1:
1694                     buffers.add(s.nioBuffer(c.idx(index), localLength));
1695                     break;
1696                 default:
1697                     Collections.addAll(buffers, s.nioBuffers(c.idx(index), localLength));
1698                 }
1699
1700                 index += localLength;
1701                 length -= localLength;
1702                 i ++;
1703             }
1704
1705             return buffers.toArray(new ByteBuffer[0]);
1706         } finally {
1707             buffers.recycle();
1708         }
1709     }
1710
1711     /**
1712      * Consolidate the composed {@link ByteBuf}s
1713      */

1714     public CompositeByteBuf consolidate() {
1715         ensureAccessible();
1716         consolidate0(0, componentCount);
1717         return this;
1718     }
1719
1720     /**
1721      * Consolidate the composed {@link ByteBuf}s
1722      *
1723      * @param cIndex the index on which to start to compose
1724      * @param numComponents the number of components to compose
1725      */

1726     public CompositeByteBuf consolidate(int cIndex, int numComponents) {
1727         checkComponentIndex(cIndex, numComponents);
1728         consolidate0(cIndex, numComponents);
1729         return this;
1730     }
1731
1732     private void consolidate0(int cIndex, int numComponents) {
1733         if (numComponents <= 1) {
1734             return;
1735         }
1736
1737         final int endCIndex = cIndex + numComponents;
1738         final int startOffset = cIndex != 0 ? components[cIndex].offset : 0;
1739         final int capacity = components[endCIndex - 1].endOffset - startOffset;
1740         final ByteBuf consolidated = allocBuffer(capacity);
1741
1742         for (int i = cIndex; i < endCIndex; i ++) {
1743             components[i].transferTo(consolidated);
1744         }
1745         lastAccessed = null;
1746         removeCompRange(cIndex + 1, endCIndex);
1747         components[cIndex] = newComponent(consolidated, 0);
1748         if (cIndex != 0 || numComponents != componentCount) {
1749             updateComponentOffsets(cIndex);
1750         }
1751     }
1752
1753     /**
1754      * Discard all {@link ByteBuf}s which are read.
1755      */

1756     public CompositeByteBuf discardReadComponents() {
1757         ensureAccessible();
1758         final int readerIndex = readerIndex();
1759         if (readerIndex == 0) {
1760             return this;
1761         }
1762
1763         // Discard everything if (readerIndex = writerIndex = capacity).
1764         int writerIndex = writerIndex();
1765         if (readerIndex == writerIndex && writerIndex == capacity()) {
1766             for (int i = 0, size = componentCount; i < size; i++) {
1767                 components[i].free();
1768             }
1769             lastAccessed = null;
1770             clearComps();
1771             setIndex(0, 0);
1772             adjustMarkers(readerIndex);
1773             return this;
1774         }
1775
1776         // Remove read components.
1777         int firstComponentId = 0;
1778         Component c = null;
1779         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1780             c = components[firstComponentId];
1781             if (c.endOffset > readerIndex) {
1782                 break;
1783             }
1784             c.free();
1785         }
1786         if (firstComponentId == 0) {
1787             return this// Nothing to discard
1788         }
1789         Component la = lastAccessed;
1790         if (la != null && la.endOffset <= readerIndex) {
1791             lastAccessed = null;
1792         }
1793         removeCompRange(0, firstComponentId);
1794
1795         // Update indexes and markers.
1796         int offset = c.offset;
1797         updateComponentOffsets(0);
1798         setIndex(readerIndex - offset, writerIndex - offset);
1799         adjustMarkers(offset);
1800         return this;
1801     }
1802
1803     @Override
1804     public CompositeByteBuf discardReadBytes() {
1805         ensureAccessible();
1806         final int readerIndex = readerIndex();
1807         if (readerIndex == 0) {
1808             return this;
1809         }
1810
1811         // Discard everything if (readerIndex = writerIndex = capacity).
1812         int writerIndex = writerIndex();
1813         if (readerIndex == writerIndex && writerIndex == capacity()) {
1814             for (int i = 0, size = componentCount; i < size; i++) {
1815                 components[i].free();
1816             }
1817             lastAccessed = null;
1818             clearComps();
1819             setIndex(0, 0);
1820             adjustMarkers(readerIndex);
1821             return this;
1822         }
1823
1824         int firstComponentId = 0;
1825         Component c = null;
1826         for (int size = componentCount; firstComponentId < size; firstComponentId++) {
1827             c = components[firstComponentId];
1828             if (c.endOffset > readerIndex) {
1829                 break;
1830             }
1831             c.free();
1832         }
1833
1834         // Replace the first readable component with a new slice.
1835         int trimmedBytes = readerIndex - c.offset;
1836         c.offset = 0;
1837         c.endOffset -= readerIndex;
1838         c.srcAdjustment += readerIndex;
1839         c.adjustment += readerIndex;
1840         ByteBuf slice = c.slice;
1841         if (slice != null) {
1842             // We must replace the cached slice with a derived one to ensure that
1843             // it can later be released properly in the case of PooledSlicedByteBuf.
1844             c.slice = slice.slice(trimmedBytes, c.length());
1845         }
1846         Component la = lastAccessed;
1847         if (la != null && la.endOffset <= readerIndex) {
1848             lastAccessed = null;
1849         }
1850
1851         removeCompRange(0, firstComponentId);
1852
1853         // Update indexes and markers.
1854         updateComponentOffsets(0);
1855         setIndex(0, writerIndex - readerIndex);
1856         adjustMarkers(readerIndex);
1857         return this;
1858     }
1859
1860     private ByteBuf allocBuffer(int capacity) {
1861         return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
1862     }
1863
1864     @Override
1865     public String toString() {
1866         String result = super.toString();
1867         result = result.substring(0, result.length() - 1);
1868         return result + ", components=" + componentCount + ')';
1869     }
1870
1871     private static final class Component {
1872         final ByteBuf srcBuf; // the originally added buffer
1873         final ByteBuf buf; // srcBuf unwrapped zero or more times
1874
1875         int srcAdjustment; // index of the start of this CompositeByteBuf relative to srcBuf
1876         int adjustment; // index of the start of this CompositeByteBuf relative to buf
1877
1878         int offset; // offset of this component within this CompositeByteBuf
1879         int endOffset; // end offset of this component within this CompositeByteBuf
1880
1881         private ByteBuf slice; // cached slice, may be null
1882
1883         Component(ByteBuf srcBuf, int srcOffset, ByteBuf buf, int bufOffset,
1884                 int offset, int len, ByteBuf slice) {
1885             this.srcBuf = srcBuf;
1886             this.srcAdjustment = srcOffset - offset;
1887             this.buf = buf;
1888             this.adjustment = bufOffset - offset;
1889             this.offset = offset;
1890             this.endOffset = offset + len;
1891             this.slice = slice;
1892         }
1893
1894         int srcIdx(int index) {
1895             return index + srcAdjustment;
1896         }
1897
1898         int idx(int index) {
1899             return index + adjustment;
1900         }
1901
1902         int length() {
1903             return endOffset - offset;
1904         }
1905
1906         void reposition(int newOffset) {
1907             int move = newOffset - offset;
1908             endOffset += move;
1909             srcAdjustment -= move;
1910             adjustment -= move;
1911             offset = newOffset;
1912         }
1913
1914         // copy then release
1915         void transferTo(ByteBuf dst) {
1916             dst.writeBytes(buf, idx(offset), length());
1917             free();
1918         }
1919
1920         ByteBuf slice() {
1921             ByteBuf s = slice;
1922             if (s == null) {
1923                 slice = s = srcBuf.slice(srcIdx(offset), length());
1924             }
1925             return s;
1926         }
1927
1928         ByteBuf duplicate() {
1929             return srcBuf.duplicate();
1930         }
1931
1932         ByteBuffer internalNioBuffer(int index, int length) {
1933             // Some buffers override this so we must use srcBuf
1934             return srcBuf.internalNioBuffer(srcIdx(index), length);
1935         }
1936
1937         void free() {
1938             slice = null;
1939             // Release the original buffer since it may have a different
1940             // refcount to the unwrapped buf (e.g. if PooledSlicedByteBuf)
1941             srcBuf.release();
1942         }
1943     }
1944
1945     @Override
1946     public CompositeByteBuf readerIndex(int readerIndex) {
1947         super.readerIndex(readerIndex);
1948         return this;
1949     }
1950
1951     @Override
1952     public CompositeByteBuf writerIndex(int writerIndex) {
1953         super.writerIndex(writerIndex);
1954         return this;
1955     }
1956
1957     @Override
1958     public CompositeByteBuf setIndex(int readerIndex, int writerIndex) {
1959         super.setIndex(readerIndex, writerIndex);
1960         return this;
1961     }
1962
1963     @Override
1964     public CompositeByteBuf clear() {
1965         super.clear();
1966         return this;
1967     }
1968
1969     @Override
1970     public CompositeByteBuf markReaderIndex() {
1971         super.markReaderIndex();
1972         return this;
1973     }
1974
1975     @Override
1976     public CompositeByteBuf resetReaderIndex() {
1977         super.resetReaderIndex();
1978         return this;
1979     }
1980
1981     @Override
1982     public CompositeByteBuf markWriterIndex() {
1983         super.markWriterIndex();
1984         return this;
1985     }
1986
1987     @Override
1988     public CompositeByteBuf resetWriterIndex() {
1989         super.resetWriterIndex();
1990         return this;
1991     }
1992
1993     @Override
1994     public CompositeByteBuf ensureWritable(int minWritableBytes) {
1995         super.ensureWritable(minWritableBytes);
1996         return this;
1997     }
1998
1999     @Override
2000     public CompositeByteBuf getBytes(int index, ByteBuf dst) {
2001         return getBytes(index, dst, dst.writableBytes());
2002     }
2003
2004     @Override
2005     public CompositeByteBuf getBytes(int index, ByteBuf dst, int length) {
2006         getBytes(index, dst, dst.writerIndex(), length);
2007         dst.writerIndex(dst.writerIndex() + length);
2008         return this;
2009     }
2010
2011     @Override
2012     public CompositeByteBuf getBytes(int index, byte[] dst) {
2013         return getBytes(index, dst, 0, dst.length);
2014     }
2015
2016     @Override
2017     public CompositeByteBuf setBoolean(int index, boolean value) {
2018         return setByte(index, value? 1 : 0);
2019     }
2020
2021     @Override
2022     public CompositeByteBuf setChar(int index, int value) {
2023         return setShort(index, value);
2024     }
2025
2026     @Override
2027     public CompositeByteBuf setFloat(int index, float value) {
2028         return setInt(index, Float.floatToRawIntBits(value));
2029     }
2030
2031     @Override
2032     public CompositeByteBuf setDouble(int index, double value) {
2033         return setLong(index, Double.doubleToRawLongBits(value));
2034     }
2035
2036     @Override
2037     public CompositeByteBuf setBytes(int index, ByteBuf src) {
2038         super.setBytes(index, src, src.readableBytes());
2039         return this;
2040     }
2041
2042     @Override
2043     public CompositeByteBuf setBytes(int index, ByteBuf src, int length) {
2044         super.setBytes(index, src, length);
2045         return this;
2046     }
2047
2048     @Override
2049     public CompositeByteBuf setBytes(int index, byte[] src) {
2050         return setBytes(index, src, 0, src.length);
2051     }
2052
2053     @Override
2054     public CompositeByteBuf setZero(int index, int length) {
2055         super.setZero(index, length);
2056         return this;
2057     }
2058
2059     @Override
2060     public CompositeByteBuf readBytes(ByteBuf dst) {
2061         super.readBytes(dst, dst.writableBytes());
2062         return this;
2063     }
2064
2065     @Override
2066     public CompositeByteBuf readBytes(ByteBuf dst, int length) {
2067         super.readBytes(dst, length);
2068         return this;
2069     }
2070
2071     @Override
2072     public CompositeByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
2073         super.readBytes(dst, dstIndex, length);
2074         return this;
2075     }
2076
2077     @Override
2078     public CompositeByteBuf readBytes(byte[] dst) {
2079         super.readBytes(dst, 0, dst.length);
2080         return this;
2081     }
2082
2083     @Override
2084     public CompositeByteBuf readBytes(byte[] dst, int dstIndex, int length) {
2085         super.readBytes(dst, dstIndex, length);
2086         return this;
2087     }
2088
2089     @Override
2090     public CompositeByteBuf readBytes(ByteBuffer dst) {
2091         super.readBytes(dst);
2092         return this;
2093     }
2094
2095     @Override
2096     public CompositeByteBuf readBytes(OutputStream out, int length) throws IOException {
2097         super.readBytes(out, length);
2098         return this;
2099     }
2100
2101     @Override
2102     public CompositeByteBuf skipBytes(int length) {
2103         super.skipBytes(length);
2104         return this;
2105     }
2106
2107     @Override
2108     public CompositeByteBuf writeBoolean(boolean value) {
2109         writeByte(value ? 1 : 0);
2110         return this;
2111     }
2112
2113     @Override
2114     public CompositeByteBuf writeByte(int value) {
2115         ensureWritable0(1);
2116         _setByte(writerIndex++, value);
2117         return this;
2118     }
2119
2120     @Override
2121     public CompositeByteBuf writeShort(int value) {
2122         super.writeShort(value);
2123         return this;
2124     }
2125
2126     @Override
2127     public CompositeByteBuf writeMedium(int value) {
2128         super.writeMedium(value);
2129         return this;
2130     }
2131
2132     @Override
2133     public CompositeByteBuf writeInt(int value) {
2134         super.writeInt(value);
2135         return this;
2136     }
2137
2138     @Override
2139     public CompositeByteBuf writeLong(long value) {
2140         super.writeLong(value);
2141         return this;
2142     }
2143
2144     @Override
2145     public CompositeByteBuf writeChar(int value) {
2146         super.writeShort(value);
2147         return this;
2148     }
2149
2150     @Override
2151     public CompositeByteBuf writeFloat(float value) {
2152         super.writeInt(Float.floatToRawIntBits(value));
2153         return this;
2154     }
2155
2156     @Override
2157     public CompositeByteBuf writeDouble(double value) {
2158         super.writeLong(Double.doubleToRawLongBits(value));
2159         return this;
2160     }
2161
2162     @Override
2163     public CompositeByteBuf writeBytes(ByteBuf src) {
2164         super.writeBytes(src, src.readableBytes());
2165         return this;
2166     }
2167
2168     @Override
2169     public CompositeByteBuf writeBytes(ByteBuf src, int length) {
2170         super.writeBytes(src, length);
2171         return this;
2172     }
2173
2174     @Override
2175     public CompositeByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
2176         super.writeBytes(src, srcIndex, length);
2177         return this;
2178     }
2179
2180     @Override
2181     public CompositeByteBuf writeBytes(byte[] src) {
2182         super.writeBytes(src, 0, src.length);
2183         return this;
2184     }
2185
2186     @Override
2187     public CompositeByteBuf writeBytes(byte[] src, int srcIndex, int length) {
2188         super.writeBytes(src, srcIndex, length);
2189         return this;
2190     }
2191
2192     @Override
2193     public CompositeByteBuf writeBytes(ByteBuffer src) {
2194         super.writeBytes(src);
2195         return this;
2196     }
2197
2198     @Override
2199     public CompositeByteBuf writeZero(int length) {
2200         super.writeZero(length);
2201         return this;
2202     }
2203
2204     @Override
2205     public CompositeByteBuf retain(int increment) {
2206         super.retain(increment);
2207         return this;
2208     }
2209
2210     @Override
2211     public CompositeByteBuf retain() {
2212         super.retain();
2213         return this;
2214     }
2215
2216     @Override
2217     public CompositeByteBuf touch() {
2218         return this;
2219     }
2220
2221     @Override
2222     public CompositeByteBuf touch(Object hint) {
2223         return this;
2224     }
2225
2226     @Override
2227     public ByteBuffer[] nioBuffers() {
2228         return nioBuffers(readerIndex(), readableBytes());
2229     }
2230
2231     @Override
2232     public CompositeByteBuf discardSomeReadBytes() {
2233         return discardReadComponents();
2234     }
2235
2236     @Override
2237     protected void deallocate() {
2238         if (freed) {
2239             return;
2240         }
2241
2242         freed = true;
2243         // We're not using foreach to avoid creating an iterator.
2244         // see https://github.com/netty/netty/issues/2642
2245         for (int i = 0, size = componentCount; i < size; i++) {
2246             components[i].free();
2247         }
2248     }
2249
2250     @Override
2251     boolean isAccessible() {
2252         return !freed;
2253     }
2254
2255     @Override
2256     public ByteBuf unwrap() {
2257         return null;
2258     }
2259
2260     private final class CompositeByteBufIterator implements Iterator<ByteBuf> {
2261         private final int size = numComponents();
2262         private int index;
2263
2264         @Override
2265         public boolean hasNext() {
2266             return size > index;
2267         }
2268
2269         @Override
2270         public ByteBuf next() {
2271             if (size != numComponents()) {
2272                 throw new ConcurrentModificationException();
2273             }
2274             if (!hasNext()) {
2275                 throw new NoSuchElementException();
2276             }
2277             try {
2278                 return components[index++].slice();
2279             } catch (IndexOutOfBoundsException e) {
2280                 throw new ConcurrentModificationException();
2281             }
2282         }
2283
2284         @Override
2285         public void remove() {
2286             throw new UnsupportedOperationException("Read-Only");
2287         }
2288     }
2289
2290     // Component array manipulation - range checking omitted
2291
2292     private void clearComps() {
2293         removeCompRange(0, componentCount);
2294     }
2295
2296     private void removeComp(int i) {
2297         removeCompRange(i, i + 1);
2298     }
2299
2300     private void removeCompRange(int from, int to) {
2301         if (from >= to) {
2302             return;
2303         }
2304         final int size = componentCount;
2305         assert from >= 0 && to <= size;
2306         if (to < size) {
2307             System.arraycopy(components, to, components, from, size - to);
2308         }
2309         int newSize = size - to + from;
2310         for (int i = newSize; i < size; i++) {
2311             components[i] = null;
2312         }
2313         componentCount = newSize;
2314     }
2315
2316     private void addComp(int i, Component c) {
2317         shiftComps(i, 1);
2318         components[i] = c;
2319     }
2320
2321     private void shiftComps(int i, int count) {
2322         final int size = componentCount, newSize = size + count;
2323         assert i >= 0 && i <= size && count > 0;
2324         if (newSize > components.length) {
2325             // grow the array
2326             int newArrSize = Math.max(size + (size >> 1), newSize);
2327             Component[] newArr;
2328             if (i == size) {
2329                 newArr = Arrays.copyOf(components, newArrSize, Component[].class);
2330             } else {
2331                 newArr = new Component[newArrSize];
2332                 if (i > 0) {
2333                     System.arraycopy(components, 0, newArr, 0, i);
2334                 }
2335                 if (i < size) {
2336                     System.arraycopy(components, i, newArr, i + count, size - i);
2337                 }
2338             }
2339             components = newArr;
2340         } else if (i < size) {
2341             System.arraycopy(components, i, components, i + count, size - i);
2342         }
2343         componentCount = newSize;
2344     }
2345 }
2346