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