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