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.Unpooled;
17 
18 import hunt.net.buffer.AbstractByteBuf;
19 import hunt.net.buffer.AbstractByteBufAllocator;
20 import hunt.net.buffer.ByteBuf;
21 import hunt.net.buffer.ByteBufAllocator;
22 import hunt.net.buffer.ByteBufUtil;
23 import hunt.net.buffer.CompositeByteBuf;
24 import hunt.net.buffer.ReadOnlyByteBufferBuf;
25 import hunt.net.buffer.UnpooledByteBufAllocator;
26 import hunt.net.buffer.UnpooledHeapByteBuf;
27 
28 import hunt.Byte;
29 import hunt.io.ByteBuffer;
30 import hunt.Exceptions;
31 import hunt.logging;
32 import hunt.net.Exceptions;
33 import hunt.stream.Common;
34 import hunt.util.StringBuilder;
35 import hunt.text.Charset;
36 import hunt.util.ByteOrder;
37 
38 import std.conv;
39 import std.format;
40 import std.range;
41 import std.concurrency : initOnce;
42 
43 // import io.netty.buffer.CompositeByteBuf.ByteWrapper;
44 // import io.netty.util.internal.PlatformDependent;
45 
46 // import java.nio.ByteBuffer;
47 // import java.nio.ByteOrder;
48 // import java.nio.CharBuffer;
49 // import java.nio.charset.Charset;
50 // import java.util.Arrays;
51 
52 
53 /**
54  * Creates a new {@link ByteBuf} by allocating new space or by wrapping
55  * or copying existing byte arrays, byte buffers and a string.
56  *
57  * <h3>Use static import</h3>
58  * This classes is intended to be used with Java 5 static import statement:
59  *
60  * <pre>
61  * import static io.netty.buffer.{@link Unpooled}.*;
62  *
63  * {@link ByteBuf} heapBuffer    = buffer(128);
64  * {@link ByteBuf} directBuffer  = directBuffer(256);
65  * {@link ByteBuf} wrappedBuffer = wrappedBuffer(new byte[128], new byte[256]);
66  * {@link ByteBuf} copiedBuffer  = copiedBuffer({@link ByteBuffer}.allocate(128));
67  * </pre>
68  *
69  * <h3>Allocating a new buffer</h3>
70  *
71  * Three buffer types are provided out of the box.
72  *
73  * <ul>
74  * <li>{@link #buffer(int)} allocates a new fixed-capacity heap buffer.</li>
75  * <li>{@link #directBuffer(int)} allocates a new fixed-capacity direct buffer.</li>
76  * </ul>
77  *
78  * <h3>Creating a wrapped buffer</h3>
79  *
80  * Wrapped buffer is a buffer which is a view of one or more existing
81  * byte arrays and byte buffers.  Any changes in the content of the original
82  * array or buffer will be visible in the wrapped buffer.  Various wrapper
83  * methods are provided and their name is all {@code wrappedBuffer()}.
84  * You might want to take a look at the methods that accept varargs closely if
85  * you want to create a buffer which is composed of more than one array to
86  * reduce the number of memory copy.
87  *
88  * <h3>Creating a copied buffer</h3>
89  *
90  * Copied buffer is a deep copy of one or more existing byte arrays, byte
91  * buffers or a string.  Unlike a wrapped buffer, there's no shared data
92  * between the original data and the copied buffer.  Various copy methods are
93  * provided and their name is all {@code copiedBuffer()}.  It is also convenient
94  * to use this operation to merge multiple buffers into one buffer.
95  */
96 final class Unpooled {
97 
98     private static ByteBufAllocator ALLOC() {
99         __gshared ByteBufAllocator inst;
100         return initOnce!inst(UnpooledByteBufAllocator.DEFAULT());
101     }
102 
103     /**
104      * Big endian byte order.
105      */
106     enum ByteOrder BIG_ENDIAN = ByteOrder.BigEndian;
107 
108     /**
109      * Little endian byte order.
110      */
111     enum ByteOrder LITTLE_ENDIAN = ByteOrder.LittleEndian;
112 
113     /**
114      * A buffer whose capacity is {@code 0}.
115      */
116     static ByteBuf EMPTY_BUFFER() {
117         __gshared ByteBuf inst;
118         return initOnce!inst(ALLOC.buffer(0, 0));
119     }
120 
121     // static {
122     //     assert EMPTY_BUFFER instanceof EmptyByteBuf: "EMPTY_BUFFER must be an EmptyByteBuf.";
123     // }
124 
125     /**
126      * Creates a new big-endian heap buffer with reasonably small initial capacity, which
127      * expands its capacity boundlessly on demand.
128      */
129     static ByteBuf buffer() {
130         return ALLOC.heapBuffer();
131     }
132 
133     /**
134      * Creates a new big-endian direct buffer with reasonably small initial capacity, which
135      * expands its capacity boundlessly on demand.
136      */
137     static ByteBuf directBuffer() {
138         return ALLOC.directBuffer();
139     }
140 
141     /**
142      * Creates a new big-endian heap buffer with the specified {@code capacity}, which
143      * expands its capacity boundlessly on demand.  The new buffer's {@code readerIndex} and
144      * {@code writerIndex} are {@code 0}.
145      */
146     static ByteBuf buffer(size_t initialCapacity) {
147         return ALLOC.heapBuffer(cast(int)initialCapacity);
148     }
149 
150     /**
151      * Creates a new big-endian direct buffer with the specified {@code capacity}, which
152      * expands its capacity boundlessly on demand.  The new buffer's {@code readerIndex} and
153      * {@code writerIndex} are {@code 0}.
154      */
155     static ByteBuf directBuffer(size_t initialCapacity) {
156         return ALLOC.directBuffer(cast(int)initialCapacity);
157     }
158 
159     /**
160      * Creates a new big-endian heap buffer with the specified
161      * {@code initialCapacity}, that may grow up to {@code maxCapacity}
162      * The new buffer's {@code readerIndex} and {@code writerIndex} are
163      * {@code 0}.
164      */
165     static ByteBuf buffer(int initialCapacity, int maxCapacity) {
166         return ALLOC.heapBuffer(initialCapacity, maxCapacity);
167     }
168 
169     /**
170      * Creates a new big-endian direct buffer with the specified
171      * {@code initialCapacity}, that may grow up to {@code maxCapacity}.
172      * The new buffer's {@code readerIndex} and {@code writerIndex} are
173      * {@code 0}.
174      */
175     static ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
176         return ALLOC.directBuffer(initialCapacity, maxCapacity);
177     }
178 
179     /**
180      * Creates a new big-endian buffer which wraps the specified {@code array}.
181      * A modification on the specified array's content will be visible to the
182      * returned buffer.
183      */
184     static ByteBuf wrappedBuffer(byte[] array) {
185         if (array.length == 0) {
186             return EMPTY_BUFFER;
187         }
188         return new UnpooledHeapByteBuf(ALLOC, array, cast(int)array.length);
189     }
190 
191     /**
192      * Creates a new big-endian buffer which wraps the sub-region of the
193      * specified {@code array}.  A modification on the specified array's
194      * content will be visible to the returned buffer.
195      */
196     static ByteBuf wrappedBuffer(byte[] array, int offset, int length) {
197         if (length == 0) {
198             return EMPTY_BUFFER;
199         }
200 
201         if (offset == 0 && length == array.length) {
202             return wrappedBuffer(array);
203         }
204 
205         return wrappedBuffer(array).slice(offset, length);
206     }
207 
208     /**
209      * Creates a new buffer which wraps the specified NIO buffer's current
210      * slice.  A modification on the specified buffer's content will be
211      * visible to the returned buffer.
212      */
213     static ByteBuf wrappedBuffer(ByteBuffer buffer) {
214         if (!buffer.hasRemaining()) {
215             return EMPTY_BUFFER;
216         }
217         if (!buffer.isDirect() && buffer.hasArray()) {
218             ByteBuf b = wrappedBuffer(
219                     buffer.array(),
220                     buffer.arrayOffset() + buffer.position(),
221                     buffer.remaining());
222             // return .order(buffer.order());
223             return b;
224         } else {
225             if (buffer.isReadOnly()) {
226                 return new ReadOnlyByteBufferBuf(ALLOC, buffer);
227             }  else {
228                 implementationMissing(false);
229                 return null;
230                 // return new UnpooledDirectByteBuf(ALLOC, buffer, buffer.remaining());
231             }
232         }
233             
234         // if (!buffer.isDirect() && buffer.hasArray()) {
235         //     return wrappedBuffer(
236         //             buffer.array(),
237         //             buffer.arrayOffset() + buffer.position(),
238         //             buffer.remaining()).order(buffer.order());
239         // } else if (PlatformDependent.hasUnsafe()) {
240         //     if (buffer.isReadOnly()) {
241         //         if (buffer.isDirect()) {
242         //             return new ReadOnlyUnsafeDirectByteBuf(ALLOC, buffer);
243         //         } else {
244         //             return new ReadOnlyByteBufferBuf(ALLOC, buffer);
245         //         }
246         //     } else {
247         //         return new UnpooledUnsafeDirectByteBuf(ALLOC, buffer, buffer.remaining());
248         //     }
249         // } else {
250         //     if (buffer.isReadOnly()) {
251         //         return new ReadOnlyByteBufferBuf(ALLOC, buffer);
252         //     }  else {
253         //         return new UnpooledDirectByteBuf(ALLOC, buffer, buffer.remaining());
254         //     }
255         // }
256     }
257 
258     /**
259      * Creates a new buffer which wraps the specified memory address. If {@code doFree} is true the
260      * memoryAddress will automatically be freed once the reference count of the {@link ByteBuf} reaches {@code 0}.
261      */
262     // static ByteBuf wrappedBuffer(long memoryAddress, int size, bool doFree) {
263     //     return new WrappedUnpooledUnsafeDirectByteBuf(ALLOC, memoryAddress, size, doFree);
264     // }
265 
266     /**
267      * Creates a new buffer which wraps the specified buffer's readable bytes.
268      * A modification on the specified buffer's content will be visible to the
269      * returned buffer.
270      * @param buffer The buffer to wrap. Reference count ownership of this variable is transferred to this method.
271      * @return The readable portion of the {@code buffer}, or an empty buffer if there is no readable portion.
272      * The caller is responsible for releasing this buffer.
273      */
274     static ByteBuf wrappedBuffer(ByteBuf buffer) {
275         if (buffer.isReadable()) {
276             return buffer.slice();
277         } else {
278             buffer.release();
279             return EMPTY_BUFFER;
280         }
281     }
282 
283     /**
284      * Creates a new big-endian composite buffer which wraps the specified
285      * arrays without copying them.  A modification on the specified arrays'
286      * content will be visible to the returned buffer.
287      */
288     static ByteBuf wrappedBuffer(byte[][] arrays... ) {
289         return wrappedBuffer(cast(int)arrays.length, arrays);
290     }
291 
292     /**
293      * Creates a new big-endian composite buffer which wraps the readable bytes of the
294      * specified buffers without copying them.  A modification on the content
295      * of the specified buffers will be visible to the returned buffer.
296      * @param buffers The buffers to wrap. Reference count ownership of all variables is transferred to this method.
297      * @return The readable portion of the {@code buffers}. The caller is responsible for releasing this buffer.
298      */
299     static ByteBuf wrappedBuffer(ByteBuf[] buffers...) {
300         return wrappedBuffer(cast(int)buffers.length, buffers);
301     }
302 
303     /**
304      * Creates a new big-endian composite buffer which wraps the slices of the specified
305      * NIO buffers without copying them.  A modification on the content of the
306      * specified buffers will be visible to the returned buffer.
307      */
308     static ByteBuf wrappedBuffer(ByteBuffer[] buffers...) {
309         return wrappedBuffer(cast(int)buffers.length, buffers);
310     }
311 
312     static ByteBuf wrappedBuffer(T)(int maxNumComponents, ByteWrapper!(T) wrapper, T[] array) {
313         switch (array.length) {
314         case 0:
315             break;
316         case 1:
317             if (!wrapper.isEmpty(array[0])) {
318                 return wrapper.wrap(array[0]);
319             }
320             break;
321         default:
322             for (int i = 0, len = cast(int)array.length; i < len; i++) {
323                 T bytes = array[i];
324                 if (bytes is null) {
325                     return EMPTY_BUFFER;
326                 }
327                 if (!wrapper.isEmpty(bytes)) {
328                     return new CompositeByteBuf(ALLOC, false, maxNumComponents, wrapper, array, i);
329                 }
330             }
331         }
332 
333         return EMPTY_BUFFER;
334     }
335 
336     /**
337      * Creates a new big-endian composite buffer which wraps the specified
338      * arrays without copying them.  A modification on the specified arrays'
339      * content will be visible to the returned buffer.
340      */
341     static ByteBuf wrappedBuffer(int maxNumComponents, byte[][] arrays...) {
342         return wrappedBuffer(maxNumComponents, CompositeByteBuf.BYTE_ARRAY_WRAPPER, arrays);
343     }
344 
345     /**
346      * Creates a new big-endian composite buffer which wraps the readable bytes of the
347      * specified buffers without copying them.  A modification on the content
348      * of the specified buffers will be visible to the returned buffer.
349      * @param maxNumComponents Advisement as to how many independent buffers are allowed to exist before
350      * consolidation occurs.
351      * @param buffers The buffers to wrap. Reference count ownership of all variables is transferred to this method.
352      * @return The readable portion of the {@code buffers}. The caller is responsible for releasing this buffer.
353      */
354     static ByteBuf wrappedBuffer(int maxNumComponents, ByteBuf[] buffers...) {
355         switch (buffers.length) {
356         case 0:
357             break;
358         case 1:
359             ByteBuf buffer = buffers[0];
360             if (buffer.isReadable()) {
361                 return wrappedBuffer(buffer); // .order(BIG_ENDIAN)
362             } else {
363                 buffer.release();
364             }
365             break;
366         default:
367             for (int i = 0; i < buffers.length; i++) {
368                 ByteBuf buf = buffers[i];
369                 if (buf.isReadable()) {
370                     return new CompositeByteBuf(ALLOC, false, maxNumComponents, buffers, i);
371                 }
372                 buf.release();
373             }
374             break;
375         }
376         return EMPTY_BUFFER;
377     }
378 
379     /**
380      * Creates a new big-endian composite buffer which wraps the slices of the specified
381      * NIO buffers without copying them.  A modification on the content of the
382      * specified buffers will be visible to the returned buffer.
383      */
384     static ByteBuf wrappedBuffer(int maxNumComponents, ByteBuffer[] buffers... ) {
385         return wrappedBuffer(maxNumComponents, CompositeByteBuf.BYTE_BUFFER_WRAPPER, buffers);
386     }
387 
388     /**
389      * Returns a new big-endian composite buffer with no components.
390      */
391     static CompositeByteBuf compositeBuffer() {
392         return compositeBuffer(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS);
393     }
394 
395     /**
396      * Returns a new big-endian composite buffer with no components.
397      */
398     static CompositeByteBuf compositeBuffer(int maxNumComponents) {
399         return new CompositeByteBuf(ALLOC, false, maxNumComponents);
400     }
401 
402     /**
403      * Creates a new big-endian buffer whose content is a copy of the
404      * specified {@code array}.  The new buffer's {@code readerIndex} and
405      * {@code writerIndex} are {@code 0} and {@code array.length} respectively.
406      */
407     static ByteBuf copiedBuffer(byte[] array) {
408         if (array.length == 0) {
409             return EMPTY_BUFFER;
410         }
411         return wrappedBuffer(array.dup);
412     }
413 
414     /**
415      * Creates a new big-endian buffer whose content is a copy of the
416      * specified {@code array}'s sub-region.  The new buffer's
417      * {@code readerIndex} and {@code writerIndex} are {@code 0} and
418      * the specified {@code length} respectively.
419      */
420     static ByteBuf copiedBuffer(byte[] array, int offset, int length) {
421         if (length == 0) {
422             return EMPTY_BUFFER;
423         }
424         // byte[] copy = PlatformDependent.allocateUninitializedArray(length);
425         // System.arraycopy(array, offset, copy, 0, length);
426         byte[] copy = array[offset .. offset+length].dup;
427         return wrappedBuffer(copy);
428     }
429 
430     /**
431      * Creates a new buffer whose content is a copy of the specified
432      * {@code buffer}'s current slice.  The new buffer's {@code readerIndex}
433      * and {@code writerIndex} are {@code 0} and {@code buffer.remaining}
434      * respectively.
435      */
436     static ByteBuf copiedBuffer(ByteBuffer buffer) {
437         int length = buffer.remaining();
438         if (length == 0) {
439             return EMPTY_BUFFER;
440         }
441         byte[] copy = new byte[length]; // PlatformDependent.allocateUninitializedArray(length);
442         // Duplicate the buffer so we not adjust the position during our get operation.
443         // See https://github.com/netty/netty/issues/3896
444         ByteBuffer duplicate = buffer.duplicate();
445         duplicate.get(copy);
446         return wrappedBuffer(copy); // .order(duplicate.order())
447     }
448 
449     /**
450      * Creates a new buffer whose content is a copy of the specified
451      * {@code buffer}'s readable bytes.  The new buffer's {@code readerIndex}
452      * and {@code writerIndex} are {@code 0} and {@code buffer.readableBytes}
453      * respectively.
454      */
455     static ByteBuf copiedBuffer(ByteBuf b) {
456         int readable = b.readableBytes();
457         if (readable > 0) {
458             ByteBuf copy = buffer(readable);
459             copy.writeBytes(b, b.readerIndex(), readable);
460             return copy;
461         } else {
462             return EMPTY_BUFFER;
463         }
464     }
465 
466     /**
467      * Creates a new big-endian buffer whose content is a merged copy of
468      * the specified {@code arrays}.  The new buffer's {@code readerIndex}
469      * and {@code writerIndex} are {@code 0} and the sum of all arrays'
470      * {@code length} respectively.
471      */
472     static ByteBuf copiedBuffer(byte[][] arrays...) {
473         switch (arrays.length) {
474             case 0:
475                 return EMPTY_BUFFER;
476             case 1:
477                 if (arrays[0].length == 0) {
478                     return EMPTY_BUFFER;
479                 } else {
480                     return copiedBuffer(arrays[0]);
481                 }
482             
483             default: 
484                 break; // do nothing
485         }
486 
487         // Merge the specified arrays into one array.
488         int length = 0;
489         foreach(byte[] a; arrays) {
490             if (int.max - length < a.length) {
491                 throw new IllegalArgumentException(
492                         "The total length of the specified arrays is too big.");
493             }
494             length += a.length;
495         }
496 
497         if (length == 0) {
498             return EMPTY_BUFFER;
499         }
500 
501         byte[] mergedArray = new byte[length]; 
502         for (size_t i = 0, j = 0; i < arrays.length; i ++) {
503             byte[] a = arrays[i];
504             // System.arraycopy(a, 0, mergedArray, j, a.length);
505             mergedArray[j .. j+a.length] = a[0 .. $];
506             j += a.length;
507         }
508 
509         return wrappedBuffer(mergedArray);
510     }
511 
512     /**
513      * Creates a new buffer whose content is a merged copy of the specified
514      * {@code buffers}' readable bytes.  The new buffer's {@code readerIndex}
515      * and {@code writerIndex} are {@code 0} and the sum of all buffers'
516      * {@code readableBytes} respectively.
517      *
518      * @throws IllegalArgumentException
519      *         if the specified buffers' endianness are different from each
520      *         other
521      */
522     static ByteBuf copiedBuffer(ByteBuf[] buffers...) {
523         switch (buffers.length) {
524             case 0:
525                 return EMPTY_BUFFER;
526             case 1:
527                 return copiedBuffer(buffers[0]);
528             default:
529                 break;
530         }
531 
532         // Merge the specified buffers into one buffer.
533         ByteOrder order;
534         bool detected = false;
535         int length = 0;
536         foreach(ByteBuf b; buffers) {
537             int bLen = b.readableBytes();
538             if (bLen <= 0) {
539                 continue;
540             }
541             if (int.max - length < bLen) {
542                 throw new IllegalArgumentException(
543                         "The total length of the specified buffers is too big.");
544             }
545             length += bLen;
546             if (detected) {
547                 if (order != b.order()) {
548                     throw new IllegalArgumentException("inconsistent byte order");
549                 }
550             } else {
551                 order = b.order();
552                 detected = true;
553             }
554         }
555 
556         if (length == 0) {
557             return EMPTY_BUFFER;
558         }
559 
560         byte[] mergedArray = new byte[length]; // PlatformDependent.allocateUninitializedArray(length);
561         for (int i = 0, j = 0; i < cast(int)buffers.length; i ++) {
562             ByteBuf b = buffers[i];
563             int bLen = b.readableBytes();
564             b.getBytes(b.readerIndex(), mergedArray, j, bLen);
565             j += bLen;
566         }
567 
568         return wrappedBuffer(mergedArray); //.order(order);
569     }
570 
571     /**
572      * Creates a new buffer whose content is a merged copy of the specified
573      * {@code buffers}' slices.  The new buffer's {@code readerIndex} and
574      * {@code writerIndex} are {@code 0} and the sum of all buffers'
575      * {@code remaining} respectively.
576      *
577      * @throws IllegalArgumentException
578      *         if the specified buffers' endianness are different from each
579      *         other
580      */
581     static ByteBuf copiedBuffer(ByteBuffer[] buffers...) {
582         switch (buffers.length) {
583             case 0:
584                 return EMPTY_BUFFER;
585             case 1:
586                 return copiedBuffer(buffers[0]);
587             default:
588                 break;
589         }
590 
591         // Merge the specified buffers into one buffer.
592         ByteOrder order;
593         bool isDetected = false;
594         int length = 0;
595         foreach(ByteBuffer b; buffers) {
596             int bLen = b.remaining();
597             if (bLen <= 0) {
598                 continue;
599             }
600             if (int.max - length < bLen) {
601                 throw new IllegalArgumentException(
602                         "The total length of the specified buffers is too big.");
603             }
604             length += bLen;
605             if (isDetected) {
606                 if (order != b.order()) {
607                     throw new IllegalArgumentException("inconsistent byte order");
608                 }
609             } else {
610                 order = b.order();
611                 isDetected = true;
612             }
613         }
614 
615         if (length == 0) {
616             return EMPTY_BUFFER;
617         }
618 
619         byte[] mergedArray = new byte[length]; // PlatformDependent.allocateUninitializedArray(length);
620         for (int i = 0, j = 0; i < buffers.length; i ++) {
621             // Duplicate the buffer so we not adjust the position during our get operation.
622             // See https://github.com/netty/netty/issues/3896
623             ByteBuffer b = buffers[i].duplicate();
624             int bLen = b.remaining();
625             b.get(mergedArray, j, bLen);
626             j += bLen;
627         }
628 
629         return wrappedBuffer(mergedArray); // .order(order);
630     }
631 
632     /**
633      * Creates a new big-endian buffer whose content is the specified
634      * {@code string} encoded in the specified {@code charset}.
635      * The new buffer's {@code readerIndex} and {@code writerIndex} are
636      * {@code 0} and the length of the encoded string respectively.
637      */
638     static ByteBuf copiedBuffer(CharSequence data, Charset charset) {
639         if (data.empty()) {
640             throw new NullPointerException("data");
641         }
642 
643         return copiedBuffer(cast(char[])data, charset);
644         // FIXME: Needing refactor or cleanup -@zxp at 8/20/2019, 6:39:37 PM
645         // 
646         // if (string instanceof CharBuffer) {
647         //     return copiedBuffer((CharBuffer) string, charset);
648         // }
649 
650         // return copiedBuffer(CharBuffer.wrap(data), charset);
651     }
652 
653     /**
654      * Creates a new big-endian buffer whose content is a subregion of
655      * the specified {@code string} encoded in the specified {@code charset}.
656      * The new buffer's {@code readerIndex} and {@code writerIndex} are
657      * {@code 0} and the length of the encoded string respectively.
658      */
659     // static ByteBuf copiedBuffer(
660     //         CharSequence string, int offset, int length, Charset charset) {
661     //     if (string is null) {
662     //         throw new NullPointerException("string");
663     //     }
664     //     if (length == 0) {
665     //         return EMPTY_BUFFER;
666     //     }
667 
668     //     if (string instanceof CharBuffer) {
669     //         CharBuffer buf = (CharBuffer) string;
670     //         if (buf.hasArray()) {
671     //             return copiedBuffer(
672     //                     buf.array(),
673     //                     buf.arrayOffset() + buf.position() + offset,
674     //                     length, charset);
675     //         }
676 
677     //         buf = buf.slice();
678     //         buf.limit(length);
679     //         buf.position(offset);
680     //         return copiedBuffer(buf, charset);
681     //     }
682 
683     //     return copiedBuffer(CharBuffer.wrap(string, offset, offset + length), charset);
684     // }
685 
686     /**
687      * Creates a new big-endian buffer whose content is the specified
688      * {@code array} encoded in the specified {@code charset}.
689      * The new buffer's {@code readerIndex} and {@code writerIndex} are
690      * {@code 0} and the length of the encoded string respectively.
691      */
692     static ByteBuf copiedBuffer(char[] array, Charset charset) {
693         if (array is null) {
694             throw new NullPointerException("array");
695         }
696         return copiedBuffer(array, 0, array.length, charset);
697     }
698 
699     /**
700      * Creates a new big-endian buffer whose content is a subregion of
701      * the specified {@code array} encoded in the specified {@code charset}.
702      * The new buffer's {@code readerIndex} and {@code writerIndex} are
703      * {@code 0} and the length of the encoded string respectively.
704      */
705     static ByteBuf copiedBuffer(char[] array, size_t offset, size_t length, Charset charset) {
706         if (array is null) {
707             throw new NullPointerException("array");
708         }
709         if (length == 0) {
710             return EMPTY_BUFFER;
711         }
712         // return copiedBuffer(CharBuffer.wrap(array, offset, length), charset);
713         //ALLOC.wrap()
714         
715         return wrappedBuffer(cast(byte[])array[offset .. offset + length].dup);
716     }
717 
718     // private static ByteBuf copiedBuffer(CharBuffer buffer, Charset charset) {
719     //     return ByteBufUtil.encodeString0(ALLOC, true, buffer, charset, 0);
720     // }
721 
722     /**
723      * Creates a read-only buffer which disallows any modification operations
724      * on the specified {@code buffer}.  The new buffer has the same
725      * {@code readerIndex} and {@code writerIndex} with the specified
726      * {@code buffer}.
727      *
728      * deprecated("") Use {@link ByteBuf#asReadOnly()}.
729      */
730     // deprecated("")
731     // static ByteBuf unmodifiableBuffer(ByteBuf buffer) {
732     //     ByteOrder endianness = buffer.order();
733     //     if (endianness == ByteOrder.BigEndian) {
734     //         return new ReadOnlyByteBuf(buffer);
735     //     }
736 
737     //     return new ReadOnlyByteBuf(buffer.order(BIG_ENDIAN)).order(LITTLE_ENDIAN);
738     // }
739 
740     /**
741      * Creates a new 4-byte big-endian buffer that holds the specified 32-bit integer.
742      */
743     static ByteBuf copyInt(int value) {
744         ByteBuf buf = buffer(4);
745         buf.writeInt(value);
746         return buf;
747     }
748 
749     /**
750      * Create a big-endian buffer that holds a sequence of the specified 32-bit integers.
751      */
752     static ByteBuf copyInt(int[] values...) {
753         if (values is null || values.length == 0) {
754             return EMPTY_BUFFER;
755         }
756         ByteBuf buffer = buffer(cast(int)values.length * 4);
757         foreach(int v; values) {
758             buffer.writeInt(v);
759         }
760         return buffer;
761     }
762 
763     /**
764      * Creates a new 2-byte big-endian buffer that holds the specified 16-bit integer.
765      */
766     // static ByteBuf copyShort(int value) {
767     //     ByteBuf buf = buffer(2);
768     //     buf.writeShort(value);
769     //     return buf;
770     // }
771 
772     /**
773      * Create a new big-endian buffer that holds a sequence of the specified 16-bit integers.
774      */
775     // static ByteBuf copyShort(short[] values...) {
776     //     if (values is null || values.length == 0) {
777     //         return EMPTY_BUFFER;
778     //     }
779     //     ByteBuf buffer = buffer(cast(int)values.length * 2);
780     //     foreach(int v; values) {
781     //         buffer.writeShort(v);
782     //     }
783     //     return buffer;
784     // }
785 
786     /**
787      * Create a new big-endian buffer that holds a sequence of the specified 16-bit integers.
788      */
789     static ByteBuf copyShort(int[] values...) {
790         if (values is null || values.length == 0) {
791             return EMPTY_BUFFER;
792         }
793         ByteBuf buffer = buffer(cast(int)values.length * 2);
794         foreach(int v; values) {
795             buffer.writeShort(v);
796         }
797         return buffer;
798     }
799 
800     /**
801      * Creates a new 3-byte big-endian buffer that holds the specified 24-bit integer.
802      */
803     static ByteBuf copyMedium(int value) {
804         ByteBuf buf = buffer(3);
805         buf.writeMedium(value);
806         return buf;
807     }
808 
809     /**
810      * Create a new big-endian buffer that holds a sequence of the specified 24-bit integers.
811      */
812     static ByteBuf copyMedium(int[] values...) {
813         if (values is null || values.length == 0) {
814             return EMPTY_BUFFER;
815         }
816         ByteBuf buffer = buffer(cast(int)values.length * 3);
817         foreach(int v; values) {
818             buffer.writeMedium(v);
819         }
820         return buffer;
821     }
822 
823     /**
824      * Creates a new 8-byte big-endian buffer that holds the specified 64-bit integer.
825      */
826     // static ByteBuf copyLong(long value) {
827     //     ByteBuf buf = buffer(8);
828     //     buf.writeLong(value);
829     //     return buf;
830     // }
831 
832     /**
833      * Create a new big-endian buffer that holds a sequence of the specified 64-bit integers.
834      */
835     static ByteBuf copyLong(long[] values...) {
836         if (values is null || values.length == 0) {
837             return EMPTY_BUFFER;
838         }
839         ByteBuf buffer = buffer(cast(int)values.length * 8);
840         foreach(long v; values) {
841             buffer.writeLong(v);
842         }
843         return buffer;
844     }
845 
846     /**
847      * Creates a new single-byte big-endian buffer that holds the specified bool value.
848      */
849     static ByteBuf copyBoolean(bool value) {
850         ByteBuf buf = buffer(1);
851         buf.writeBoolean(value);
852         return buf;
853     }
854 
855     /**
856      * Create a new big-endian buffer that holds a sequence of the specified bool values.
857      */
858     static ByteBuf copyBoolean(bool[] values...) {
859         if (values is null || values.length == 0) {
860             return EMPTY_BUFFER;
861         }
862         ByteBuf buffer = buffer(values.length);
863         foreach(bool v; values) {
864             buffer.writeBoolean(v);
865         }
866         return buffer;
867     }
868 
869     /**
870      * Creates a new 4-byte big-endian buffer that holds the specified 32-bit floating point number.
871      */
872     // static ByteBuf copyFloat(float value) {
873     //     ByteBuf buf = buffer(4);
874     //     buf.writeFloat(value);
875     //     return buf;
876     // }
877 
878     /**
879      * Create a new big-endian buffer that holds a sequence of the specified 32-bit floating point numbers.
880      */
881     static ByteBuf copyFloat(float[] values...) {
882         if (values is null || values.length == 0) {
883             return EMPTY_BUFFER;
884         }
885         ByteBuf buffer = buffer(values.length * 4);
886         foreach(float v; values) {
887             buffer.writeFloat(v);
888         }
889         return buffer;
890     }
891 
892     /**
893      * Creates a new 8-byte big-endian buffer that holds the specified 64-bit floating point number.
894      */
895     // static ByteBuf copyDouble(double value) {
896     //     ByteBuf buf = buffer(8);
897     //     buf.writeDouble(value);
898     //     return buf;
899     // }
900 
901     /**
902      * Create a new big-endian buffer that holds a sequence of the specified 64-bit floating point numbers.
903      */
904     static ByteBuf copyDouble(double[] values...) {
905         if (values is null || values.length == 0) {
906             return EMPTY_BUFFER;
907         }
908         ByteBuf buffer = buffer(values.length * 8);
909         foreach(double v; values) {
910             buffer.writeDouble(v);
911         }
912         return buffer;
913     }
914 
915     /**
916      * Return a unreleasable view on the given {@link ByteBuf} which will just ignore release and retain calls.
917      */
918     // static ByteBuf unreleasableBuffer(ByteBuf buf) {
919     //     return new UnreleasableByteBuf(buf);
920     // }
921 
922     /**
923      * Wrap the given {@link ByteBuf}s in an unmodifiable {@link ByteBuf}. Be aware the returned {@link ByteBuf} will
924      * not try to slice the given {@link ByteBuf}s to reduce GC-Pressure.
925      *
926      * deprecated("") Use {@link #wrappedUnmodifiableBuffer(ByteBuf...)}.
927      */
928     // deprecated("")
929     // static ByteBuf unmodifiableBuffer(ByteBuf[] buffers...) {
930     //     return wrappedUnmodifiableBuffer(true, buffers);
931     // }
932 
933     /**
934      * Wrap the given {@link ByteBuf}s in an unmodifiable {@link ByteBuf}. Be aware the returned {@link ByteBuf} will
935      * not try to slice the given {@link ByteBuf}s to reduce GC-Pressure.
936      *
937      * The returned {@link ByteBuf} may wrap the provided array directly, and so should not be subsequently modified.
938      */
939     static ByteBuf wrappedUnmodifiableBuffer(ByteBuf[] buffers...) {
940         return wrappedUnmodifiableBuffer(false, buffers);
941     }
942 
943     private static ByteBuf wrappedUnmodifiableBuffer(bool copy, ByteBuf[] buffers...) {
944         switch (buffers.length) {
945             case 0:
946                 return EMPTY_BUFFER;
947             case 1:
948                 return buffers[0].asReadOnly();
949             default:
950                 ByteBuf[] bs = buffers;
951                 if (copy) {
952                     bs = buffers.dup;
953                     // buffers = Arrays.copyOf(buffers, buffers.length, ByteBuf[].class);
954                 }
955                 implementationMissing(false);
956                 return null;
957                 // return new FixedCompositeByteBuf(ALLOC, bs);
958         }
959     }
960 
961     private this() {
962         // Unused
963     }
964 }
965 
966 
967 
968 alias copiedBuffer = Unpooled.copiedBuffer;
969 alias copyInt = Unpooled.copyInt;
970 alias copyShort = Unpooled.copyShort;
971 alias copyMedium = Unpooled.copyMedium;
972 alias copyLong = Unpooled.copyLong;
973 alias copyBoolean = Unpooled.copyBoolean;
974 alias copyFloat = Unpooled.copyFloat;
975 alias copyDouble = Unpooled.copyDouble;
976 alias EMPTY_BUFFER = Unpooled.EMPTY_BUFFER;
977 alias wrappedUnmodifiableBuffer = Unpooled.wrappedUnmodifiableBuffer;
978 alias wrappedBuffer = Unpooled.wrappedBuffer;