private static TextRange nextUnmappable(@NotNull CharBuffer in,
                                          int position,
                                          @NotNull Ref<ByteBuffer> outRef,
                                          @NotNull CharBuffer back,
                                          @NotNull Charset charset) {
    CharsetEncoder encoder = charset.newEncoder()
                                    .onUnmappableCharacter(CodingErrorAction.REPORT)
                                    .onMalformedInput(CodingErrorAction.REPORT);
    int textLength = in.limit() - position;

    ByteBuffer out = outRef.get();
    if (out == null) {
      outRef.set(out = ByteBuffer.allocate((int)(encoder.averageBytesPerChar() * textLength)));
    }
    out.rewind();
    out.limit(out.capacity());
    in.rewind();
    in.position(position);
    CoderResult cr;
    for (;;) {
      cr = in.hasRemaining() ? encoder.encode(in, out, true) : CoderResult.UNDERFLOW;
      if (cr.isUnderflow()) {
        cr = encoder.flush(out);
      }

      if (!cr.isOverflow()) {
        break;
      }

      int n = 3 * out.capacity()/2 + 1;
      ByteBuffer tmp = ByteBuffer.allocate(n);
      out.flip();
      tmp.put(out);
      outRef.set(out = tmp);
    }
    if (cr.isError()) {
      return TextRange.from(in.position(), cr.length());
    }
    // phew, encoded successfully. now check if we can decode it back with char-to-char precision
    int outLength = out.position();
    CharsetDecoder decoder = charset.newDecoder()
                                    .onUnmappableCharacter(CodingErrorAction.REPORT)
                                    .onMalformedInput(CodingErrorAction.REPORT);
    out.rewind();
    out.limit(outLength);
    back.rewind();
    CoderResult dr = decoder.decode(out, back, true);
    if (dr.isError()) {
      return TextRange.from(back.position(), dr.length());
    }
    if (back.position() != textLength) {
      return TextRange.from(Math.min(textLength, back.position()), 1);
    }
    // ok, we decoded it back to string. now compare if the strings are identical
    in.rewind();
    in.position(position);
    back.rewind();
    int len = StringUtil.commonPrefixLength(in, back);
    if (len == textLength) return null;
    return TextRange.from(len, 1);  // let's report only the first diff char
  }
private static TextRange nextUnmappable(@NotNull CharBuffer in,
                                          int position,
                                          @NotNull Ref<ByteBuffer> outRef,
                                          @NotNull CharBuffer back,
                                          @NotNull Charset charset)