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