View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.util.AsciiString;
19  import io.netty.util.ByteProcessor;
20  import io.netty.util.CharsetUtil;
21  import io.netty.util.IllegalReferenceCountException;
22  import io.netty.util.Recycler.EnhancedHandle;
23  import io.netty.util.ResourceLeakDetector;
24  import io.netty.util.concurrent.FastThreadLocal;
25  import io.netty.util.internal.MathUtil;
26  import io.netty.util.internal.ObjectPool;
27  import io.netty.util.internal.ObjectPool.Handle;
28  import io.netty.util.internal.ObjectPool.ObjectCreator;
29  import io.netty.util.internal.PlatformDependent;
30  import io.netty.util.internal.SWARUtil;
31  import io.netty.util.internal.StringUtil;
32  import io.netty.util.internal.SystemPropertyUtil;
33  import io.netty.util.internal.logging.InternalLogger;
34  import io.netty.util.internal.logging.InternalLoggerFactory;
35  
36  import java.io.IOException;
37  import java.io.OutputStream;
38  import java.nio.ByteBuffer;
39  import java.nio.ByteOrder;
40  import java.nio.CharBuffer;
41  import java.nio.charset.CharacterCodingException;
42  import java.nio.charset.Charset;
43  import java.nio.charset.CharsetDecoder;
44  import java.nio.charset.CharsetEncoder;
45  import java.nio.charset.CoderResult;
46  import java.nio.charset.CodingErrorAction;
47  import java.util.Arrays;
48  import java.util.Locale;
49  
50  import static io.netty.util.internal.MathUtil.isOutOfBounds;
51  import static io.netty.util.internal.ObjectUtil.checkNotNull;
52  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
53  import static io.netty.util.internal.StringUtil.NEWLINE;
54  import static io.netty.util.internal.StringUtil.isSurrogate;
55  
56  /**
57   * A collection of utility methods that is related with handling {@link ByteBuf},
58   * such as the generation of hex dump and swapping an integer's byte order.
59   */
60  public final class ByteBufUtil {
61  
62      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ByteBufUtil.class);
63      private static final FastThreadLocal<byte[]> BYTE_ARRAYS = new FastThreadLocal<byte[]>() {
64          @Override
65          protected byte[] initialValue() throws Exception {
66              return PlatformDependent.allocateUninitializedArray(MAX_TL_ARRAY_LEN);
67          }
68      };
69  
70      private static final byte WRITE_UTF_UNKNOWN = (byte) '?';
71      private static final int MAX_CHAR_BUFFER_SIZE;
72      private static final int THREAD_LOCAL_BUFFER_SIZE;
73      private static final int MAX_BYTES_PER_CHAR_UTF8 =
74              (int) CharsetUtil.encoder(CharsetUtil.UTF_8).maxBytesPerChar();
75  
76      static final int WRITE_CHUNK_SIZE = 8192;
77      static final ByteBufAllocator DEFAULT_ALLOCATOR;
78  
79      static {
80          String allocType = SystemPropertyUtil.get(
81                  "io.netty.allocator.type", "adaptive");
82  
83          ByteBufAllocator alloc;
84          if ("unpooled".equals(allocType)) {
85              alloc = UnpooledByteBufAllocator.DEFAULT;
86              logger.debug("-Dio.netty.allocator.type: {}", allocType);
87          } else if ("pooled".equals(allocType)) {
88              alloc = PooledByteBufAllocator.DEFAULT;
89              logger.debug("-Dio.netty.allocator.type: {}", allocType);
90          } else if ("adaptive".equals(allocType)) {
91              alloc = new AdaptiveByteBufAllocator();
92              logger.debug("-Dio.netty.allocator.type: {}", allocType);
93          } else {
94              alloc = PooledByteBufAllocator.DEFAULT;
95              logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
96          }
97  
98          DEFAULT_ALLOCATOR = alloc;
99  
100         THREAD_LOCAL_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalDirectBufferSize", 0);
101         logger.debug("-Dio.netty.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE);
102 
103         MAX_CHAR_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.maxThreadLocalCharBufferSize", 16 * 1024);
104         logger.debug("-Dio.netty.maxThreadLocalCharBufferSize: {}", MAX_CHAR_BUFFER_SIZE);
105     }
106 
107     static final int MAX_TL_ARRAY_LEN = 1024;
108 
109     /**
110      * Allocates a new array if minLength > {@link ByteBufUtil#MAX_TL_ARRAY_LEN}
111      */
112     static byte[] threadLocalTempArray(int minLength) {
113         return minLength <= MAX_TL_ARRAY_LEN ? BYTE_ARRAYS.get()
114             : PlatformDependent.allocateUninitializedArray(minLength);
115     }
116 
117     /**
118      * @return whether the specified buffer has a nonzero ref count
119      */
120     public static boolean isAccessible(ByteBuf buffer) {
121         return buffer.isAccessible();
122     }
123 
124     /**
125      * @throws IllegalReferenceCountException if the buffer has a zero ref count
126      * @return the passed in buffer
127      */
128     public static ByteBuf ensureAccessible(ByteBuf buffer) {
129         if (!buffer.isAccessible()) {
130             throw new IllegalReferenceCountException(buffer.refCnt());
131         }
132         return buffer;
133     }
134 
135     /**
136      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
137      * of the specified buffer's readable bytes.
138      */
139     public static String hexDump(ByteBuf buffer) {
140         return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
141     }
142 
143     /**
144      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
145      * of the specified buffer's sub-region.
146      */
147     public static String hexDump(ByteBuf buffer, int fromIndex, int length) {
148         return HexUtil.hexDump(buffer, fromIndex, length);
149     }
150 
151     /**
152      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
153      * of the specified byte array.
154      */
155     public static String hexDump(byte[] array) {
156         return hexDump(array, 0, array.length);
157     }
158 
159     /**
160      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
161      * of the specified byte array's sub-region.
162      */
163     public static String hexDump(byte[] array, int fromIndex, int length) {
164         return HexUtil.hexDump(array, fromIndex, length);
165     }
166 
167     /**
168      * Decode a 2-digit hex byte from within a string.
169      */
170     public static byte decodeHexByte(CharSequence s, int pos) {
171         return StringUtil.decodeHexByte(s, pos);
172     }
173 
174     /**
175      * Decodes a string generated by {@link #hexDump(byte[])}
176      */
177     public static byte[] decodeHexDump(CharSequence hexDump) {
178         return StringUtil.decodeHexDump(hexDump, 0, hexDump.length());
179     }
180 
181     /**
182      * Decodes part of a string generated by {@link #hexDump(byte[])}
183      */
184     public static byte[] decodeHexDump(CharSequence hexDump, int fromIndex, int length) {
185         return StringUtil.decodeHexDump(hexDump, fromIndex, length);
186     }
187 
188     /**
189      * Used to determine if the return value of {@link ByteBuf#ensureWritable(int, boolean)} means that there is
190      * adequate space and a write operation will succeed.
191      * @param ensureWritableResult The return value from {@link ByteBuf#ensureWritable(int, boolean)}.
192      * @return {@code true} if {@code ensureWritableResult} means that there is adequate space and a write operation
193      * will succeed.
194      */
195     public static boolean ensureWritableSuccess(int ensureWritableResult) {
196         return ensureWritableResult == 0 || ensureWritableResult == 2;
197     }
198 
199     /**
200      * Calculates the hash code of the specified buffer.  This method is
201      * useful when implementing a new buffer type.
202      */
203     public static int hashCode(ByteBuf buffer) {
204         final int aLen = buffer.readableBytes();
205         final int intCount = aLen >>> 2;
206         final int byteCount = aLen & 3;
207 
208         int hashCode = EmptyByteBuf.EMPTY_BYTE_BUF_HASH_CODE;
209         int arrayIndex = buffer.readerIndex();
210         if (buffer.order() == ByteOrder.BIG_ENDIAN) {
211             for (int i = intCount; i > 0; i --) {
212                 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
213                 arrayIndex += 4;
214             }
215         } else {
216             for (int i = intCount; i > 0; i --) {
217                 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
218                 arrayIndex += 4;
219             }
220         }
221 
222         for (int i = byteCount; i > 0; i --) {
223             hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
224         }
225 
226         if (hashCode == 0) {
227             hashCode = 1;
228         }
229 
230         return hashCode;
231     }
232 
233     /**
234      * Returns the reader index of needle in haystack, or -1 if needle is not in haystack.
235      * This method uses the <a href="https://en.wikipedia.org/wiki/Two-way_string-matching_algorithm">Two-Way
236      * string matching algorithm</a>, which yields O(1) space complexity and excellent performance.
237      */
238     public static int indexOf(ByteBuf needle, ByteBuf haystack) {
239         if (haystack == null || needle == null) {
240             return -1;
241         }
242 
243         if (needle.readableBytes() > haystack.readableBytes()) {
244             return -1;
245         }
246 
247         int n = haystack.readableBytes();
248         int m = needle.readableBytes();
249         if (m == 0) {
250             return 0;
251         }
252 
253         // When the needle has only one byte that can be read,
254         // the ByteBuf.indexOf() can be used
255         if (m == 1) {
256             return haystack.indexOf(haystack.readerIndex(), haystack.writerIndex(),
257                           needle.getByte(needle.readerIndex()));
258         }
259 
260         int i;
261         int j = 0;
262         int aStartIndex = needle.readerIndex();
263         int bStartIndex = haystack.readerIndex();
264         long suffixes =  maxSuf(needle, m, aStartIndex, true);
265         long prefixes = maxSuf(needle, m, aStartIndex, false);
266         int ell = Math.max((int) (suffixes >> 32), (int) (prefixes >> 32));
267         int per = Math.max((int) suffixes, (int) prefixes);
268         int memory;
269         int length = Math.min(m - per, ell + 1);
270 
271         if (equals(needle, aStartIndex, needle, aStartIndex + per,  length)) {
272             memory = -1;
273             while (j <= n - m) {
274                 i = Math.max(ell, memory) + 1;
275                 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
276                     ++i;
277                 }
278                 if (i > n) {
279                     return -1;
280                 }
281                 if (i >= m) {
282                     i = ell;
283                     while (i > memory && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
284                         --i;
285                     }
286                     if (i <= memory) {
287                         return j + bStartIndex;
288                     }
289                     j += per;
290                     memory = m - per - 1;
291                 } else {
292                     j += i - ell;
293                     memory = -1;
294                 }
295             }
296         } else {
297             per = Math.max(ell + 1, m - ell - 1) + 1;
298             while (j <= n - m) {
299                 i = ell + 1;
300                 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
301                     ++i;
302                 }
303                 if (i > n) {
304                     return -1;
305                 }
306                 if (i >= m) {
307                     i = ell;
308                     while (i >= 0 && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
309                         --i;
310                     }
311                     if (i < 0) {
312                         return j + bStartIndex;
313                     }
314                     j += per;
315                 } else {
316                     j += i - ell;
317                 }
318             }
319         }
320         return -1;
321     }
322 
323     private static long maxSuf(ByteBuf x, int m, int start, boolean isSuffix) {
324         int p = 1;
325         int ms = -1;
326         int j = start;
327         int k = 1;
328         byte a;
329         byte b;
330         while (j + k < m) {
331             a = x.getByte(j + k);
332             b = x.getByte(ms + k);
333             boolean suffix = isSuffix ? a < b : a > b;
334             if (suffix) {
335                 j += k;
336                 k = 1;
337                 p = j - ms;
338             } else if (a == b) {
339                 if (k != p) {
340                     ++k;
341                 } else {
342                     j += p;
343                     k = 1;
344                 }
345             } else {
346                 ms = j;
347                 j = ms + 1;
348                 k = p = 1;
349             }
350         }
351         return ((long) ms << 32) + p;
352     }
353 
354     /**
355      * Returns {@code true} if and only if the two specified buffers are
356      * identical to each other for {@code length} bytes starting at {@code aStartIndex}
357      * index for the {@code a} buffer and {@code bStartIndex} index for the {@code b} buffer.
358      * A more compact way to express this is:
359      * <p>
360      * {@code a[aStartIndex : aStartIndex + length] == b[bStartIndex : bStartIndex + length]}
361      */
362     public static boolean equals(ByteBuf a, int aStartIndex, ByteBuf b, int bStartIndex, int length) {
363         checkNotNull(a, "a");
364         checkNotNull(b, "b");
365         // All indexes and lengths must be non-negative
366         checkPositiveOrZero(aStartIndex, "aStartIndex");
367         checkPositiveOrZero(bStartIndex, "bStartIndex");
368         checkPositiveOrZero(length, "length");
369 
370         if (a.writerIndex() - length < aStartIndex || b.writerIndex() - length < bStartIndex) {
371             return false;
372         }
373 
374         final int longCount = length >>> 3;
375         final int byteCount = length & 7;
376 
377         if (a.order() == b.order()) {
378             for (int i = longCount; i > 0; i --) {
379                 if (a.getLong(aStartIndex) != b.getLong(bStartIndex)) {
380                     return false;
381                 }
382                 aStartIndex += 8;
383                 bStartIndex += 8;
384             }
385         } else {
386             for (int i = longCount; i > 0; i --) {
387                 if (a.getLong(aStartIndex) != swapLong(b.getLong(bStartIndex))) {
388                     return false;
389                 }
390                 aStartIndex += 8;
391                 bStartIndex += 8;
392             }
393         }
394 
395         for (int i = byteCount; i > 0; i --) {
396             if (a.getByte(aStartIndex) != b.getByte(bStartIndex)) {
397                 return false;
398             }
399             aStartIndex ++;
400             bStartIndex ++;
401         }
402 
403         return true;
404     }
405 
406     /**
407      * Returns {@code true} if and only if the two specified buffers are
408      * identical to each other as described in {@link ByteBuf#equals(Object)}.
409      * This method is useful when implementing a new buffer type.
410      */
411     public static boolean equals(ByteBuf bufferA, ByteBuf bufferB) {
412         if (bufferA == bufferB) {
413             return true;
414         }
415         final int aLen = bufferA.readableBytes();
416         if (aLen != bufferB.readableBytes()) {
417             return false;
418         }
419         return equals(bufferA, bufferA.readerIndex(), bufferB, bufferB.readerIndex(), aLen);
420     }
421 
422     /**
423      * Compares the two specified buffers as described in {@link ByteBuf#compareTo(ByteBuf)}.
424      * This method is useful when implementing a new buffer type.
425      */
426     public static int compare(ByteBuf bufferA, ByteBuf bufferB) {
427         if (bufferA == bufferB) {
428             return 0;
429         }
430         final int aLen = bufferA.readableBytes();
431         final int bLen = bufferB.readableBytes();
432         final int minLength = Math.min(aLen, bLen);
433         final int uintCount = minLength >>> 2;
434         final int byteCount = minLength & 3;
435         int aIndex = bufferA.readerIndex();
436         int bIndex = bufferB.readerIndex();
437 
438         if (uintCount > 0) {
439             boolean bufferAIsBigEndian = bufferA.order() == ByteOrder.BIG_ENDIAN;
440             final long res;
441             int uintCountIncrement = uintCount << 2;
442 
443             if (bufferA.order() == bufferB.order()) {
444                 res = bufferAIsBigEndian ? compareUintBigEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
445                         compareUintLittleEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
446             } else {
447                 res = bufferAIsBigEndian ? compareUintBigEndianA(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
448                         compareUintBigEndianB(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
449             }
450             if (res != 0) {
451                 // Ensure we not overflow when cast
452                 return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, res));
453             }
454             aIndex += uintCountIncrement;
455             bIndex += uintCountIncrement;
456         }
457 
458         for (int aEnd = aIndex + byteCount; aIndex < aEnd; ++aIndex, ++bIndex) {
459             int comp = bufferA.getUnsignedByte(aIndex) - bufferB.getUnsignedByte(bIndex);
460             if (comp != 0) {
461                 return comp;
462             }
463         }
464 
465         return aLen - bLen;
466     }
467 
468     private static long compareUintBigEndian(
469             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
470         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
471             long comp = bufferA.getUnsignedInt(aIndex) - bufferB.getUnsignedInt(bIndex);
472             if (comp != 0) {
473                 return comp;
474             }
475         }
476         return 0;
477     }
478 
479     private static long compareUintLittleEndian(
480             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
481         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
482             long comp = uintFromLE(bufferA.getUnsignedIntLE(aIndex)) - uintFromLE(bufferB.getUnsignedIntLE(bIndex));
483             if (comp != 0) {
484                 return comp;
485             }
486         }
487         return 0;
488     }
489 
490     private static long compareUintBigEndianA(
491             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
492         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
493             long a = bufferA.getUnsignedInt(aIndex);
494             long b = uintFromLE(bufferB.getUnsignedIntLE(bIndex));
495             long comp =  a - b;
496             if (comp != 0) {
497                 return comp;
498             }
499         }
500         return 0;
501     }
502 
503     private static long compareUintBigEndianB(
504             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
505         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
506             long a = uintFromLE(bufferA.getUnsignedIntLE(aIndex));
507             long b = bufferB.getUnsignedInt(bIndex);
508             long comp =  a - b;
509             if (comp != 0) {
510                 return comp;
511             }
512         }
513         return 0;
514     }
515 
516     private static long uintFromLE(long value) {
517         return Long.reverseBytes(value) >>> Integer.SIZE;
518     }
519 
520     private static int unrolledFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int byteCount, byte value) {
521         assert byteCount > 0 && byteCount < 8;
522         if (buffer._getByte(fromIndex) == value) {
523             return fromIndex;
524         }
525         if (byteCount == 1) {
526             return -1;
527         }
528         if (buffer._getByte(fromIndex + 1) == value) {
529             return fromIndex + 1;
530         }
531         if (byteCount == 2) {
532             return -1;
533         }
534         if (buffer._getByte(fromIndex + 2) == value) {
535             return fromIndex + 2;
536         }
537         if (byteCount == 3) {
538             return -1;
539         }
540         if (buffer._getByte(fromIndex + 3) == value) {
541             return fromIndex + 3;
542         }
543         if (byteCount == 4) {
544             return -1;
545         }
546         if (buffer._getByte(fromIndex + 4) == value) {
547             return fromIndex + 4;
548         }
549         if (byteCount == 5) {
550             return -1;
551         }
552         if (buffer._getByte(fromIndex + 5) == value) {
553             return fromIndex + 5;
554         }
555         if (byteCount == 6) {
556             return -1;
557         }
558         if (buffer._getByte(fromIndex + 6) == value) {
559             return fromIndex + 6;
560         }
561         return -1;
562     }
563 
564     /**
565      * This is using a SWAR (SIMD Within A Register) batch read technique to minimize bound-checks and improve memory
566      * usage while searching for {@code value}.
567      */
568     static int firstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
569         fromIndex = Math.max(fromIndex, 0);
570         if (fromIndex >= toIndex || buffer.capacity() == 0) {
571             return -1;
572         }
573         final int length = toIndex - fromIndex;
574         buffer.checkIndex(fromIndex, length);
575         if (!PlatformDependent.isUnaligned()) {
576             return linearFirstIndexOf(buffer, fromIndex, toIndex, value);
577         }
578         assert PlatformDependent.isUnaligned();
579         int offset = fromIndex;
580         final int byteCount = length & 7;
581         if (byteCount > 0) {
582             final int index = unrolledFirstIndexOf(buffer, fromIndex, byteCount, value);
583             if (index != -1) {
584                 return index;
585             }
586             offset += byteCount;
587             if (offset == toIndex) {
588                 return -1;
589             }
590         }
591         final int longCount = length >>> 3;
592         final ByteOrder nativeOrder = ByteOrder.nativeOrder();
593         final boolean isNative = nativeOrder == buffer.order();
594         final boolean useLE = nativeOrder == ByteOrder.LITTLE_ENDIAN;
595         final long pattern = SWARUtil.compilePattern(value);
596         for (int i = 0; i < longCount; i++) {
597             // use the faster available getLong
598             final long word = useLE? buffer._getLongLE(offset) : buffer._getLong(offset);
599             final long result = SWARUtil.applyPattern(word, pattern);
600             if (result != 0) {
601                 return offset + SWARUtil.getIndex(result, isNative);
602             }
603             offset += Long.BYTES;
604         }
605         return -1;
606     }
607 
608     private static int linearFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
609         for (int i = fromIndex; i < toIndex; i++) {
610             if (buffer._getByte(i) == value) {
611                 return i;
612             }
613         }
614         return -1;
615     }
616 
617     /**
618      * The default implementation of {@link ByteBuf#indexOf(int, int, byte)}.
619      * This method is useful when implementing a new buffer type.
620      */
621     public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value) {
622         return buffer.indexOf(fromIndex, toIndex, value);
623     }
624 
625     /**
626      * Toggles the endianness of the specified 16-bit short integer.
627      */
628     public static short swapShort(short value) {
629         return Short.reverseBytes(value);
630     }
631 
632     /**
633      * Toggles the endianness of the specified 24-bit medium integer.
634      */
635     public static int swapMedium(int value) {
636         int swapped = value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff;
637         if ((swapped & 0x800000) != 0) {
638             swapped |= 0xff000000;
639         }
640         return swapped;
641     }
642 
643     /**
644      * Toggles the endianness of the specified 32-bit integer.
645      */
646     public static int swapInt(int value) {
647         return Integer.reverseBytes(value);
648     }
649 
650     /**
651      * Toggles the endianness of the specified 64-bit long integer.
652      */
653     public static long swapLong(long value) {
654         return Long.reverseBytes(value);
655     }
656 
657     /**
658      * Writes a big-endian 16-bit short integer to the buffer.
659      */
660     @SuppressWarnings("deprecation")
661     public static ByteBuf writeShortBE(ByteBuf buf, int shortValue) {
662         return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeShort(shortValue) :
663                 buf.writeShort(swapShort((short) shortValue));
664     }
665 
666     /**
667      * Sets a big-endian 16-bit short integer to the buffer.
668      */
669     @SuppressWarnings("deprecation")
670     public static ByteBuf setShortBE(ByteBuf buf, int index, int shortValue) {
671         return buf.order() == ByteOrder.BIG_ENDIAN? buf.setShort(index, shortValue) :
672                 buf.setShort(index, swapShort((short) shortValue));
673     }
674 
675     /**
676      * Writes a big-endian 24-bit medium integer to the buffer.
677      */
678     @SuppressWarnings("deprecation")
679     public static ByteBuf writeMediumBE(ByteBuf buf, int mediumValue) {
680         return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeMedium(mediumValue) :
681                 buf.writeMedium(swapMedium(mediumValue));
682     }
683 
684     /**
685      * Reads a big-endian unsigned 16-bit short integer from the buffer.
686      */
687     @SuppressWarnings("deprecation")
688     public static int readUnsignedShortBE(ByteBuf buf) {
689         return buf.order() == ByteOrder.BIG_ENDIAN? buf.readUnsignedShort() :
690                 swapShort((short) buf.readUnsignedShort()) & 0xFFFF;
691     }
692 
693     /**
694      * Reads a big-endian 32-bit integer from the buffer.
695      */
696     @SuppressWarnings("deprecation")
697     public static int readIntBE(ByteBuf buf) {
698         return buf.order() == ByteOrder.BIG_ENDIAN? buf.readInt() :
699                 swapInt(buf.readInt());
700     }
701 
702     /**
703      * Read the given amount of bytes into a new {@link ByteBuf} that is allocated from the {@link ByteBufAllocator}.
704      */
705     public static ByteBuf readBytes(ByteBufAllocator alloc, ByteBuf buffer, int length) {
706         boolean release = true;
707         ByteBuf dst = alloc.buffer(length);
708         try {
709             buffer.readBytes(dst);
710             release = false;
711             return dst;
712         } finally {
713             if (release) {
714                 dst.release();
715             }
716         }
717     }
718 
719     static int lastIndexOf(final AbstractByteBuf buffer, int fromIndex, final int toIndex, final byte value) {
720         assert fromIndex > toIndex;
721         final int capacity = buffer.capacity();
722         fromIndex = Math.min(fromIndex, capacity);
723         if (fromIndex <= 0) { // fromIndex is the exclusive upper bound.
724             return -1;
725         }
726         final int length = fromIndex - toIndex;
727         buffer.checkIndex(toIndex, length);
728         if (!PlatformDependent.isUnaligned()) {
729             return linearLastIndexOf(buffer, fromIndex, toIndex, value);
730         }
731         final int longCount = length >>> 3;
732         if (longCount > 0) {
733             final ByteOrder nativeOrder = ByteOrder.nativeOrder();
734             final boolean isNative = nativeOrder == buffer.order();
735             final boolean useLE = nativeOrder == ByteOrder.LITTLE_ENDIAN;
736             final long pattern = SWARUtil.compilePattern(value);
737             for (int i = 0, offset = fromIndex - Long.BYTES; i < longCount; i++, offset -= Long.BYTES) {
738                 // use the faster available getLong
739                 final long word = useLE? buffer._getLongLE(offset) : buffer._getLong(offset);
740                 final long result = SWARUtil.applyPattern(word, pattern);
741                 if (result != 0) {
742                     // used the oppoiste endianness since we are looking for the last index.
743                     return offset + Long.BYTES - 1 - SWARUtil.getIndex(result, !isNative);
744                 }
745             }
746         }
747         return unrolledLastIndexOf(buffer, fromIndex - (longCount << 3), length & 7, value);
748     }
749 
750     private static int linearLastIndexOf(final AbstractByteBuf buffer, final int fromIndex, final int toIndex,
751                                          final byte value) {
752         for (int i = fromIndex - 1; i >= toIndex; i--) {
753             if (buffer._getByte(i) == value) {
754                 return i;
755             }
756         }
757         return -1;
758     }
759 
760     private static int unrolledLastIndexOf(final AbstractByteBuf buffer, final int fromIndex, final int byteCount,
761                                            final byte value) {
762         assert byteCount >= 0 && byteCount < 8;
763         if (byteCount == 0) {
764             return -1;
765         }
766         if (buffer._getByte(fromIndex - 1) == value) {
767             return fromIndex - 1;
768         }
769         if (byteCount == 1) {
770             return -1;
771         }
772         if (buffer._getByte(fromIndex - 2) == value) {
773             return fromIndex - 2;
774         }
775         if (byteCount == 2) {
776             return -1;
777         }
778         if (buffer._getByte(fromIndex - 3) == value) {
779             return fromIndex - 3;
780         }
781         if (byteCount == 3) {
782             return -1;
783         }
784         if (buffer._getByte(fromIndex - 4) == value) {
785             return fromIndex - 4;
786         }
787         if (byteCount == 4) {
788             return -1;
789         }
790         if (buffer._getByte(fromIndex - 5) == value) {
791             return fromIndex - 5;
792         }
793         if (byteCount == 5) {
794             return -1;
795         }
796         if (buffer._getByte(fromIndex - 6) == value) {
797             return fromIndex - 6;
798         }
799         if (byteCount == 6) {
800             return -1;
801         }
802         if (buffer._getByte(fromIndex - 7) == value) {
803             return fromIndex - 7;
804         }
805         return -1;
806     }
807 
808     private static CharSequence checkCharSequenceBounds(CharSequence seq, int start, int end) {
809         if (MathUtil.isOutOfBounds(start, end - start, seq.length())) {
810             throw new IndexOutOfBoundsException("expected: 0 <= start(" + start + ") <= end (" + end
811                     + ") <= seq.length(" + seq.length() + ')');
812         }
813         return seq;
814     }
815 
816     /**
817      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
818      * it to a {@link ByteBuf} allocated with {@code alloc}.
819      * @param alloc The allocator used to allocate a new {@link ByteBuf}.
820      * @param seq The characters to write into a buffer.
821      * @return The {@link ByteBuf} which contains the <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoded
822      * result.
823      */
824     public static ByteBuf writeUtf8(ByteBufAllocator alloc, CharSequence seq) {
825         // UTF-8 uses max. 3 bytes per char, so calculate the worst case.
826         ByteBuf buf = alloc.buffer(utf8MaxBytes(seq));
827         writeUtf8(buf, seq);
828         return buf;
829     }
830 
831     /**
832      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
833      * it to a {@link ByteBuf}.
834      * <p>
835      * It behaves like {@link #reserveAndWriteUtf8(ByteBuf, CharSequence, int)} with {@code reserveBytes}
836      * computed by {@link #utf8MaxBytes(CharSequence)}.<br>
837      * This method returns the actual number of bytes written.
838      */
839     public static int writeUtf8(ByteBuf buf, CharSequence seq) {
840         int seqLength = seq.length();
841         return reserveAndWriteUtf8Seq(buf, seq, 0, seqLength, utf8MaxBytes(seqLength));
842     }
843 
844     /**
845      * Equivalent to <code>{@link #writeUtf8(ByteBuf, CharSequence) writeUtf8(buf, seq.subSequence(start, end))}</code>
846      * but avoids subsequence object allocation.
847      */
848     public static int writeUtf8(ByteBuf buf, CharSequence seq, int start, int end) {
849         checkCharSequenceBounds(seq, start, end);
850         return reserveAndWriteUtf8Seq(buf, seq, start, end, utf8MaxBytes(end - start));
851     }
852 
853     /**
854      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
855      * it into {@code reserveBytes} of a {@link ByteBuf}.
856      * <p>
857      * The {@code reserveBytes} must be computed (ie eagerly using {@link #utf8MaxBytes(CharSequence)}
858      * or exactly with {@link #utf8Bytes(CharSequence)}) to ensure this method to not fail: for performance reasons
859      * the index checks will be performed using just {@code reserveBytes}.<br>
860      * This method returns the actual number of bytes written.
861      */
862     public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int reserveBytes) {
863         return reserveAndWriteUtf8Seq(buf, seq, 0, seq.length(), reserveBytes);
864     }
865 
866     /**
867      * Equivalent to <code>{@link #reserveAndWriteUtf8(ByteBuf, CharSequence, int)
868      * reserveAndWriteUtf8(buf, seq.subSequence(start, end), reserveBytes)}</code> but avoids
869      * subsequence object allocation if possible.
870      *
871      * @return actual number of bytes written
872      */
873     public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int start, int end, int reserveBytes) {
874         return reserveAndWriteUtf8Seq(buf, checkCharSequenceBounds(seq, start, end), start, end, reserveBytes);
875     }
876 
877     private static int reserveAndWriteUtf8Seq(ByteBuf buf, CharSequence seq, int start, int end, int reserveBytes) {
878         for (;;) {
879             if (buf instanceof WrappedCompositeByteBuf) {
880                 // WrappedCompositeByteBuf is a sub-class of AbstractByteBuf so it needs special handling.
881                 buf = buf.unwrap();
882             } else if (buf instanceof AbstractByteBuf) {
883                 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
884                 byteBuf.ensureWritable0(reserveBytes);
885                 int written = writeUtf8(byteBuf, byteBuf.writerIndex, reserveBytes, seq, start, end);
886                 byteBuf.writerIndex += written;
887                 return written;
888             } else if (buf instanceof WrappedByteBuf) {
889                 // Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
890                 buf = buf.unwrap();
891             } else {
892                 byte[] bytes = seq.subSequence(start, end).toString().getBytes(CharsetUtil.UTF_8);
893                 buf.writeBytes(bytes);
894                 return bytes.length;
895             }
896         }
897     }
898 
899     static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes, CharSequence seq, int len) {
900         return writeUtf8(buffer, writerIndex, reservedBytes, seq, 0, len);
901     }
902 
903     // Fast-Path implementation
904     static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes,
905                          CharSequence seq, int start, int end) {
906         if (seq instanceof AsciiString) {
907             writeAsciiString(buffer, writerIndex, (AsciiString) seq, start, end);
908             return end - start;
909         }
910         if (PlatformDependent.hasUnsafe()) {
911             if (buffer.hasArray()) {
912                 return unsafeWriteUtf8(buffer.array(), PlatformDependent.byteArrayBaseOffset(),
913                                        buffer.arrayOffset() + writerIndex, seq, start, end);
914             }
915             if (buffer.hasMemoryAddress()) {
916                 return unsafeWriteUtf8(null, buffer.memoryAddress(), writerIndex, seq, start, end);
917             }
918         } else {
919             if (buffer.hasArray()) {
920                 return safeArrayWriteUtf8(buffer.array(), buffer.arrayOffset() + writerIndex, seq, start, end);
921             }
922             if (buffer.isDirect()) {
923                 assert buffer.nioBufferCount() == 1;
924                 final ByteBuffer internalDirectBuffer = buffer.internalNioBuffer(writerIndex, reservedBytes);
925                 final int bufferPosition = internalDirectBuffer.position();
926                 return safeDirectWriteUtf8(internalDirectBuffer, bufferPosition, seq, start, end);
927             }
928         }
929         return safeWriteUtf8(buffer, writerIndex, seq, start, end);
930     }
931 
932     // AsciiString Fast-Path implementation - no explicit bound-checks
933     static void writeAsciiString(AbstractByteBuf buffer, int writerIndex, AsciiString seq, int start, int end) {
934         final int begin = seq.arrayOffset() + start;
935         final int length = end - start;
936         if (PlatformDependent.hasUnsafe()) {
937             if (buffer.hasArray()) {
938                 PlatformDependent.copyMemory(seq.array(), begin,
939                                              buffer.array(), buffer.arrayOffset() + writerIndex, length);
940                 return;
941             }
942             if (buffer.hasMemoryAddress()) {
943                 PlatformDependent.copyMemory(seq.array(), begin, buffer.memoryAddress() + writerIndex, length);
944                 return;
945             }
946         }
947         if (buffer.hasArray()) {
948             System.arraycopy(seq.array(), begin, buffer.array(), buffer.arrayOffset() + writerIndex, length);
949             return;
950         }
951         buffer.setBytes(writerIndex, seq.array(), begin, length);
952     }
953 
954     // Safe off-heap Fast-Path implementation
955     private static int safeDirectWriteUtf8(ByteBuffer buffer, int writerIndex, CharSequence seq, int start, int end) {
956         assert !(seq instanceof AsciiString);
957         int oldWriterIndex = writerIndex;
958 
959         // We can use the _set methods as these not need to do any index checks and reference checks.
960         // This is possible as we called ensureWritable(...) before.
961         for (int i = start; i < end; i++) {
962             char c = seq.charAt(i);
963             if (c < 0x80) {
964                 buffer.put(writerIndex++, (byte) c);
965             } else if (c < 0x800) {
966                 buffer.put(writerIndex++, (byte) (0xc0 | (c >> 6)));
967                 buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
968             } else if (isSurrogate(c)) {
969                 if (!Character.isHighSurrogate(c)) {
970                     buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
971                     continue;
972                 }
973                 // Surrogate Pair consumes 2 characters.
974                 if (++i == end) {
975                     buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
976                     break;
977                 }
978                 // Extra method is copied here to NOT allow inlining of writeUtf8
979                 // and increase the chance to inline CharSequence::charAt instead
980                 char c2 = seq.charAt(i);
981                 if (!Character.isLowSurrogate(c2)) {
982                     buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
983                     buffer.put(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : (byte) c2);
984                 } else {
985                     int codePoint = Character.toCodePoint(c, c2);
986                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
987                     buffer.put(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
988                     buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
989                     buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
990                     buffer.put(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
991                 }
992             } else {
993                 buffer.put(writerIndex++, (byte) (0xe0 | (c >> 12)));
994                 buffer.put(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
995                 buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
996             }
997         }
998         return writerIndex - oldWriterIndex;
999     }
1000 
1001     // Safe off-heap Fast-Path implementation
1002     private static int safeWriteUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int start, int end) {
1003         assert !(seq instanceof AsciiString);
1004         int oldWriterIndex = writerIndex;
1005 
1006         // We can use the _set methods as these not need to do any index checks and reference checks.
1007         // This is possible as we called ensureWritable(...) before.
1008         for (int i = start; i < end; i++) {
1009             char c = seq.charAt(i);
1010             if (c < 0x80) {
1011                 buffer._setByte(writerIndex++, (byte) c);
1012             } else if (c < 0x800) {
1013                 buffer._setByte(writerIndex++, (byte) (0xc0 | (c >> 6)));
1014                 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
1015             } else if (isSurrogate(c)) {
1016                 if (!Character.isHighSurrogate(c)) {
1017                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
1018                     continue;
1019                 }
1020                 // Surrogate Pair consumes 2 characters.
1021                 if (++i == end) {
1022                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
1023                     break;
1024                 }
1025                 // Extra method is copied here to NOT allow inlining of writeUtf8
1026                 // and increase the chance to inline CharSequence::charAt instead
1027                 char c2 = seq.charAt(i);
1028                 if (!Character.isLowSurrogate(c2)) {
1029                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
1030                     buffer._setByte(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
1031                 } else {
1032                     int codePoint = Character.toCodePoint(c, c2);
1033                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
1034                     buffer._setByte(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
1035                     buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
1036                     buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
1037                     buffer._setByte(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
1038                 }
1039             } else {
1040                 buffer._setByte(writerIndex++, (byte) (0xe0 | (c >> 12)));
1041                 buffer._setByte(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
1042                 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
1043             }
1044         }
1045         return writerIndex - oldWriterIndex;
1046     }
1047 
1048     // safe byte[] Fast-Path implementation
1049     private static int safeArrayWriteUtf8(byte[] buffer, int writerIndex, CharSequence seq, int start, int end) {
1050         int oldWriterIndex = writerIndex;
1051         for (int i = start; i < end; i++) {
1052             char c = seq.charAt(i);
1053             if (c < 0x80) {
1054                 buffer[writerIndex++] = (byte) c;
1055             } else if (c < 0x800) {
1056                 buffer[writerIndex++] = (byte) (0xc0 | (c >> 6));
1057                 buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
1058             } else if (isSurrogate(c)) {
1059                 if (!Character.isHighSurrogate(c)) {
1060                     buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
1061                     continue;
1062                 }
1063                 // Surrogate Pair consumes 2 characters.
1064                 if (++i == end) {
1065                     buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
1066                     break;
1067                 }
1068                 char c2 = seq.charAt(i);
1069                 // Extra method is copied here to NOT allow inlining of writeUtf8
1070                 // and increase the chance to inline CharSequence::charAt instead
1071                 if (!Character.isLowSurrogate(c2)) {
1072                     buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
1073                     buffer[writerIndex++] = (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
1074                 } else {
1075                     int codePoint = Character.toCodePoint(c, c2);
1076                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
1077                     buffer[writerIndex++] = (byte) (0xf0 | (codePoint >> 18));
1078                     buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 12) & 0x3f));
1079                     buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 6) & 0x3f));
1080                     buffer[writerIndex++] = (byte) (0x80 | (codePoint & 0x3f));
1081                 }
1082             } else {
1083                 buffer[writerIndex++] = (byte) (0xe0 | (c >> 12));
1084                 buffer[writerIndex++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1085                 buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
1086             }
1087         }
1088         return writerIndex - oldWriterIndex;
1089     }
1090 
1091     // unsafe Fast-Path implementation
1092     private static int unsafeWriteUtf8(byte[] buffer, long memoryOffset, int writerIndex,
1093                                        CharSequence seq, int start, int end) {
1094         assert !(seq instanceof AsciiString);
1095         long writerOffset = memoryOffset + writerIndex;
1096         final long oldWriterOffset = writerOffset;
1097         for (int i = start; i < end; i++) {
1098             char c = seq.charAt(i);
1099             if (c < 0x80) {
1100                 PlatformDependent.putByte(buffer, writerOffset++, (byte) c);
1101             } else if (c < 0x800) {
1102                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xc0 | (c >> 6)));
1103                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
1104             } else if (isSurrogate(c)) {
1105                 if (!Character.isHighSurrogate(c)) {
1106                     PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1107                     continue;
1108                 }
1109                 // Surrogate Pair consumes 2 characters.
1110                 if (++i == end) {
1111                     PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1112                     break;
1113                 }
1114                 char c2 = seq.charAt(i);
1115                 // Extra method is copied here to NOT allow inlining of writeUtf8
1116                 // and increase the chance to inline CharSequence::charAt instead
1117                 if (!Character.isLowSurrogate(c2)) {
1118                     PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1119                     PlatformDependent.putByte(buffer, writerOffset++,
1120                                               (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2));
1121                 } else {
1122                     int codePoint = Character.toCodePoint(c, c2);
1123                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
1124                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xf0 | (codePoint >> 18)));
1125                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
1126                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
1127                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (codePoint & 0x3f)));
1128                 }
1129             } else {
1130                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xe0 | (c >> 12)));
1131                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((c >> 6) & 0x3f)));
1132                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
1133             }
1134         }
1135         return (int) (writerOffset - oldWriterOffset);
1136     }
1137 
1138     /**
1139      * Returns max bytes length of UTF8 character sequence of the given length.
1140      */
1141     public static int utf8MaxBytes(final int seqLength) {
1142         return seqLength * MAX_BYTES_PER_CHAR_UTF8;
1143     }
1144 
1145     /**
1146      * Returns max bytes length of UTF8 character sequence.
1147      * <p>
1148      * It behaves like {@link #utf8MaxBytes(int)} applied to {@code seq} {@link CharSequence#length()}.
1149      */
1150     public static int utf8MaxBytes(CharSequence seq) {
1151         if (seq instanceof AsciiString) {
1152             return seq.length();
1153         }
1154         return utf8MaxBytes(seq.length());
1155     }
1156 
1157     /**
1158      * Returns the exact bytes length of UTF8 character sequence.
1159      * <p>
1160      * This method is producing the exact length according to {@link #writeUtf8(ByteBuf, CharSequence)}.
1161      */
1162     public static int utf8Bytes(final CharSequence seq) {
1163         return utf8ByteCount(seq, 0, seq.length());
1164     }
1165 
1166     /**
1167      * Equivalent to <code>{@link #utf8Bytes(CharSequence) utf8Bytes(seq.subSequence(start, end))}</code>
1168      * but avoids subsequence object allocation.
1169      * <p>
1170      * This method is producing the exact length according to {@link #writeUtf8(ByteBuf, CharSequence, int, int)}.
1171      */
1172     public static int utf8Bytes(final CharSequence seq, int start, int end) {
1173         return utf8ByteCount(checkCharSequenceBounds(seq, start, end), start, end);
1174     }
1175 
1176     private static int utf8ByteCount(final CharSequence seq, int start, int end) {
1177         if (seq instanceof AsciiString) {
1178             return end - start;
1179         }
1180         int i = start;
1181         // ASCII fast path
1182         while (i < end && seq.charAt(i) < 0x80) {
1183             ++i;
1184         }
1185         // !ASCII is packed in a separate method to let the ASCII case be smaller
1186         return i < end ? (i - start) + utf8BytesNonAscii(seq, i, end) : i - start;
1187     }
1188 
1189     private static int utf8BytesNonAscii(final CharSequence seq, final int start, final int end) {
1190         int encodedLength = 0;
1191         for (int i = start; i < end; i++) {
1192             final char c = seq.charAt(i);
1193             // making it 100% branchless isn't rewarding due to the many bit operations necessary!
1194             if (c < 0x800) {
1195                 // branchless version of: (c <= 127 ? 0:1) + 1
1196                 encodedLength += ((0x7f - c) >>> 31) + 1;
1197             } else if (isSurrogate(c)) {
1198                 if (!Character.isHighSurrogate(c)) {
1199                     encodedLength++;
1200                     // WRITE_UTF_UNKNOWN
1201                     continue;
1202                 }
1203                 // Surrogate Pair consumes 2 characters.
1204                 if (++i == end) {
1205                     encodedLength++;
1206                     // WRITE_UTF_UNKNOWN
1207                     break;
1208                 }
1209                 if (!Character.isLowSurrogate(seq.charAt(i))) {
1210                     // WRITE_UTF_UNKNOWN + (Character.isHighSurrogate(c2) ? WRITE_UTF_UNKNOWN : c2)
1211                     encodedLength += 2;
1212                     continue;
1213                 }
1214                 // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
1215                 encodedLength += 4;
1216             } else {
1217                 encodedLength += 3;
1218             }
1219         }
1220         return encodedLength;
1221     }
1222 
1223     /**
1224      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> and write
1225      * it to a {@link ByteBuf} allocated with {@code alloc}.
1226      * @param alloc The allocator used to allocate a new {@link ByteBuf}.
1227      * @param seq The characters to write into a buffer.
1228      * @return The {@link ByteBuf} which contains the <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> encoded
1229      * result.
1230      */
1231     public static ByteBuf writeAscii(ByteBufAllocator alloc, CharSequence seq) {
1232         // ASCII uses 1 byte per char
1233         ByteBuf buf = alloc.buffer(seq.length());
1234         writeAscii(buf, seq);
1235         return buf;
1236     }
1237 
1238     /**
1239      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> and write it
1240      * to a {@link ByteBuf}.
1241      *
1242      * This method returns the actual number of bytes written.
1243      */
1244     public static int writeAscii(ByteBuf buf, CharSequence seq) {
1245         // ASCII uses 1 byte per char
1246         for (;;) {
1247             if (buf instanceof WrappedCompositeByteBuf) {
1248                 // WrappedCompositeByteBuf is a sub-class of AbstractByteBuf so it needs special handling.
1249                 buf = buf.unwrap();
1250             } else if (buf instanceof AbstractByteBuf) {
1251                 final int len = seq.length();
1252                 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
1253                 byteBuf.ensureWritable0(len);
1254                 if (seq instanceof AsciiString) {
1255                     writeAsciiString(byteBuf, byteBuf.writerIndex, (AsciiString) seq, 0, len);
1256                 } else {
1257                     final int written = writeAscii(byteBuf, byteBuf.writerIndex, seq, len);
1258                     assert written == len;
1259                 }
1260                 byteBuf.writerIndex += len;
1261                 return len;
1262             } else if (buf instanceof WrappedByteBuf) {
1263                 // Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
1264                 buf = buf.unwrap();
1265             } else {
1266                 byte[] bytes = seq.toString().getBytes(CharsetUtil.US_ASCII);
1267                 buf.writeBytes(bytes);
1268                 return bytes.length;
1269             }
1270         }
1271     }
1272 
1273     static int writeAscii(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
1274         if (seq instanceof AsciiString) {
1275             writeAsciiString(buffer, writerIndex, (AsciiString) seq, 0, len);
1276         } else {
1277             writeAsciiCharSequence(buffer, writerIndex, seq, len);
1278         }
1279         return len;
1280     }
1281 
1282     private static int writeAsciiCharSequence(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
1283         // We can use the _set methods as these not need to do any index checks and reference checks.
1284         // This is possible as we called ensureWritable(...) before.
1285         for (int i = 0; i < len; i++) {
1286             buffer._setByte(writerIndex++, AsciiString.c2b(seq.charAt(i)));
1287         }
1288         return len;
1289     }
1290 
1291     /**
1292      * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which
1293      * is allocated via the {@link ByteBufAllocator}.
1294      */
1295     public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset) {
1296         return encodeString0(alloc, false, src, charset, 0);
1297     }
1298 
1299     /**
1300      * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which
1301      * is allocated via the {@link ByteBufAllocator}.
1302      *
1303      * @param alloc The {@link ByteBufAllocator} to allocate {@link ByteBuf}.
1304      * @param src The {@link CharBuffer} to encode.
1305      * @param charset The specified {@link Charset}.
1306      * @param extraCapacity the extra capacity to alloc except the space for decoding.
1307      */
1308     public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset, int extraCapacity) {
1309         return encodeString0(alloc, false, src, charset, extraCapacity);
1310     }
1311 
1312     static ByteBuf encodeString0(ByteBufAllocator alloc, boolean enforceHeap, CharBuffer src, Charset charset,
1313                                  int extraCapacity) {
1314         final CharsetEncoder encoder = CharsetUtil.encoder(charset);
1315         int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar()) + extraCapacity;
1316         boolean release = true;
1317         final ByteBuf dst;
1318         if (enforceHeap) {
1319             dst = alloc.heapBuffer(length);
1320         } else {
1321             dst = alloc.buffer(length);
1322         }
1323         try {
1324             final ByteBuffer dstBuf = dst.internalNioBuffer(dst.readerIndex(), length);
1325             final int pos = dstBuf.position();
1326             CoderResult cr = encoder.encode(src, dstBuf, true);
1327             if (!cr.isUnderflow()) {
1328                 cr.throwException();
1329             }
1330             cr = encoder.flush(dstBuf);
1331             if (!cr.isUnderflow()) {
1332                 cr.throwException();
1333             }
1334             dst.writerIndex(dst.writerIndex() + dstBuf.position() - pos);
1335             release = false;
1336             return dst;
1337         } catch (CharacterCodingException x) {
1338             throw new IllegalStateException(x);
1339         } finally {
1340             if (release) {
1341                 dst.release();
1342             }
1343         }
1344     }
1345 
1346     @SuppressWarnings("deprecation")
1347     static String decodeString(ByteBuf src, int readerIndex, int len, Charset charset) {
1348         if (len == 0) {
1349             return StringUtil.EMPTY_STRING;
1350         }
1351         final byte[] array;
1352         final int offset;
1353 
1354         if (src.hasArray()) {
1355             array = src.array();
1356             offset = src.arrayOffset() + readerIndex;
1357         } else {
1358             array = threadLocalTempArray(len);
1359             offset = 0;
1360             src.getBytes(readerIndex, array, 0, len);
1361         }
1362         if (CharsetUtil.US_ASCII.equals(charset)) {
1363             // Fast-path for US-ASCII which is used frequently.
1364             return new String(array, 0, offset, len);
1365         }
1366         return new String(array, offset, len, charset);
1367     }
1368 
1369     /**
1370      * Returns a cached thread-local direct buffer, if available.
1371      *
1372      * @return a cached thread-local direct buffer, if available.  {@code null} otherwise.
1373      */
1374     public static ByteBuf threadLocalDirectBuffer() {
1375         if (THREAD_LOCAL_BUFFER_SIZE <= 0) {
1376             return null;
1377         }
1378 
1379         if (PlatformDependent.hasUnsafe()) {
1380             return ThreadLocalUnsafeDirectByteBuf.newInstance();
1381         } else {
1382             return ThreadLocalDirectByteBuf.newInstance();
1383         }
1384     }
1385 
1386     /**
1387      * Create a copy of the underlying storage from {@code buf} into a byte array.
1388      * The copy will start at {@link ByteBuf#readerIndex()} and copy {@link ByteBuf#readableBytes()} bytes.
1389      */
1390     public static byte[] getBytes(ByteBuf buf) {
1391         return getBytes(buf,  buf.readerIndex(), buf.readableBytes());
1392     }
1393 
1394     /**
1395      * Create a copy of the underlying storage from {@code buf} into a byte array.
1396      * The copy will start at {@code start} and copy {@code length} bytes.
1397      */
1398     public static byte[] getBytes(ByteBuf buf, int start, int length) {
1399         return getBytes(buf, start, length, true);
1400     }
1401 
1402     /**
1403      * Return an array of the underlying storage from {@code buf} into a byte array.
1404      * The copy will start at {@code start} and copy {@code length} bytes.
1405      * If {@code copy} is true a copy will be made of the memory.
1406      * If {@code copy} is false the underlying storage will be shared, if possible.
1407      */
1408     public static byte[] getBytes(ByteBuf buf, int start, int length, boolean copy) {
1409         int capacity = buf.capacity();
1410         if (isOutOfBounds(start, length, capacity)) {
1411             throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
1412                     + ") <= " + "buf.capacity(" + capacity + ')');
1413         }
1414 
1415         if (buf.hasArray()) {
1416             int baseOffset = buf.arrayOffset() + start;
1417             byte[] bytes = buf.array();
1418             if (copy || baseOffset != 0 || length != bytes.length) {
1419                 return Arrays.copyOfRange(bytes, baseOffset, baseOffset + length);
1420             } else {
1421                 return bytes;
1422             }
1423         }
1424 
1425         byte[] bytes = PlatformDependent.allocateUninitializedArray(length);
1426         buf.getBytes(start, bytes);
1427         return bytes;
1428     }
1429 
1430     /**
1431      * Copies the all content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
1432      *
1433      * @param src the source string to copy
1434      * @param dst the destination buffer
1435      */
1436     public static void copy(AsciiString src, ByteBuf dst) {
1437         copy(src, 0, dst, src.length());
1438     }
1439 
1440     /**
1441      * Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#setBytes(int, byte[], int, int)}.
1442      * Unlike the {@link #copy(AsciiString, ByteBuf)} and {@link #copy(AsciiString, int, ByteBuf, int)} methods,
1443      * this method do not increase a {@code writerIndex} of {@code dst} buffer.
1444      *
1445      * @param src the source string to copy
1446      * @param srcIdx the starting offset of characters to copy
1447      * @param dst the destination buffer
1448      * @param dstIdx the starting offset in the destination buffer
1449      * @param length the number of characters to copy
1450      */
1451     public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int dstIdx, int length) {
1452         if (isOutOfBounds(srcIdx, length, src.length())) {
1453             throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
1454                             + length + ") <= srcLen(" + src.length() + ')');
1455         }
1456 
1457         checkNotNull(dst, "dst").setBytes(dstIdx, src.array(), srcIdx + src.arrayOffset(), length);
1458     }
1459 
1460     /**
1461      * Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
1462      *
1463      * @param src the source string to copy
1464      * @param srcIdx the starting offset of characters to copy
1465      * @param dst the destination buffer
1466      * @param length the number of characters to copy
1467      */
1468     public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int length) {
1469         if (isOutOfBounds(srcIdx, length, src.length())) {
1470             throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
1471                             + length + ") <= srcLen(" + src.length() + ')');
1472         }
1473 
1474         checkNotNull(dst, "dst").writeBytes(src.array(), srcIdx + src.arrayOffset(), length);
1475     }
1476 
1477     /**
1478      * Returns a multi-line hexadecimal dump of the specified {@link ByteBuf} that is easy to read by humans.
1479      */
1480     public static String prettyHexDump(ByteBuf buffer) {
1481         return prettyHexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
1482     }
1483 
1484     /**
1485      * Returns a multi-line hexadecimal dump of the specified {@link ByteBuf} that is easy to read by humans,
1486      * starting at the given {@code offset} using the given {@code length}.
1487      */
1488     public static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1489         return HexUtil.prettyHexDump(buffer, offset, length);
1490     }
1491 
1492     /**
1493      * Appends the prettified multi-line hexadecimal dump of the specified {@link ByteBuf} to the specified
1494      * {@link StringBuilder} that is easy to read by humans.
1495      */
1496     public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf) {
1497         appendPrettyHexDump(dump, buf, buf.readerIndex(), buf.readableBytes());
1498     }
1499 
1500     /**
1501      * Appends the prettified multi-line hexadecimal dump of the specified {@link ByteBuf} to the specified
1502      * {@link StringBuilder} that is easy to read by humans, starting at the given {@code offset} using
1503      * the given {@code length}.
1504      */
1505     public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1506         HexUtil.appendPrettyHexDump(dump, buf, offset, length);
1507     }
1508 
1509     /* Separate class so that the expensive static initialization is only done when needed */
1510     private static final class HexUtil {
1511 
1512         private static final char[] BYTE2CHAR = new char[256];
1513         private static final char[] HEXDUMP_TABLE = new char[256 * 4];
1514         private static final String[] HEXPADDING = new String[16];
1515         private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4];
1516         private static final String[] BYTE2HEX = new String[256];
1517         private static final String[] BYTEPADDING = new String[16];
1518 
1519         static {
1520             final char[] DIGITS = "0123456789abcdef".toCharArray();
1521             for (int i = 0; i < 256; i ++) {
1522                 HEXDUMP_TABLE[ i << 1     ] = DIGITS[i >>> 4 & 0x0F];
1523                 HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i       & 0x0F];
1524             }
1525 
1526             int i;
1527 
1528             // Generate the lookup table for hex dump paddings
1529             for (i = 0; i < HEXPADDING.length; i ++) {
1530                 int padding = HEXPADDING.length - i;
1531                 StringBuilder buf = new StringBuilder(padding * 3);
1532                 for (int j = 0; j < padding; j ++) {
1533                     buf.append("   ");
1534                 }
1535                 HEXPADDING[i] = buf.toString();
1536             }
1537 
1538             // Generate the lookup table for the start-offset header in each row (up to 64KiB).
1539             for (i = 0; i < HEXDUMP_ROWPREFIXES.length; i ++) {
1540                 StringBuilder buf = new StringBuilder(12);
1541                 buf.append(NEWLINE);
1542                 buf.append(Long.toHexString(i << 4 & 0xFFFFFFFFL | 0x100000000L));
1543                 buf.setCharAt(buf.length() - 9, '|');
1544                 buf.append('|');
1545                 HEXDUMP_ROWPREFIXES[i] = buf.toString();
1546             }
1547 
1548             // Generate the lookup table for byte-to-hex-dump conversion
1549             for (i = 0; i < BYTE2HEX.length; i ++) {
1550                 BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i);
1551             }
1552 
1553             // Generate the lookup table for byte dump paddings
1554             for (i = 0; i < BYTEPADDING.length; i ++) {
1555                 int padding = BYTEPADDING.length - i;
1556                 StringBuilder buf = new StringBuilder(padding);
1557                 for (int j = 0; j < padding; j ++) {
1558                     buf.append(' ');
1559                 }
1560                 BYTEPADDING[i] = buf.toString();
1561             }
1562 
1563             // Generate the lookup table for byte-to-char conversion
1564             for (i = 0; i < BYTE2CHAR.length; i ++) {
1565                 if (i <= 0x1f || i >= 0x7f) {
1566                     BYTE2CHAR[i] = '.';
1567                 } else {
1568                     BYTE2CHAR[i] = (char) i;
1569                 }
1570             }
1571         }
1572 
1573         private static String hexDump(ByteBuf buffer, int fromIndex, int length) {
1574             checkPositiveOrZero(length, "length");
1575             if (length == 0) {
1576               return "";
1577             }
1578 
1579             int endIndex = fromIndex + length;
1580             char[] buf = new char[length << 1];
1581 
1582             int srcIdx = fromIndex;
1583             int dstIdx = 0;
1584             for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1585               System.arraycopy(
1586                   HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1,
1587                   buf, dstIdx, 2);
1588             }
1589 
1590             return new String(buf);
1591         }
1592 
1593         private static String hexDump(byte[] array, int fromIndex, int length) {
1594             checkPositiveOrZero(length, "length");
1595             if (length == 0) {
1596                 return "";
1597             }
1598 
1599             int endIndex = fromIndex + length;
1600             char[] buf = new char[length << 1];
1601 
1602             int srcIdx = fromIndex;
1603             int dstIdx = 0;
1604             for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1605                 System.arraycopy(
1606                     HEXDUMP_TABLE, (array[srcIdx] & 0xFF) << 1,
1607                     buf, dstIdx, 2);
1608             }
1609 
1610             return new String(buf);
1611         }
1612 
1613         private static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1614             if (length == 0) {
1615               return StringUtil.EMPTY_STRING;
1616             } else {
1617                 int rows = length / 16 + ((length & 15) == 0? 0 : 1) + 4;
1618                 StringBuilder buf = new StringBuilder(rows * 80);
1619                 appendPrettyHexDump(buf, buffer, offset, length);
1620                 return buf.toString();
1621             }
1622         }
1623 
1624         private static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1625             if (isOutOfBounds(offset, length, buf.capacity())) {
1626                 throw new IndexOutOfBoundsException(
1627                         "expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length
1628                                                     + ") <= " + "buf.capacity(" + buf.capacity() + ')');
1629             }
1630             if (length == 0) {
1631                 return;
1632             }
1633             dump.append(
1634                               "         +-------------------------------------------------+" +
1635                     NEWLINE + "         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |" +
1636                     NEWLINE + "+--------+-------------------------------------------------+----------------+");
1637 
1638             final int fullRows = length >>> 4;
1639             final int remainder = length & 0xF;
1640 
1641             // Dump the rows which have 16 bytes.
1642             for (int row = 0; row < fullRows; row ++) {
1643                 int rowStartIndex = (row << 4) + offset;
1644 
1645                 // Per-row prefix.
1646                 appendHexDumpRowPrefix(dump, row, rowStartIndex);
1647 
1648                 // Hex dump
1649                 int rowEndIndex = rowStartIndex + 16;
1650                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1651                     dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1652                 }
1653                 dump.append(" |");
1654 
1655                 // ASCII dump
1656                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1657                     dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1658                 }
1659                 dump.append('|');
1660             }
1661 
1662             // Dump the last row which has less than 16 bytes.
1663             if (remainder != 0) {
1664                 int rowStartIndex = (fullRows << 4) + offset;
1665                 appendHexDumpRowPrefix(dump, fullRows, rowStartIndex);
1666 
1667                 // Hex dump
1668                 int rowEndIndex = rowStartIndex + remainder;
1669                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1670                     dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1671                 }
1672                 dump.append(HEXPADDING[remainder]);
1673                 dump.append(" |");
1674 
1675                 // Ascii dump
1676                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1677                     dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1678                 }
1679                 dump.append(BYTEPADDING[remainder]);
1680                 dump.append('|');
1681             }
1682 
1683             dump.append(NEWLINE +
1684                         "+--------+-------------------------------------------------+----------------+");
1685         }
1686 
1687         private static void appendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartIndex) {
1688             if (row < HEXDUMP_ROWPREFIXES.length) {
1689                 dump.append(HEXDUMP_ROWPREFIXES[row]);
1690             } else {
1691                 dump.append(NEWLINE);
1692                 dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L));
1693                 dump.setCharAt(dump.length() - 9, '|');
1694                 dump.append('|');
1695             }
1696         }
1697     }
1698 
1699     static final class ThreadLocalUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
1700 
1701         private static final ObjectPool<ThreadLocalUnsafeDirectByteBuf> RECYCLER =
1702                 ObjectPool.newPool(new ObjectCreator<ThreadLocalUnsafeDirectByteBuf>() {
1703                     @Override
1704                     public ThreadLocalUnsafeDirectByteBuf newObject(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1705                         return new ThreadLocalUnsafeDirectByteBuf(handle);
1706                     }
1707                 });
1708 
1709         static ThreadLocalUnsafeDirectByteBuf newInstance() {
1710             ThreadLocalUnsafeDirectByteBuf buf = RECYCLER.get();
1711             buf.resetRefCnt();
1712             return buf;
1713         }
1714 
1715         private final EnhancedHandle<ThreadLocalUnsafeDirectByteBuf> handle;
1716 
1717         private ThreadLocalUnsafeDirectByteBuf(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1718             super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1719             this.handle = (EnhancedHandle<ThreadLocalUnsafeDirectByteBuf>) handle;
1720         }
1721 
1722         @Override
1723         protected void deallocate() {
1724             if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1725                 super.deallocate();
1726             } else {
1727                 clear();
1728                 handle.unguardedRecycle(this);
1729             }
1730         }
1731     }
1732 
1733     static final class ThreadLocalDirectByteBuf extends UnpooledDirectByteBuf {
1734 
1735         private static final ObjectPool<ThreadLocalDirectByteBuf> RECYCLER = ObjectPool.newPool(
1736                 new ObjectCreator<ThreadLocalDirectByteBuf>() {
1737             @Override
1738             public ThreadLocalDirectByteBuf newObject(Handle<ThreadLocalDirectByteBuf> handle) {
1739                 return new ThreadLocalDirectByteBuf(handle);
1740             }
1741         });
1742 
1743         static ThreadLocalDirectByteBuf newInstance() {
1744             ThreadLocalDirectByteBuf buf = RECYCLER.get();
1745             buf.resetRefCnt();
1746             return buf;
1747         }
1748 
1749         private final EnhancedHandle<ThreadLocalDirectByteBuf> handle;
1750 
1751         private ThreadLocalDirectByteBuf(Handle<ThreadLocalDirectByteBuf> handle) {
1752             super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1753             this.handle = (EnhancedHandle<ThreadLocalDirectByteBuf>) handle;
1754         }
1755 
1756         @Override
1757         protected void deallocate() {
1758             if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1759                 super.deallocate();
1760             } else {
1761                 clear();
1762                 handle.unguardedRecycle(this);
1763             }
1764         }
1765     }
1766 
1767     /**
1768      * Returns {@code true} if the given {@link ByteBuf} is valid text using the given {@link Charset},
1769      * otherwise return {@code false}.
1770      *
1771      * @param buf The given {@link ByteBuf}.
1772      * @param charset The specified {@link Charset}.
1773      */
1774     public static boolean isText(ByteBuf buf, Charset charset) {
1775         return isText(buf, buf.readerIndex(), buf.readableBytes(), charset);
1776     }
1777 
1778     /**
1779      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1780      * text using the given {@link Charset}, otherwise return {@code false}.
1781      *
1782      * @param buf The given {@link ByteBuf}.
1783      * @param index The start index of the specified buffer.
1784      * @param length The length of the specified buffer.
1785      * @param charset The specified {@link Charset}.
1786      *
1787      * @throws IndexOutOfBoundsException if {@code index} + {@code length} is greater than {@code buf.readableBytes}
1788      */
1789     public static boolean isText(ByteBuf buf, int index, int length, Charset charset) {
1790         checkNotNull(buf, "buf");
1791         checkNotNull(charset, "charset");
1792         final int maxIndex = buf.readerIndex() + buf.readableBytes();
1793         if (index < 0 || length < 0 || index > maxIndex - length) {
1794             throw new IndexOutOfBoundsException("index: " + index + " length: " + length);
1795         }
1796         if (charset.equals(CharsetUtil.UTF_8)) {
1797             return isUtf8(buf, index, length);
1798         } else if (charset.equals(CharsetUtil.US_ASCII)) {
1799             return isAscii(buf, index, length);
1800         } else {
1801             CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
1802             try {
1803                 if (buf.nioBufferCount() == 1) {
1804                     decoder.decode(buf.nioBuffer(index, length));
1805                 } else {
1806                     ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
1807                     try {
1808                         heapBuffer.writeBytes(buf, index, length);
1809                         decoder.decode(heapBuffer.internalNioBuffer(heapBuffer.readerIndex(), length));
1810                     } finally {
1811                         heapBuffer.release();
1812                     }
1813                 }
1814                 return true;
1815             } catch (CharacterCodingException ignore) {
1816                 return false;
1817             }
1818         }
1819     }
1820 
1821     /**
1822      * Aborts on a byte which is not a valid ASCII character.
1823      */
1824     private static final ByteProcessor FIND_NON_ASCII = new ByteProcessor() {
1825         @Override
1826         public boolean process(byte value) {
1827             return value >= 0;
1828         }
1829     };
1830 
1831     /**
1832      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1833      * ASCII text, otherwise return {@code false}.
1834      *
1835      * @param buf    The given {@link ByteBuf}.
1836      * @param index  The start index of the specified buffer.
1837      * @param length The length of the specified buffer.
1838      */
1839     private static boolean isAscii(ByteBuf buf, int index, int length) {
1840         return buf.forEachByte(index, length, FIND_NON_ASCII) == -1;
1841     }
1842 
1843     /**
1844      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1845      * UTF8 text, otherwise return {@code false}.
1846      *
1847      * @param buf The given {@link ByteBuf}.
1848      * @param index The start index of the specified buffer.
1849      * @param length The length of the specified buffer.
1850      *
1851      * @see
1852      * <a href=https://www.ietf.org/rfc/rfc3629.txt>UTF-8 Definition</a>
1853      *
1854      * <pre>
1855      * 1. Bytes format of UTF-8
1856      *
1857      * The table below summarizes the format of these different octet types.
1858      * The letter x indicates bits available for encoding bits of the character number.
1859      *
1860      * Char. number range  |        UTF-8 octet sequence
1861      *    (hexadecimal)    |              (binary)
1862      * --------------------+---------------------------------------------
1863      * 0000 0000-0000 007F | 0xxxxxxx
1864      * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1865      * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1866      * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1867      * </pre>
1868      *
1869      * <pre>
1870      * 2. Syntax of UTF-8 Byte Sequences
1871      *
1872      * UTF8-octets = *( UTF8-char )
1873      * UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
1874      * UTF8-1      = %x00-7F
1875      * UTF8-2      = %xC2-DF UTF8-tail
1876      * UTF8-3      = %xE0 %xA0-BF UTF8-tail /
1877      *               %xE1-EC 2( UTF8-tail ) /
1878      *               %xED %x80-9F UTF8-tail /
1879      *               %xEE-EF 2( UTF8-tail )
1880      * UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) /
1881      *               %xF1-F3 3( UTF8-tail ) /
1882      *               %xF4 %x80-8F 2( UTF8-tail )
1883      * UTF8-tail   = %x80-BF
1884      * </pre>
1885      */
1886     private static boolean isUtf8(ByteBuf buf, int index, int length) {
1887         final int endIndex = index + length;
1888         while (index < endIndex) {
1889             byte b1 = buf.getByte(index++);
1890             byte b2, b3, b4;
1891             if ((b1 & 0x80) == 0) {
1892                 // 1 byte
1893                 continue;
1894             }
1895             if ((b1 & 0xE0) == 0xC0) {
1896                 // 2 bytes
1897                 //
1898                 // Bit/Byte pattern
1899                 // 110xxxxx    10xxxxxx
1900                 // C2..DF      80..BF
1901                 if (index >= endIndex) { // no enough bytes
1902                     return false;
1903                 }
1904                 b2 = buf.getByte(index++);
1905                 if ((b2 & 0xC0) != 0x80) { // 2nd byte not starts with 10
1906                     return false;
1907                 }
1908                 if ((b1 & 0xFF) < 0xC2) { // out of lower bound
1909                     return false;
1910                 }
1911             } else if ((b1 & 0xF0) == 0xE0) {
1912                 // 3 bytes
1913                 //
1914                 // Bit/Byte pattern
1915                 // 1110xxxx    10xxxxxx    10xxxxxx
1916                 // E0          A0..BF      80..BF
1917                 // E1..EC      80..BF      80..BF
1918                 // ED          80..9F      80..BF
1919                 // E1..EF      80..BF      80..BF
1920                 if (index > endIndex - 2) { // no enough bytes
1921                     return false;
1922                 }
1923                 b2 = buf.getByte(index++);
1924                 b3 = buf.getByte(index++);
1925                 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { // 2nd or 3rd bytes not start with 10
1926                     return false;
1927                 }
1928                 if ((b1 & 0x0F) == 0x00 && (b2 & 0xFF) < 0xA0) { // out of lower bound
1929                     return false;
1930                 }
1931                 if ((b1 & 0x0F) == 0x0D && (b2 & 0xFF) > 0x9F) { // out of upper bound
1932                     return false;
1933                 }
1934             } else if ((b1 & 0xF8) == 0xF0) {
1935                 // 4 bytes
1936                 //
1937                 // Bit/Byte pattern
1938                 // 11110xxx    10xxxxxx    10xxxxxx    10xxxxxx
1939                 // F0          90..BF      80..BF      80..BF
1940                 // F1..F3      80..BF      80..BF      80..BF
1941                 // F4          80..8F      80..BF      80..BF
1942                 if (index > endIndex - 3) { // no enough bytes
1943                     return false;
1944                 }
1945                 b2 = buf.getByte(index++);
1946                 b3 = buf.getByte(index++);
1947                 b4 = buf.getByte(index++);
1948                 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80) {
1949                     // 2nd, 3rd or 4th bytes not start with 10
1950                     return false;
1951                 }
1952                 if ((b1 & 0xFF) > 0xF4 // b1 invalid
1953                         || (b1 & 0xFF) == 0xF0 && (b2 & 0xFF) < 0x90    // b2 out of lower bound
1954                         || (b1 & 0xFF) == 0xF4 && (b2 & 0xFF) > 0x8F) { // b2 out of upper bound
1955                     return false;
1956                 }
1957             } else {
1958                 return false;
1959             }
1960         }
1961         return true;
1962     }
1963 
1964     /**
1965      * Read bytes from the given {@link ByteBuffer} into the given {@link OutputStream} using the {@code position} and
1966      * {@code length}. The position and limit of the given {@link ByteBuffer} may be adjusted.
1967      */
1968     static void readBytes(ByteBufAllocator allocator, ByteBuffer buffer, int position, int length, OutputStream out)
1969             throws IOException {
1970         if (buffer.hasArray()) {
1971             out.write(buffer.array(), position + buffer.arrayOffset(), length);
1972         } else {
1973             int chunkLen = Math.min(length, WRITE_CHUNK_SIZE);
1974             buffer.clear().position(position);
1975 
1976             if (length <= MAX_TL_ARRAY_LEN || !allocator.isDirectBufferPooled()) {
1977                 getBytes(buffer, threadLocalTempArray(chunkLen), 0, chunkLen, out, length);
1978             } else {
1979                 // if direct buffers are pooled chances are good that heap buffers are pooled as well.
1980                 ByteBuf tmpBuf = allocator.heapBuffer(chunkLen);
1981                 try {
1982                     byte[] tmp = tmpBuf.array();
1983                     int offset = tmpBuf.arrayOffset();
1984                     getBytes(buffer, tmp, offset, chunkLen, out, length);
1985                 } finally {
1986                     tmpBuf.release();
1987                 }
1988             }
1989         }
1990     }
1991 
1992     private static void getBytes(ByteBuffer inBuffer, byte[] in, int inOffset, int inLen, OutputStream out, int outLen)
1993             throws IOException {
1994         do {
1995             int len = Math.min(inLen, outLen);
1996             inBuffer.get(in, inOffset, len);
1997             out.write(in, inOffset, len);
1998             outLen -= len;
1999         } while (outLen > 0);
2000     }
2001 
2002     /**
2003      * Set {@link AbstractByteBuf#leakDetector}'s {@link ResourceLeakDetector.LeakListener}.
2004      *
2005      * @param leakListener If leakListener is not null, it will be notified once a ByteBuf leak is detected.
2006      */
2007     public static void setLeakListener(ResourceLeakDetector.LeakListener leakListener) {
2008         AbstractByteBuf.leakDetector.setLeakListener(leakListener);
2009     }
2010 
2011     private ByteBufUtil() { }
2012 }