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 }