protected CoderResult decodeLoop(ByteBuffer bb, CharBuffer cb) {
   int cbRemaining = cb.remaining();
   if (CharsetProviderImpl.hasLoadedNatives()
       && bb.isDirect()
       && bb.hasRemaining()
       && cb.hasArray()) {
     int toProceed = bb.remaining();
     int cbPos = cb.position();
     int bbPos = bb.position();
     boolean throwOverflow = false;
     if (cbRemaining < toProceed) {
       toProceed = cbRemaining;
       throwOverflow = true;
     }
     int res =
         nDecode(
             cb.array(),
             cb.arrayOffset() + cbPos,
             toProceed,
             AddressUtil.getDirectBufferAddress(bb),
             bbPos);
     bb.position(bbPos + res);
     cb.position(cbPos + res);
     if (throwOverflow) return CoderResult.OVERFLOW;
   } else {
     if (bb.hasArray() && cb.hasArray()) {
       int rem = bb.remaining();
       rem = cbRemaining >= rem ? rem : cbRemaining;
       byte[] bArr = bb.array();
       char[] cArr = cb.array();
       int bStart = bb.position();
       int cStart = cb.position();
       int i;
       for (i = bStart; i < bStart + rem; i++) {
         char in = (char) (bArr[i] & 0xFF);
         if (in >= 4) {
           int index = (int) in - 4;
           cArr[cStart++] = (char) arr[index];
         } else {
           cArr[cStart++] = (char) (in & 0xFF);
         }
       }
       bb.position(i);
       cb.position(cStart);
       if (rem == cbRemaining && bb.hasRemaining()) return CoderResult.OVERFLOW;
     } else {
       while (bb.hasRemaining()) {
         if (cbRemaining == 0) return CoderResult.OVERFLOW;
         char in = (char) (bb.get() & 0xFF);
         if (in >= 4) {
           int index = (int) in - 4;
           cb.put(arr[index]);
         } else {
           cb.put((char) (in & 0xFF));
         }
         cbRemaining--;
       }
     }
   }
   return CoderResult.UNDERFLOW;
 }
 protected CoderResult encodeLoop(CharBuffer cb, ByteBuffer bb) {
   int bbRemaining = bb.remaining();
   if (CharsetProviderImpl.hasLoadedNatives()
       && bb.isDirect()
       && cb.hasRemaining()
       && cb.hasArray()) {
     int toProceed = cb.remaining();
     int cbPos = cb.position();
     int bbPos = bb.position();
     boolean throwOverflow = false;
     if (bbRemaining < toProceed) {
       toProceed = bbRemaining;
       throwOverflow = true;
     }
     int[] res = {toProceed, 0};
     nEncode(
         AddressUtil.getDirectBufferAddress(bb),
         bbPos,
         cb.array(),
         cb.arrayOffset() + cbPos,
         res);
     if (res[0] <= 0) {
       bb.position(bbPos - res[0]);
       cb.position(cbPos - res[0]);
       if (res[1] != 0) {
         if (res[1] < 0) return CoderResult.malformedForLength(-res[1]);
         else return CoderResult.unmappableForLength(res[1]);
       }
     } else {
       bb.position(bbPos + res[0]);
       cb.position(cbPos + res[0]);
       if (throwOverflow) return CoderResult.OVERFLOW;
     }
   } else {
     if (bb.hasArray() && cb.hasArray()) {
       byte[] byteArr = bb.array();
       char[] charArr = cb.array();
       int rem = cb.remaining();
       int byteArrStart = bb.position();
       rem = bbRemaining <= rem ? bbRemaining : rem;
       int x;
       for (x = cb.position(); x < cb.position() + rem; x++) {
         char c = charArr[x];
         if (c > (char) 0x20AC) {
           if (c >= 0xD800 && c <= 0xDFFF) {
             if (x + 1 < cb.limit()) {
               char c1 = charArr[x + 1];
               if (c1 >= 0xD800 && c1 <= 0xDFFF) {
                 cb.position(x);
                 bb.position(byteArrStart);
                 return CoderResult.unmappableForLength(2);
               }
             } else {
               cb.position(x);
               bb.position(byteArrStart);
               return CoderResult.UNDERFLOW;
             }
             cb.position(x);
             bb.position(byteArrStart);
             return CoderResult.malformedForLength(1);
           }
           cb.position(x);
           bb.position(byteArrStart);
           return CoderResult.unmappableForLength(1);
         } else {
           if (c < 0x04) {
             byteArr[byteArrStart++] = (byte) c;
           } else {
             int index = (int) c >> 8;
             index = encodeIndex[index];
             if (index < 0) {
               cb.position(x);
               bb.position(byteArrStart);
               return CoderResult.unmappableForLength(1);
             }
             index <<= 8;
             index += (int) c & 0xFF;
             if ((byte) arr[index] != 0) {
               byteArr[byteArrStart++] = (byte) arr[index];
             } else {
               cb.position(x);
               bb.position(byteArrStart);
               return CoderResult.unmappableForLength(1);
             }
           }
         }
       }
       cb.position(x);
       bb.position(byteArrStart);
       if (rem == bbRemaining && cb.hasRemaining()) {
         return CoderResult.OVERFLOW;
       }
     } else {
       while (cb.hasRemaining()) {
         if (bbRemaining == 0) return CoderResult.OVERFLOW;
         char c = cb.get();
         if (c > (char) 0x20AC) {
           if (c >= 0xD800 && c <= 0xDFFF) {
             if (cb.hasRemaining()) {
               char c1 = cb.get();
               if (c1 >= 0xD800 && c1 <= 0xDFFF) {
                 cb.position(cb.position() - 2);
                 return CoderResult.unmappableForLength(2);
               } else {
                 cb.position(cb.position() - 1);
               }
             } else {
               cb.position(cb.position() - 1);
               return CoderResult.UNDERFLOW;
             }
             cb.position(cb.position() - 1);
             return CoderResult.malformedForLength(1);
           }
           cb.position(cb.position() - 1);
           return CoderResult.unmappableForLength(1);
         } else {
           if (c < 0x04) {
             bb.put((byte) c);
           } else {
             int index = (int) c >> 8;
             index = encodeIndex[index];
             if (index < 0) {
               cb.position(cb.position() - 1);
               return CoderResult.unmappableForLength(1);
             }
             index <<= 8;
             index += (int) c & 0xFF;
             if ((byte) arr[index] != 0) {
               bb.put((byte) arr[index]);
             } else {
               cb.position(cb.position() - 1);
               return CoderResult.unmappableForLength(1);
             }
           }
           bbRemaining--;
         }
       }
     }
   }
   return CoderResult.UNDERFLOW;
 }