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