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