All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.openhft.chronicle.bytes.internal.BytesInternal Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2016-2022 chronicle.software
 *
 *     https://chronicle.software
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.openhft.chronicle.bytes.internal;

import net.openhft.chronicle.bytes.*;
import net.openhft.chronicle.bytes.util.DecoratedBufferOverflowException;
import net.openhft.chronicle.bytes.util.DecoratedBufferUnderflowException;
import net.openhft.chronicle.bytes.util.StringInternerBytes;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.Maths;
import net.openhft.chronicle.core.Memory;
import net.openhft.chronicle.core.UnsafeMemory;
import net.openhft.chronicle.core.annotation.NonNegative;
import net.openhft.chronicle.core.io.*;
import net.openhft.chronicle.core.pool.ClassAliasPool;
import net.openhft.chronicle.core.pool.EnumInterner;
import net.openhft.chronicle.core.pool.StringBuilderPool;
import net.openhft.chronicle.core.scoped.ScopedResource;
import net.openhft.chronicle.core.scoped.ScopedResourcePool;
import net.openhft.chronicle.core.scoped.ScopedThreadLocal;
import net.openhft.chronicle.core.util.Histogram;
import net.openhft.chronicle.core.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UTFDataFormatException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static net.openhft.chronicle.assertions.AssertUtil.SKIP_ASSERTIONS;
import static net.openhft.chronicle.bytes.StreamingDataOutput.JAVA9_STRING_CODER_LATIN;
import static net.openhft.chronicle.bytes.StreamingDataOutput.JAVA9_STRING_CODER_UTF16;
import static net.openhft.chronicle.bytes.internal.ReferenceCountedUtil.throwExceptionIfReleased;
import static net.openhft.chronicle.core.UnsafeMemory.MEMORY;
import static net.openhft.chronicle.core.io.ReferenceOwner.temporary;
import static net.openhft.chronicle.core.util.Longs.requireNonNegative;
import static net.openhft.chronicle.core.util.ObjectUtils.requireNonNull;
import static net.openhft.chronicle.core.util.StringUtils.*;

/**
 * Utility methods to support common functionality in this package. This is not intended to be
 * accessed directly.
 */
@SuppressWarnings("rawtypes")
public
enum BytesInternal {

    ; // none
    private static final int THREAD_LOCAL_BYTES_POOL_SIZE = Jvm.getInteger("bytesInternal.bytes.instancesPerThread", 2);
    public static final ThreadLocal BYTE_BUFFER_TL = ThreadLocal.withInitial(() -> ByteBuffer.allocateDirect(0));
    public static final ThreadLocal BYTE_BUFFER2_TL = ThreadLocal.withInitial(() -> ByteBuffer.allocateDirect(0));
    public static final ScopedThreadLocal> BYTES_SCOPED_THREAD_LOCAL = new ScopedThreadLocal<>(
            () -> {
                Bytes bbb = Bytes.allocateElasticDirect(256);
                IOTools.unmonitor(bbb);
                return bbb;
            },
            Bytes::clear,
            THREAD_LOCAL_BYTES_POOL_SIZE);
    public static final StringInternerBytes SI;
    static final char[] HEXADECIMAL = "0123456789abcdef".toCharArray();
    private static final String INFINITY = "Infinity";
    private static final String NAN = "NaN";
    private static final String MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END = "malformed input: partial character at end";
    private static final String MALFORMED_INPUT_AROUND_BYTE = "malformed input around byte ";
    private static final String WAS = " was ";
    private static final String CAN_T_PARSE_FLEXIBLE_LONG_WITHOUT_PRECISION_LOSS = "Can't parse flexible long without precision loss: ";
    private static final byte[] MIN_VALUE_TEXT = ("" + Long.MIN_VALUE).getBytes(ISO_8859_1);
    private static final ScopedResourcePool STRING_BUILDER_SCOPED_RESOURCE_POOL = StringBuilderPool.createThreadLocal();
    private static final byte[] INFINITY_BYTES = INFINITY.getBytes(ISO_8859_1);
    private static final byte[] NAN_BYTES = NAN.getBytes(ISO_8859_1);
    private static final long MAX_VALUE_DIVIDE_5 = Long.MAX_VALUE / 5;
    private static final long MAX_VALUE_DIVIDE_10 = Long.MAX_VALUE / 10;
    private static final ThreadLocal dateCacheTL = new ThreadLocal<>();
    private static final int MAX_STRING_LEN = Jvm.getInteger("bytes.max-string-len", 128 * 1024);
    private static final int NEG_ONE = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? 0x80 : 0x8000;

    private static final MethodHandle VECTORIZED_MISMATCH_METHOD_HANDLE;
    private static final ThreadLocal BYTE_ARRAY_TL = ThreadLocal.withInitial(() -> new byte[20]);

    static {
        try {
            SI = new StringInternerBytes(Jvm.getInteger("wire.string-interner.size", 4096));
            ClassAliasPool.CLASS_ALIASES.addAlias(BytesStore.class, "!binary");
        } catch (Exception e) {
            throw new AssertionError(e);
        }

        MethodHandle vectorizedMismatchMethodHandle = null;
        try {
            if (Jvm.isJava9Plus() && !Jvm.getBoolean("disable.vectorized.content_equals")) {
                final Class arraysSupportClass = Class.forName("jdk.internal.util.ArraysSupport");
                final Method vectorizedMismatch = Jvm.getMethod(arraysSupportClass, "vectorizedMismatch",
                        Object.class,
                        long.class,
                        Object.class,
                        long.class,
                        int.class,
                        int.class);

                vectorizedMismatch.setAccessible(true);
                vectorizedMismatchMethodHandle = MethodHandles.lookup().unreflect(vectorizedMismatch);
            }
        } catch (Exception e) {
            if (e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException"))
                Jvm.debug().on(BytesInternal.class, "Cannot get access to vectorizedMismatch. The following command line args are required: " +
                        "--illegal-access=permit --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-exports java.base/jdk.internal.util=ALL-UNNAMED" +
                        ". exception: " + e);
            else
                Jvm.warn().on(BytesInternal.class, e);
        } finally {
            VECTORIZED_MISMATCH_METHOD_HANDLE = vectorizedMismatchMethodHandle;
        }
    }

    public static boolean contentEqual(@Nullable final BytesStore a,
                                       @Nullable final BytesStore b) throws ClosedIllegalStateException {
        if (a == null) return b == null;
        if (b == null) {
            // The contract stipulates that if either ByteStores are closed then we throw an Exception
            throwExceptionIfReleased(a);
            return false;
        }
        throwExceptionIfReleased(a);
        throwExceptionIfReleased(b);
        final long readRemaining = a.readRemaining();
        if (readRemaining != b.readRemaining())
            // The size is different so, we know that a and b cannot be equal
            return false;

        if (VECTORIZED_MISMATCH_METHOD_HANDLE != null
                && b.realReadRemaining() == a.realReadRemaining()
                && a.realReadRemaining() < Integer.MAX_VALUE
                && a.realReadRemaining() > 7
                && !(a instanceof HexDumpBytes) && !(b instanceof HexDumpBytes)) {

            // this will use AVX instructions, this is very fast; much faster than a handwritten loop.
            try {
                Boolean vectorizedResult = java11ContentEqualUsingVectorizedMismatch(a, b);
                if (vectorizedResult != null)
                    return vectorizedResult;
            } catch (UnsupportedOperationException e) {
                Jvm.warn().on(BytesInternal.class, e);
            }
        }

        return readRemaining <= Integer.MAX_VALUE
                ? contentEqualInt(a, b)
                : contentEqualsLong(a, b);
    }

    /**
     * returns true if the contents are equal using VectorizedMismatch*
     *
     * @param left  the byte on the left
     * @param right the byte on the right
     * @return true if the content are equal
     * see ...
     * JDK-8033148 will add methods to Arrays for array equals, compare and mismatch.
     * The implementations of equals, compare and mismatch can be reimplemented using underlying mismatch methods that in turn defer to a single method, vectorizedMismatch, that accesses the memory contents of arrays using Unsafe.getLongUnaligned.
     * The vectorizedMismatch implementation can be optimized efficiently by C2 to obtain an approximate 8x speed up when performing a mismatch on byte[] arrays (of a suitable size to overcome fixed costs).
     * The contract of vectorizedMismatch is simple enough that it can be made an intrinsic (see JDK-8044082) and leverage SIMDs instructions to perform operations up to a width of say 512 bits on supported architectures. Thus even further performance improvements may be possible.
     */
    private static Boolean java11ContentEqualUsingVectorizedMismatch(@NotNull final BytesStore left,
                                                                     @NotNull final BytesStore right) {
        try {
            final Object leftObject;
            final long leftOffset;

            if (left.isDirectMemory()) {
                leftObject = null;
                leftOffset = left.addressForRead(left.readPosition());
            } else {
                BytesStore bytesStore = left.bytesStore();
                if (!(bytesStore instanceof HeapBytesStore))
                    return null;

                HeapBytesStore heapBytesStore = (HeapBytesStore) bytesStore;
                leftObject = heapBytesStore.realUnderlyingObject();
                leftOffset = heapBytesStore.dataOffset() + left.readPosition();
            }

            final Object rightObject;
            final long rightOffset;

            if (right.isDirectMemory()) {
                rightObject = null;
                rightOffset = right.addressForRead(right.readPosition());
            } else {
                BytesStore bytesStore = right.bytesStore();
                if (!(bytesStore instanceof HeapBytesStore))
                    return null;

                HeapBytesStore heapBytesStore = (HeapBytesStore) bytesStore;
                rightObject = heapBytesStore.realUnderlyingObject();
                rightOffset = heapBytesStore.dataOffset() + right.readPosition();
            }

            final int length = (int) left.realReadRemaining();
            final int invoke = (int) VECTORIZED_MISMATCH_METHOD_HANDLE.invoke(leftObject,
                    leftOffset,
                    rightObject,
                    rightOffset,
                    length,
                    0);

            if (invoke >= 0)
                return Boolean.FALSE;

            int remaining = length - ~invoke;

            for (; remaining < length; remaining++) {
                if (left.readByte(left.readPosition() + remaining) !=
                        right.readByte(right.readPosition() + remaining)) {
                    return Boolean.FALSE;
                }
            }

            return Boolean.TRUE;
        } catch (Throwable e) {
            Jvm.warn().on(BytesInternal.class, e);
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    // Optimise for the common case where the length is 31-bit.
    static  & HasUncheckedRandomDataInput>
    boolean contentEqualInt(@NotNull final BytesStore a,
                            @NotNull final BytesStore b) throws ClosedIllegalStateException {

        final int aLength = (int) a.realReadRemaining();
        final int bLength = (int) b.realReadRemaining();
        if (a instanceof HasUncheckedRandomDataInput && b instanceof HasUncheckedRandomDataInput) {
            // Make sure a >= b
            if (aLength < bLength)
                return contentEqualIntUnchecked((U) b, (U) a, bLength, aLength);
            else
                return contentEqualIntUnchecked((U) a, (U) b, aLength, bLength);
        } else {
            // Make sure a >= b
            if (aLength < bLength)
                return contentEqualInt(b, a, bLength, aLength);
            else
                return contentEqualInt(a, b, aLength, bLength);
        }
    }

    // a >= b here and we also know it is safe to read bLength
    static boolean contentEqualInt(@NotNull final BytesStore a,
                                   @NotNull final BytesStore b,
                                   @NonNegative final int aLength,
                                   @NonNegative final int bLength) throws ClosedIllegalStateException {
        assert SKIP_ASSERTIONS || aLength >= bLength;
        final long aPos = a.readPosition();
        final long bPos = b.readPosition();

        int i;
        for (i = 0; i < bLength - 7; i += 8) {
            if (a.readLong(aPos + i) != b.readLong(bPos + i))
                return false;
        }
        for (; i < bLength; i++) {
            if (a.readByte(aPos + i) != b.readByte(bPos + i))
                return false;
        }
        // check for zeros
        for (; i < aLength - 7; i += 8) {
            if (a.readLong(aPos + i) != 0L)
                return false;
        }
        for (; i < aLength; i++) {
            if (a.readByte(aPos + i) != 0)
                return false;
        }

        return true;
    }

    // a >= b here and we also know it is safe to read bLength
    static  & HasUncheckedRandomDataInput>
    boolean contentEqualIntUnchecked(@NotNull final U a,
                                     @NotNull final U b,
                                     @NonNegative final int aLength,
                                     @NonNegative final int bLength) throws ClosedIllegalStateException {
        assert SKIP_ASSERTIONS || aLength >= bLength;
        final UncheckedRandomDataInput ua = a.acquireUncheckedInput();
        final UncheckedRandomDataInput ub = b.acquireUncheckedInput();
        final long aPos = a.readPosition();
        final long bPos = b.readPosition();

        int i;
        for (i = 0; i < bLength - 7; i += 8) {
            if (ua.readLong(aPos + i) != ub.readLong(bPos + i))
                return false;
        }
        for (; i < bLength; i++) {
            if (ua.readByte(aPos + i) != ub.readByte(bPos + i))
                return false;
        }
        // check for zeros
        for (; i < aLength - 7; i += 8) {
            if (ua.readLong(aPos + i) != 0L)
                return false;
        }
        for (; i < aLength; i++) {
            if (ua.readByte(aPos + i) != 0)
                return false;
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    static  & HasUncheckedRandomDataInput>
    boolean contentEqualsLong(@NotNull final BytesStore a,
                              @NotNull final BytesStore b) {
        final long aLength = a.realReadRemaining();
        final long bLength = b.realReadRemaining();
        if (a instanceof HasUncheckedRandomDataInput && b instanceof HasUncheckedRandomDataInput) {
            // Make sure a >= b
            if (a.realCapacity() < b.realCapacity())
                return contentEqualsLongUnchecked((U) b, (U) a, bLength, aLength);
            else
                return contentEqualsLongUnchecked((U) a, (U) b, aLength, bLength);
        } else {
            // Make sure a >= b
            if (a.realCapacity() < b.realCapacity())
                return contentEqualsLong(b, a, bLength, aLength);
            else
                return contentEqualsLong(a, b, aLength, bLength);
        }
    }

    // a >= b here and we also know it is safe to read bLength
    private static boolean contentEqualsLong(@NotNull final BytesStore a,
                                             @NotNull final BytesStore b,
                                             @NonNegative final long aLength,
                                             @NonNegative final long bLength) throws ClosedIllegalStateException {
        assert SKIP_ASSERTIONS || aLength >= bLength;
        // assume a >= b
        long aPos = a.readPosition();
        long bPos = b.readPosition();

        long i;
        for (i = 0; i < bLength - 7; i += 8) {
            if (a.readLong(aPos + i) != b.readLong(bPos + i))
                return false;
        }
        for (; i < bLength; i++) {
            if (a.readByte(aPos + i) != b.readByte(bPos + i))
                return false;
        }
        // check for zeros
        for (; i < aLength - 7; i += 8) {
            if (a.readLong(aPos + i) != 0L)
                return false;
        }
        for (; i < aLength; i++) {
            if (a.readByte(aPos + i) != 0)
                return false;
        }
        return true;
    }

    // a >= b here and we also know it is safe to read bLength
    private static  & HasUncheckedRandomDataInput>
    boolean contentEqualsLongUnchecked(@NotNull final U a,
                                       @NotNull final U b,
                                       @NonNegative final long aLength,
                                       @NonNegative final long bLength) {
        assert SKIP_ASSERTIONS || aLength >= bLength;

        final UncheckedRandomDataInput ua = a.acquireUncheckedInput();
        final UncheckedRandomDataInput ub = b.acquireUncheckedInput();

        // assume a >= b
        long aPos = a.readPosition();
        long bPos = b.readPosition();

        long i;
        for (i = 0; i < bLength - 7; i += 8) {
            if (ua.readLong(aPos + i) != ub.readLong(bPos + i))
                return false;
        }
        for (; i < bLength; i++) {
            if (ua.readByte(aPos + i) != ub.readByte(bPos + i))
                return false;
        }
        // check for zeros
        for (; i < aLength - 7; i += 8) {
            if (ua.readLong(aPos + i) != 0L)
                return false;
        }
        for (; i < aLength; i++) {
            if (ua.readByte(aPos + i) != 0)
                return false;
        }
        return true;
    }

    public static boolean startsWith(@NotNull BytesStore a, @NotNull BytesStore b)
            throws ClosedIllegalStateException {
        throwExceptionIfReleased(a);
        throwExceptionIfReleased(b);
        final long bRealReadRemaining = b.realReadRemaining();
        if (a.realReadRemaining() < bRealReadRemaining)
            return false;

        return startsWith(a, b, a.readPosition(), b.readPosition(), bRealReadRemaining);
    }

    public static  & HasUncheckedRandomDataInput>
    boolean startsWithUnchecked(@NotNull final U a,
                                @NotNull final BytesStore b) {
        throwExceptionIfReleased(a);
        throwExceptionIfReleased(b);
        final long bRealReadRemaining = b.realReadRemaining();
        if (a.realReadRemaining() < bRealReadRemaining) {
            return false;
        }

        if (b instanceof HasUncheckedRandomDataInput) {
            // We have hoisted out boundary checks in this path
            return startsWithUnchecked(a.acquireUncheckedInput(),
                    ((HasUncheckedRandomDataInput) b).acquireUncheckedInput(),
                    a.readPosition(),
                    b.readPosition(),
                    bRealReadRemaining);
        } else {
            return startsWith(a, b, a.readPosition(), b.readPosition(), bRealReadRemaining);
        }
    }

    private static boolean startsWithUnchecked(@NotNull final UncheckedRandomDataInput ua,
                                               @NotNull final UncheckedRandomDataInput ub,
                                               @NonNegative final long aPos,
                                               @NonNegative final long bPos,
                                               @NonNegative final long length) {
        int i;
        for (i = 0; i < length - 7; i += 8) {
            if (ua.readLong(aPos + i) != ub.readLong(bPos + i))
                return false;
        }
        if (i < length - 3) {
            if (ua.readInt(aPos + i) != ub.readInt(bPos + i))
                return false;
            i += 4;
        }
        if (i < length - 1) {
            if (ua.readShort(aPos + i) != ub.readShort(bPos + i))
                return false;
            i += 2;
        }
        if (i < length) {
            return ua.readByte(aPos + i) == ub.readByte(bPos + i);
        }
        return true;
    }

    private static boolean startsWith(@NotNull final BytesStore a,
                                      @NotNull final BytesStore b,
                                      @NonNegative final long aPos,
                                      @NonNegative final long bPos,
                                      @NonNegative final long length) {
        int i;
        for (i = 0; i < length - 7; i += 8) {
            if (a.readLong(aPos + i) != b.readLong(bPos + i))
                return false;
        }
        if (i < length - 3) {
            if (a.readInt(aPos + i) != b.readInt(bPos + i))
                return false;
            i += 4;
        }
        if (i < length - 1) {
            if (a.readShort(aPos + i) != b.readShort(bPos + i))
                return false;
            i += 2;
        }
        if (i < length) {
            return a.readByte(aPos + i) == b.readByte(bPos + i);
        }
        return true;
    }

    public static void parseUtf8(
            @NotNull StreamingDataInput bytes, Appendable appendable, boolean utf, @NonNegative int length)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        // Because Bytes implements Appendable, we need to check if it might be closed
        throwExceptionIfReleased(appendable);
        if (appendable instanceof StringBuilder
                && bytes.isDirectMemory()
                && length < 1 << 20
                && utf) {
            // todo fix, a problem with very long sequences. #35
            parseUtf8_SB1((Bytes) bytes, (StringBuilder) appendable, utf, length);
        } else {
            parseUtf81(bytes, appendable, utf, length);
        }
    }

    public static void parseUtf8(
            @NotNull RandomDataInput input, @NonNegative long offset, Appendable appendable, boolean utf, @NonNegative int length)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, ClosedIllegalStateException {

        assert utf;
        throwExceptionIfReleased(input);
        throwExceptionIfReleased(appendable);
        if (appendable instanceof StringBuilder) {
            if (input instanceof NativeBytesStore) {
                parseUtf8_SB1((NativeBytesStore) input, offset, (StringBuilder) appendable, length);
                return;
            } else if (input instanceof Bytes
                    && ((Bytes) input).bytesStore() instanceof NativeBytesStore) {
                @Nullable NativeBytesStore bs = (NativeBytesStore) ((Bytes) input).bytesStore();
                parseUtf8_SB1(bs, offset, (StringBuilder) appendable, length);
                return;
            }
        }
        parseUtf81(input, offset, appendable, length);
    }

    public static boolean compareUtf8(@NotNull RandomDataInput input, @NonNegative long offset, @Nullable CharSequence other)
            throws IORuntimeException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(input);
        if (other != null)
            throwExceptionIfReleased(other);

        long utfLen;
        if ((utfLen = input.readByte(offset++)) < 0) {
            utfLen &= 0x7FL;
            long b;
            int count = 7;
            while ((b = input.readByte(offset++)) < 0) {
                utfLen |= (b & 0x7FL) << count;
                count += 7;
            }
            if (b != 0) {
                if (count > 56)
                    throw new IORuntimeException(
                            "Cannot read more than 9 stop bits of positive value");
                utfLen |= (b << count);
            } else {
                if (count > 63)
                    throw new IORuntimeException(
                            "Cannot read more than 10 stop bits of negative value");
                utfLen = ~utfLen;
            }
        }
        if (utfLen == -1)
            return other == null;
        return other != null && compareUtf8(input, offset, utfLen, other);
    }

    private static boolean compareUtf8(
            @NotNull RandomDataInput input, @NonNegative long offset, @NonNegative long utfLen, @NotNull CharSequence other)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, IndexOutOfBoundsException, ClosedIllegalStateException {
        throwExceptionIfReleased(input);
        throwExceptionIfReleased(other);
        if (offset + utfLen > input.realCapacity())
            throw new BufferUnderflowException();
        int i = 0;
        while (i < utfLen && i < other.length()) {
            int c = input.readByte(offset + i);
            if (c < 0)
                break;
            if ((char) c != other.charAt(i))
                return false;
            i++;
        }
        if (i < utfLen && i < other.length())
            return compareUtf82(input, offset + i, i, utfLen, other);
        return utfLen == other.length();
    }

    private static boolean compareUtf82(
            @NotNull RandomDataInput input, @NonNegative long offset, int charI, @NonNegative long utfLen, @NotNull CharSequence other)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, IndexOutOfBoundsException, ClosedIllegalStateException {
        throwExceptionIfReleased(input);
        throwExceptionIfReleased(other);
        long limit = offset + utfLen;
        while (offset < limit && charI < other.length()) {
            int c = input.readUnsignedByte(offset++);
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    if ((char) c != other.charAt(charI))
                        return false;
                    break;

                case 12:
                case 13: {
                    /* 110x xxxx 10xx xxxx */
                    if (offset == limit)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END);
                    int char2 = input.readUnsignedByte(offset++);
                    if ((char2 & 0xC0) != 0x80)
                        throw newUTFDataFormatRuntimeException((offset - limit + utfLen), "was " + char2);
                    int c2 = (char) (((c & 0x1F) << 6) |
                            (char2 & 0x3F));
                    if ((char) c2 != other.charAt(charI))
                        return false;
                    break;
                }

                case 14: {
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    if (offset + 2 > limit)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END);
                    int char2 = input.readUnsignedByte(offset++);
                    int char3 = input.readUnsignedByte(offset++);

                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_AROUND_BYTE + (offset - limit + utfLen - 1) +
                                        WAS + char2 + " " + char3);
                    int c3 = (char) (((c & 0x0F) << 12) |
                            ((char2 & 0x3F) << 6) |
                            (char3 & 0x3F));
                    if ((char) c3 != other.charAt(charI))
                        return false;
                    break;
                }
                // TODO add code point of characters > 0xFFFF support.
                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw newUTFDataFormatRuntimeException(offset - limit + utfLen, "");
            }
            charI++;
        }
        return offset == limit && charI == other.length();
    }

    public static void parse8bit(@NonNegative long offset, @NotNull RandomDataInput bytesStore, Appendable appendable, @NonNegative int utflen)
            throws BufferUnderflowException, IOException, ClosedIllegalStateException {
        throwExceptionIfReleased(bytesStore);
        throwExceptionIfReleased(appendable);
        if (bytesStore instanceof NativeBytesStore
                && appendable instanceof StringBuilder) {
            parse8bit_SB1(offset, (NativeBytesStore) bytesStore, (StringBuilder) appendable, utflen);
        } else {
            parse8bit1(offset, bytesStore, appendable, utflen);
        }
    }

    public static void parseUtf81(
            @NotNull StreamingDataInput bytes, @NotNull Appendable appendable, boolean utf, @NonNegative int length)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(appendable);
        if (bytes.readRemaining() < length)
            throw new IllegalArgumentException();
        try {
            int count = 0;
            while (count < length) {
                int c = bytes.rawReadByte();
                if (c < 0) {
                    bytes.readSkip(-1);
                    break;
                }
                count++;
                appendable.append((char) c);
            }

            if (length > count)
                parseUtf82(bytes, appendable, utf, length, count);
        } catch (IOException e) {
            throw Jvm.rethrow(e);
        }
    }

    public static void parseUtf81(@NotNull RandomDataInput input, @NonNegative long offset,
                                  @NotNull Appendable appendable, int utflen)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(input);
        throwExceptionIfReleased(appendable);
        try {
            assert input.realCapacity() >= offset + utflen;
            long limit = offset + utflen;
            while (offset < limit) {
                int c = input.readUnsignedByte(offset++);
                if (c >= 128) {
                    offset--;
                    break;

                } else if (c < 0) {
                    break;
                }
                appendable.append((char) c);
            }

            if (limit > offset)
                parseUtf82(input, offset, limit, appendable, utflen);
        } catch (IOException e) {
            throw Jvm.rethrow(e);
        }
    }

    public static void parse8bit1(@NotNull StreamingDataInput bytes, @NotNull StringBuilder sb, @NonNegative int utflen)
            throws ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        if (bytes.readRemaining() < utflen)
            throw new IllegalArgumentException();
        sb.ensureCapacity(utflen);

        if (Jvm.isJava9Plus()) {
            byte[] sbBytes = extractBytes(sb);
            for (int count = 0; count < utflen; count++) {
                int c = bytes.readUnsignedByte();
                sbBytes[count] = (byte) c;
            }
        } else {
            char[] chars = StringUtils.extractChars(sb);
            for (int count = 0; count < utflen; count++) {
                int c = bytes.readUnsignedByte();
                chars[count] = (char) c;
            }
        }
        StringUtils.setLength(sb, utflen);
    }

    public static void parse8bit1(@NotNull StreamingDataInput bytes, @NotNull Appendable appendable, @NonNegative int utflen)
            throws ClosedIllegalStateException, IOException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(appendable);
        assert bytes.readRemaining() >= utflen;
        for (int count = 0; count < utflen; count++) {
            int c = bytes.readUnsignedByte();
            appendable.append((char) c);
        }
    }

    public static void parse8bit1(@NonNegative long offset, @NotNull RandomDataInput bytes, @NotNull Appendable appendable, @NonNegative int utflen)
            throws BufferUnderflowException, ClosedIllegalStateException, IOException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(appendable);
        if (bytes.realCapacity() < utflen + offset)
            throw new DecoratedBufferUnderflowException(bytes.realCapacity() + " < " + utflen + " +" + offset);
        for (int count = 0; count < utflen; count++) {
            int c = bytes.readUnsignedByte(offset + count);
            appendable.append((char) c);
        }
    }

    public static void parseUtf8_SB1(@NotNull Bytes bytes, @NotNull StringBuilder sb, boolean utf, @NonNegative int utflen)
            throws UTFDataFormatRuntimeException, BufferUnderflowException {
        try {
            throwExceptionIfReleased(bytes);
            assert utf;

            if (utflen > bytes.readRemaining()) {
                @NotNull final BufferUnderflowException bue = new BufferUnderflowException();
                bue.initCause(new ClosedIllegalStateException("utflen: " + utflen + ", readRemaining: " + bytes.readRemaining()));
                throw bue;
            }
            long readPosition = bytes.readPosition();
            sb.ensureCapacity(utflen);

            int count = calculateCount(bytes, sb, utflen, readPosition);

            bytes.readSkip(count);
            setCount(sb, count);
            if (count < utflen) {
                final long rp0 = bytes.readPosition();
                parseUtf82Guarded(bytes, sb, utf, utflen, count, rp0);
            }
        } catch (IOException | ClosedIllegalStateException e) {
            throw Jvm.rethrow(e);
        }
    }

    private static void parseUtf82Guarded(@NotNull Bytes bytes, @NotNull StringBuilder sb, boolean utf, @NonNegative int utflen, int count, long rp0) throws IOException {
        try {
            parseUtf82(bytes, sb, utf, utflen, count);
        } catch (UTFDataFormatRuntimeException e) {
            long rp = Math.max(rp0 - 128, 0);
            throw new UTFDataFormatRuntimeException(Long.toHexString(rp0) + "\n" + bytes.toHexString(rp, 200), e);
        }
    }

    private static int calculateCount(@NotNull Bytes bytes, @NotNull StringBuilder sb, @NonNegative int utflen, @NonNegative long readPosition) throws ClosedIllegalStateException {
        int count = 0;
        if (Jvm.isJava9Plus()) {
            sb.setLength(utflen);
            while (count < utflen) {
                byte c = bytes.readByte(readPosition + count);
                if (c < 0)
                    break;
                sb.setCharAt(count++, (char) c); // This is not as fast as it could be.
            }
        } else {
            final char[] chars = extractChars(sb);
            while (count < utflen) {
                int c = bytes.readByte(readPosition + count);
                if (c < 0)
                    break;
                chars[count++] = (char) c;
            }
        }
        return count;
    }

    public static void parseUtf8_SB1(@NotNull NativeBytesStore bytes, @NonNegative long offset,
                                     @NotNull StringBuilder sb, @NonNegative int utflen)
            throws UTFDataFormatRuntimeException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        requireNonNull(sb);
        try {
            if (offset + utflen > bytes.realCapacity())
                throw new BufferUnderflowException();
            long address = bytes.address + bytes.translate(offset);
            Memory memory = bytes.memory;
            sb.ensureCapacity(utflen);
            int count = 0;

            if (Jvm.isJava9Plus()) {
                sb.setLength(utflen);
                while (count < utflen) {
                    byte c = memory.readByte(address + count);
                    if (c < 0)
                        break;
                    sb.setCharAt(count++, (char) c);
                }
            } else {
                char[] chars = extractChars(sb);
                while (count < utflen) {
                    int c = memory.readByte(address + count);
                    if (c < 0)
                        break;
                    chars[count++] = (char) c;
                }
            }
            setCount(sb, count);
            if (count < utflen)
                parseUtf82(bytes, offset + count, offset + utflen, sb, utflen);
            assert bytes.memory != null;
        } catch (IOException e) {
            throw Jvm.rethrow(e);
        }
    }

    public static int parse8bit_SB1(@NonNegative long offset, @NotNull NativeBytesStore nbs, @NotNull StringBuilder sb, @NonNegative int length) {
        throwExceptionIfReleased(nbs);
        requireNonNull(sb);
        long address = nbs.address + nbs.translate(offset);
        @Nullable Memory memory = nbs.memory;
        sb.ensureCapacity(length);
        int count = 0;

        if (Jvm.isJava9Plus()) {
            byte coder = getStringCoder(sb);

            if (coder == JAVA9_STRING_CODER_LATIN) {
                byte[] bytes = extractBytes(sb);
                while (count < length) {
                    byte b = memory.readByte(address + count);
                    bytes[count++] = b;
                }
            } else {
                assert coder == JAVA9_STRING_CODER_UTF16;
                sb.setLength(length);
                while (count < length) {
                    byte b = memory.readByte(address + count);
                    sb.setCharAt(count++, (char) b);
                }
            }
        } else {
            char[] chars = extractChars(sb);
            while (count < length) {
                int c = memory.readByte(address + count) & 0xFF;
                chars[count++] = (char) c;
            }
        }
        setCount(sb, count);
        return count;
    }

    static void parseUtf82(@NotNull StreamingDataInput bytes, @NotNull Appendable appendable, boolean utf, @NonNegative int length, @NonNegative int count)
            throws IOException, UTFDataFormatRuntimeException, ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(appendable);
        while (count < length) {
            int c = bytes.readUnsignedByte();
            if (c < 0)
                break;
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    count++;
                    appendable.append((char) c);
                    break;

                case 12:
                case 13: {
                    /* 110x xxxx 10xx xxxx */
                    count += utf ? 2 : 1;
                    if (count > length)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END);
                    int char2 = bytes.readUnsignedByte();
                    if ((char2 & 0xC0) != 0x80)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_AROUND_BYTE + count + WAS + char2);
                    int c2 = (char) (((c & 0x1F) << 6) |
                            (char2 & 0x3F));
                    appendable.append((char) c2);
                    break;
                }

                case 14: {
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    count += utf ? 3 : 1;
                    if (count > length)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END);
                    int char2 = bytes.readUnsignedByte();
                    int char3 = bytes.readUnsignedByte();

                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw newUTFDataFormatRuntimeException(count - 1L, WAS + char2 + " " + char3);
                    int c3 = (char) (((c & 0x0F) << 12) |
                            ((char2 & 0x3F) << 6) |
                            (char3 & 0x3F));
                    appendable.append((char) c3);
                    break;
                }
                // TODO add code point of characters > 0xFFFF support.
                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw newUTFDataFormatRuntimeException(count, "");
            }
        }
    }

    static void parseUtf82(@NotNull RandomDataInput input, @NonNegative long offset, @NonNegative long limit,
                           @NotNull Appendable appendable, @NonNegative int utflen)
            throws IOException, UTFDataFormatRuntimeException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(input);
        throwExceptionIfReleased(appendable);
        while (offset < limit) {
            int c = input.readUnsignedByte(offset++);
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    appendable.append((char) c);
                    break;

                case 12:
                case 13: {
                    /* 110x xxxx 10xx xxxx */
                    if (offset == limit)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END);
                    int char2 = input.readUnsignedByte(offset++);
                    if ((char2 & 0xC0) != 0x80)
                        throw newUTFDataFormatRuntimeException(offset - limit + utflen, "was " + char2);
                    int c2 = (char) (((c & 0x1F) << 6) |
                            (char2 & 0x3F));
                    appendable.append((char) c2);
                    break;
                }

                case 14: {
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    if (offset + 2 > limit)
                        throw new UTFDataFormatRuntimeException(
                                MALFORMED_INPUT_PARTIAL_CHARACTER_AT_END);
                    int char2 = input.readUnsignedByte(offset++);
                    int char3 = input.readUnsignedByte(offset++);

                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw newUTFDataFormatRuntimeException(offset - limit + utflen - 1, WAS + char2 + " " + char3);
                    int c3 = (char) (((c & 0x0F) << 12) |
                            ((char2 & 0x3F) << 6) |
                            (char3 & 0x3F));
                    appendable.append((char) c3);
                    break;
                }
                // TODO add code point of characters > 0xFFFF support.
                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw newUTFDataFormatRuntimeException(offset - limit + utflen, "");
            }
        }
    }

    public static void writeUtf8(@NotNull StreamingDataOutput bytes, @Nullable String str)
            throws BufferOverflowException, ClosedIllegalStateException, IllegalArgumentException, BufferUnderflowException {
        throwExceptionIfReleased(bytes);
        if (str == null) {
            BytesInternal.writeStopBitNeg1(bytes);
            return;
        }

        if (Jvm.isJava9Plus()) {
            byte[] strBytes = extractBytes(str);
            byte coder = StringUtils.getStringCoder(str);
            long utfLength = AppendableUtil.findUtf8Length(strBytes, coder);
            bytes.writeStopBit(utfLength);
            bytes.appendUtf8(strBytes, 0, str.length(), coder);
        } else {
            char[] chars = extractChars(str);
            long utfLength = AppendableUtil.findUtf8Length(chars);
            bytes.writeStopBit(utfLength);
            bytes.appendUtf8(chars, 0, chars.length);
        }
    }

    public static void writeUtf8(@NotNull StreamingDataOutput bytes, @Nullable CharSequence str)
            throws BufferOverflowException, ClosedIllegalStateException, BufferUnderflowException, IllegalArgumentException {
        throwExceptionIfReleased(bytes);
        if (str instanceof String) {
            writeUtf8(bytes, (String) str);
            return;
        }
        if (str == null) {
            BytesInternal.writeStopBitNeg1(bytes);

        } else {
            long utfLength = AppendableUtil.findUtf8Length(str);
            bytes.writeStopBit(utfLength);
            appendUtf8(bytes, str, 0, str.length());
        }
    }

    public static long writeUtf8(@NotNull RandomDataOutput out,
                                 @NonNegative long writeOffset,
                                 @Nullable CharSequence str)
            throws BufferOverflowException, ClosedIllegalStateException, ArithmeticException {
        throwExceptionIfReleased(out);
        requireNonNegative(writeOffset);
        if (str == null) {
            writeOffset = writeStopBit(out, writeOffset, -1);

        } else {
            int strLength = str.length();
            if (strLength < 32) {
                long lenOffset = writeOffset;
                writeOffset = appendUtf8(out, writeOffset + 1, str, 0, strLength);
                long utfLength = writeOffset - lenOffset - 1;
                assert utfLength <= 127;
                writeStopBit(out, lenOffset, utfLength);
            } else {
                long utfLength = AppendableUtil.findUtf8Length(str);
                writeOffset = writeStopBit(out, writeOffset, utfLength);
                if (utfLength == strLength) {
                    append8bit(writeOffset, out, str, 0, strLength);
                    writeOffset += utfLength;
                } else {
                    writeOffset = appendUtf8(out, writeOffset, str, 0, strLength);
                }
            }
        }
        return writeOffset;
    }

    public static long writeUtf8(@NotNull final RandomDataOutput out,
                                 @NonNegative long offset,
                                 @Nullable final CharSequence str,
                                 @NonNegative int maxUtf8Len) throws BufferOverflowException, ClosedIllegalStateException, ArithmeticException {
        requireNonNegative(offset);
        throwExceptionIfReleased(out);
        if (str == null) {
            offset = writeStopBit(out, offset, -1);

        } else {
            int strLength = str.length();
            long utfLength = AppendableUtil.findUtf8Length(str);
            if (utfLength > maxUtf8Len) {
                throw new IllegalArgumentException("Attempted to write a char sequence of " +
                        "utf8 size " + utfLength + ": \"" + str +
                        "\", when only " + maxUtf8Len + " allowed");
            }
            offset = writeStopBit(out, offset, utfLength);
            if (utfLength == strLength) {
                append8bit(offset, out, str, 0, strLength);
                offset += utfLength;
            } else {
                offset = appendUtf8(out, offset, str, 0, strLength);
            }
        }
        return offset;
    }

    @NotNull
    public static Bytes asBytes(@NotNull RandomDataOutput bytes, @NonNegative long position, @NonNegative long limit)
            throws ClosedIllegalStateException, BufferOverflowException, BufferUnderflowException {
        throwExceptionIfReleased(bytes);
        Bytes sbytes = bytes.bytesForWrite();
        sbytes.writeLimit(limit);
        sbytes.readLimit(limit);
        sbytes.readPosition(position);
        return sbytes;
    }

    public static void appendUtf8(@NotNull StreamingDataOutput bytes,
                                  @NotNull CharSequence str, @NonNegative int offset, @NonNegative int length)
            throws IndexOutOfBoundsException, ClosedIllegalStateException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(str);
        try {
            int i;
            for (i = 0; i < length; i++) {
                char c = str.charAt(offset + i);
                if (c > 0x007F)
                    break;
                bytes.rawWriteByte((byte) c);
            }
            appendUtf82(bytes, str, offset, length, i);
        } catch (BufferOverflowException | ClosedIllegalStateException e) {
            throw Jvm.rethrow(e);
        }
    }

    private static void appendUtf82(@NotNull StreamingDataOutput bytes,
                                    @NotNull CharSequence str, @NonNegative int offset, @NonNegative int length, @NonNegative int i)
            throws IndexOutOfBoundsException, BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(str);
        for (; i < length; i++) {
            char c = str.charAt(offset + i);
            appendUtf8Char(bytes, c);
        }
    }

    public static long appendUtf8(@NotNull RandomDataOutput out, @NonNegative long outOffset,
                                  @NotNull CharSequence str, @NonNegative int strOffset, @NonNegative int length)
            throws IndexOutOfBoundsException, BufferOverflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(out);
        throwExceptionIfReleased(str);
        int i;
        for (i = 0; i < length; i++) {
            char c = str.charAt(strOffset + i);
            if (c > 0x007F)
                break;
            out.writeByte(outOffset++, (byte) c);
        }
        return appendUtf82(out, outOffset, str, strOffset, length, i);
    }

    private static long appendUtf82(@NotNull RandomDataOutput out, @NonNegative long outOffset,
                                    @NotNull CharSequence str, @NonNegative int strOffset, @NonNegative int length, @NonNegative int i)
            throws IndexOutOfBoundsException, BufferOverflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(out);
        throwExceptionIfReleased(str);
        for (; i < length; i++) {
            char c = str.charAt(strOffset + i);
            outOffset = appendUtf8Char(out, outOffset, c);
        }
        return outOffset;
    }

    public static void append8bit(@NonNegative long offsetInRDO, RandomDataOutput bytes, @NotNull CharSequence str, @NonNegative int offset, @NonNegative int length)
            throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException,
            IndexOutOfBoundsException, ClosedIllegalStateException, ArithmeticException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(str);
        if (bytes instanceof VanillaBytes) {
            @NotNull VanillaBytes vb = (VanillaBytes) bytes;
            if (str instanceof RandomDataInput) {
                vb.write(offsetInRDO, (RandomDataInput) str, offset, length);
                return;
            }
            if (str instanceof String) {
                vb.write(offsetInRDO, str, offset, length);
                return;
            }
        }
        for (int i = 0; i < length; i++) {
            char c = str.charAt(offset + i);
            if (c > 255) c = '?';
            bytes.writeUnsignedByte(offsetInRDO + i, c);
        }
    }

    public static void appendUtf8Char(@NotNull StreamingDataOutput bytes, int c)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        if (c <= 0x007F) {
            bytes.rawWriteByte((byte) c);

        } else if (c <= 0x07FF) {
            bytes.rawWriteByte((byte) (0xC0 | ((c >> 6) & 0x1F)));
            bytes.rawWriteByte((byte) (0x80 | c & 0x3F));

        } else if (c <= 0xFFFF) {
            bytes.rawWriteByte((byte) (0xE0 | ((c >> 12) & 0x0F)));
            bytes.rawWriteByte((byte) (0x80 | ((c >> 6) & 0x3F)));
            bytes.rawWriteByte((byte) (0x80 | (c & 0x3F)));

        } else {
            bytes.rawWriteByte((byte) (0xF0 | ((c >> 18) & 0x07)));
            bytes.rawWriteByte((byte) (0x80 | ((c >> 12) & 0x3F)));
            bytes.rawWriteByte((byte) (0x80 | ((c >> 6) & 0x3F)));
            bytes.rawWriteByte((byte) (0x80 | (c & 0x3F)));
        }
    }

    public static long appendUtf8Char(@NotNull RandomDataOutput out, @NonNegative long offset, int c)
            throws BufferOverflowException, ClosedIllegalStateException {
        if (c <= 0x007F) {
            out.writeByte(offset++, (byte) c);

        } else if (c <= 0x07FF) {
            out.writeByte(offset++, (byte) (0xC0 | ((c >> 6) & 0x1F)));
            out.writeByte(offset++, (byte) (0x80 | c & 0x3F));

        } else if (c <= 0xFFFF) {
            out.writeByte(offset++, (byte) (0xE0 | ((c >> 12) & 0x0F)));
            out.writeByte(offset++, (byte) (0x80 | ((c >> 6) & 0x3F)));
            out.writeByte(offset++, (byte) (0x80 | (c & 0x3F)));

        } else {
            out.writeByte(offset++, (byte) (0xF0 | ((c >> 18) & 0x07)));
            out.writeByte(offset++, (byte) (0x80 | ((c >> 12) & 0x3F)));
            out.writeByte(offset++, (byte) (0x80 | ((c >> 6) & 0x3F)));
            out.writeByte(offset++, (byte) (0x80 | (c & 0x3F)));
        }
        return offset;
    }

    public static void writeStopBitNeg1(@NotNull StreamingDataOutput out) {
        out.writeUnsignedShort(NEG_ONE);
    }

    public static void writeStopBit(@NotNull StreamingDataOutput out, char n)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        if ((n & ~0x7F) == 0) {
            out.rawWriteByte((byte) (n & 0x7f));
            return;
        }
        if ((n & ~0x3FFF) == 0) {
            out.rawWriteByte((byte) (n & 0x7f | 0x80));
            out.rawWriteByte((byte) (n >> 7));
            return;
        }
        if ((n & 0xFF80) == 0xFF80) {
            out.rawWriteByte((byte) (~n & 0x7f | 0x80));
            out.rawWriteByte((byte) 0);
            return;
        }
        writeStopBit0(out, n);
    }

    public static long writeStopBit(final long addr, final long n)
            throws BufferOverflowException {
        if ((n & ~0x7F) == 0) {
            UnsafeMemory.INSTANCE.writeByte(addr, (byte) n);
            return addr + 1;
        }
        if ((n & ~0x3FFF) == 0) {
            final int lo = (int) ((n & 0x7f) | 0x80);
            final int hi = (int) (n >> 7);
            UnsafeMemory.INSTANCE.writeByte(addr, (byte) lo);
            UnsafeMemory.INSTANCE.writeByte(addr + 1, (byte) hi);
            // Note: Refrain from using writeShort as this assumes a certain endian
            return addr + 2;
        }
        return writeStopBit0(addr, n);
    }

    public static void writeStopBit(@NotNull StreamingDataOutput out, long n)
            throws BufferOverflowException, ClosedIllegalStateException {
        if ((n & ~0x7F) == 0) {
            out.rawWriteByte((byte) n);
            return;
        }
        if ((n & ~0x3FFF) == 0) {
            out.rawWriteByte((byte) ((n & 0x7f) | 0x80));
            out.rawWriteByte((byte) (n >> 7));
            return;
        }
        writeStopBit0(out, n);
    }

    public static long writeStopBit(@NotNull RandomDataOutput out, @NonNegative long offset, long n)
            throws BufferOverflowException, ClosedIllegalStateException {
        if ((n & ~0x7F) == 0) {
            out.writeByte(offset++, (byte) n);
            return offset;
        }
        if ((n & ~0x3FFF) == 0) {
            out.writeByte(offset++, (byte) ((n & 0x7f) | 0x80));
            out.writeByte(offset++, (byte) (n >> 7));
            return offset;
        }
        return writeStopBit0(out, offset, n);
    }

    @SuppressWarnings("ShiftOutOfRange")
    public static void writeStopBit(@NotNull StreamingDataOutput out, double d)
            throws BufferOverflowException, ClosedIllegalStateException {
        long n = Double.doubleToRawLongBits(d);
        while ((n & (~0L >>> 7)) != 0) {
            out.rawWriteByte((byte) (((n >>> -7) & 0x7F) | 0x80));
            n <<= 7;
        }
        out.rawWriteByte((byte) ((n >>> -7) & 0x7F));
    }

    public static double readStopBitDouble(@NotNull StreamingDataInput in)
            throws ClosedIllegalStateException {
        long n = 0;
        int shift = 64 - 7;
        int b;
        do {
            b = in.readByte();
            n |= shift > 0 ? (long) (b & 0x7F) << shift : b >> -shift;
            shift -= 7;
        } while (b < 0);
        return Double.longBitsToDouble(n);
    }

    public static void writeStopBit0(@NotNull StreamingDataOutput out, long n)
            throws BufferOverflowException, ClosedIllegalStateException {
        boolean neg = false;
        if (n < 0) {
            neg = true;
            n = ~n;
        }

        long n2;
        while ((n2 = n >>> 7) != 0) {
            out.rawWriteByte((byte) (0x80L | n));
            n = n2;
        }
        // final byte
        if (!neg) {
            out.rawWriteByte((byte) n);

        } else {
            out.rawWriteByte((byte) (0x80L | n));
            out.rawWriteByte((byte) 0);
        }
    }

    static long writeStopBit0(long addr, long n)
            throws BufferOverflowException {
        int i = 0;
        boolean neg = false;
        if (n < 0) {
            neg = true;
            n = ~n;
        }

        long n2;
        while ((n2 = n >>> 7) != 0) {
            MEMORY.writeByte(addr + i++, (byte) (0x80L | n));
            n = n2;
        }
        // final byte
        if (!neg) {
            MEMORY.writeByte(addr + i++, (byte) n);

        } else {
            MEMORY.writeByte(addr + i++, (byte) (0x80L | n));
            MEMORY.writeByte(addr + i++, (byte) 0);
        }
        return addr + i;
    }

    static long writeStopBit0(@NotNull RandomDataOutput out, @NonNegative long offset, long n)
            throws BufferOverflowException, ClosedIllegalStateException {
        boolean neg = false;
        if (n < 0) {
            neg = true;
            n = ~n;
        }

        long n2;
        while ((n2 = n >>> 7) != 0) {
            out.writeByte(offset++, (byte) (0x80L | n));
            n = n2;
        }
        // final byte
        if (!neg) {
            out.writeByte(offset++, (byte) n);

        } else {
            out.writeByte(offset++, (byte) (0x80L | n));
            out.writeByte(offset++, (byte) 0);
        }
        return offset;
    }

    public static int stopBitLength0(long n) {
        int len = 0;
        if (n < 0) {
            len = 1;
            n = ~n;
        }

        while ((n >>>= 7) != 0) len++;
        return len + 1;
    }

    public static String toDebugString(@NotNull RandomDataInput bytes, @NonNegative long maxLength)
            throws ClosedIllegalStateException, ArithmeticException, ThreadingIllegalStateException {
        if (bytes.refCount() < 1) {
            // Make sure not to access a released resource
            return "";
        }
        ReferenceOwner toDebugString = temporary("toDebugString");
        bytes.reserve(toDebugString);
        try {
            int len = Maths.toUInt31(maxLength + 40);
            @NotNull StringBuilder sb = new StringBuilder(len);
            long readPosition = bytes.readPosition();
            long readLimit = bytes.readLimit();
            if (bytes instanceof HexDumpBytes) {
                readPosition = (int) readPosition;
                readLimit = (int) readLimit;
            }
            sb.append("[")
                    .append("pos: ").append(readPosition)
                    .append(", rlim: ").append(readLimit)
                    .append(", wlim: ").append(asSize(bytes.writeLimit()))
                    .append(", cap: ").append(asSize(bytes.capacity()))
                    .append(" ] ");
            appendContent(bytes, maxLength, sb, readPosition, readLimit);
            return sb.toString();

        } finally {
            bytes.release(toDebugString);
        }
    }

    private static void appendContent(@NotNull final RandomDataInput bytes,
                                      @NonNegative final long maxLength,
                                      @NotNull final StringBuilder sb,
                                      @NonNegative final long readPosition,
                                      @NonNegative final long readLimit) {
        try {
            final long start = Math.max(bytes.start(), readPosition - 64);
            long end = Math.min(readLimit + 64, start + maxLength);
            // should never try to read past the end of the buffer
            end = Math.min(end, bytes.realCapacity());
            try {
                for (; end >= start + 16 && end >= readLimit + 16; end -= 8) {
                    if (bytes.readLong(end - 8) != 0)
                        break;
                }
            } catch (@NotNull UnsupportedOperationException | BufferUnderflowException ignored) {
                // ignore
            }
            toString(bytes, sb, start, readPosition, readLimit, end);
            if (end < bytes.readLimit())
                sb.append("...");
        } catch (Exception e) {
            sb.append(' ').append(e);
        }
    }

    @NotNull
    public static Object asSize(@NonNegative long size) {
        return size == Bytes.MAX_CAPACITY ? "8EiB" : size;
    }

    public static String to8bitString(@NotNull BytesStore bytes) throws ClosedIllegalStateException {
        final long pos = bytes.readPosition();
        throwExceptionIfReleased(bytes);
        int len = (int) Math.min(Integer.MAX_VALUE, bytes.readRemaining());
        char[] chars = new char[len];
        if (bytes instanceof VanillaBytes) {
            try {
                ((VanillaBytes) bytes).read8Bit(chars, len);
            } catch (BufferUnderflowException | ClosedIllegalStateException e) {
                throw Jvm.rethrow(e);
            }
        } else {
            for (int i = 0; i < len; i++)
                try {
                    chars[i] = (char) bytes.readUnsignedByte(pos + i);
                } catch (Exception e) {
                    return new String(chars, 0, len) + ' ' + e;
                }
        }
        return StringUtils.newString(chars);
    }

    @NotNull
    public static String toString(@NotNull RandomDataInput bytes) {
        try {
            throwExceptionIfReleased(bytes);
            // the output will be no larger than this
            final long available = bytes.realReadRemaining();
            final int size = (int) Math.min(available, MAX_STRING_LEN - 3L);
            @NotNull final StringBuilder sb = new StringBuilder(size);

            if (bytes.readRemaining() > size) {
                final Bytes bytes1 = bytes.bytesForRead();
                try {
                    bytes1.readLimit(bytes1.readPosition() + size);
                    toString(bytes1, sb);
                    if (size < available)
                        sb.append("...");
                    return sb.toString();
                } finally {
                    bytes1.releaseLast();
                }
            } else {
                toString(bytes, sb);
                return sb.toString();
            }
        } catch (ClosedIllegalStateException | BufferUnderflowException e) {
            return e.toString();
        }
    }

    private static void toString(@NotNull RandomDataInput bytes,
                                 @NotNull Appendable sb,
                                 @NonNegative long start,
                                 @NonNegative long readPosition,
                                 @NonNegative long writePosition,
                                 @NonNegative long end)
            throws ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(sb);
        try {
            // before
            if (start < bytes.start()) start = bytes.start();
            long realCapacity = bytes.realCapacity();
            if (end > realCapacity) end = realCapacity;
            boolean showStartEnd = bytes instanceof Bytes && writePosition < end;
            if (readPosition >= start && showStartEnd) {
                long last = Math.min(readPosition, end);
                toString(bytes, sb, start, last);
                sb.append('\u01C1');
            }
            toString(bytes, sb, Math.max(readPosition, start), Math.min(writePosition, end));
            if (writePosition <= end) {
                if (showStartEnd)
                    sb.append('\u2021');
                toString(bytes, sb, writePosition, end);
            }
        } catch (Exception e) {
            try {
                sb.append(' ').append(e.toString());
            } catch (IOException e1) {
                throw new AssertionError(e);
            }
        }
    }

    private static void toString(@NotNull RandomDataInput bytes, @NotNull Appendable sb, @NonNegative long start, @NonNegative long last)
            throws IOException, BufferUnderflowException, ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(sb);
        for (long i = start; i < last; i++) {
            sb.append(bytes.printable(i));
        }
    }

    private static void toString(@NotNull RandomDataInput bytes, @NotNull StringBuilder sb)
            throws ClosedIllegalStateException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        requireNonNull(sb);
        ReferenceOwner toString = temporary("toString");
        bytes.reserve(toString);
        long start = bytes.readPosition();
        assert bytes.start() <= start;
        assert start <= bytes.readLimit();
        int length = Math.toIntExact(bytes.realReadRemaining());

        try {
            for (int i = 0; i < length; i++) {
                sb.append((char) bytes.readUnsignedByte(start + i));
            }
        } catch (BufferUnderflowException e) {
            sb.append(' ').append(e);

        } finally {
            bytes.release(toString);
        }
    }

    public static char readStopBitChar(@NotNull StreamingDataInput in)
            throws IORuntimeException, ClosedIllegalStateException {
        byte b;
        if ((b = in.rawReadByte()) >= 0)
            return (char) b;
        // see if it -1
        if (b == -128 && in.peekUnsignedByte() == 0) {
            in.readSkip(1);
            return Character.MAX_VALUE;
        }
        return (char) readStopBit0(in, b);
    }

    public static long readStopBit(@NotNull StreamingDataInput in)
            throws IORuntimeException, ClosedIllegalStateException {
        byte b;
        if ((b = in.rawReadByte()) >= 0)
            return b;
        // see if it -1
        if (b == -128 && in.peekUnsignedByte() == 0) {
            in.readSkip(1);
            return -1;
        }
        return readStopBit0(in, b);
    }

    public static long readStopBit0(@NotNull StreamingDataInput in, long l)
            throws IORuntimeException, ClosedIllegalStateException {
        l &= 0x7FL;
        long b;
        int count = 7;
        while ((b = in.rawReadByte()) < 0) {
            l |= (b & 0x7FL) << count;
            count += 7;
        }
        if (b != 0) {
            if (count > 56)
                throw new IORuntimeException(
                        "Cannot read more than 9 stop bits of positive value");
            return l | (b << count);

        } else {
            if (count > 63)
                throw new IORuntimeException(
                        "Cannot read more than 10 stop bits of negative value");
            return ~l;
        }
    }

    public static void append(@NotNull ByteStringAppender out, long num, int base)
            throws IllegalArgumentException, BufferOverflowException, ClosedIllegalStateException, IndexOutOfBoundsException, ThreadingIllegalStateException {
        if (num < 0) {
            if (num == Long.MIN_VALUE) {
                if (base == 10)
                    out.write(MIN_VALUE_TEXT);
                else
                    out.write(Long.toString(Long.MIN_VALUE, base));
                return;
            }
            out.rawWriteByte((byte) '-');
            num = -num;
        }
        if (num == 0) {
            out.rawWriteByte((byte) '0');

        } else {
            switch (base) {
                case 10:
                    appendBase10(out, num);
                    break;
                case 16:
                    appendBase16(out, num, 1);
                    break;
                default:
                    out.write(Long.toString(num, base));
                    break;
            }
        }
    }

    public static void appendBase10(@NotNull ByteStringAppender out, int num)
            throws BufferOverflowException, ClosedIllegalStateException {
        appendBase10(out, (long) num);
    }

    public static void appendBase10(@NotNull ByteStringAppender out, long num)
            throws BufferOverflowException, ClosedIllegalStateException {
        if (out.canWriteDirect(20)) {
            long address = out.addressForWrite(out.writePosition());
            long address2 = UnsafeText.appendFixed(address, num);
            out.writeSkip(address2 - address);
        } else {
            appendLong0(out, num);
        }
    }

    public static void appendBase16(@NotNull ByteStringAppender out, long num, int minDigits)
            throws IllegalArgumentException, BufferOverflowException, ClosedIllegalStateException {
        int digits = 16 - Long.numberOfLeadingZeros(num) / 4;
        digits = Math.max(minDigits, digits);
        int shift = Math.max(4, digits << 2);
        do {
            shift -= 4;
            int digit = (int) ((num >>> shift) & 0xF);

            out.rawWriteByte((byte) HEXADECIMAL[digit]);
        } while (shift > 0);
    }

    public static void appendDecimal(@NotNull ByteStringAppender out, long num, int decimalPlaces)
            throws BufferOverflowException, ClosedIllegalStateException, ArithmeticException, IllegalArgumentException, ThreadingIllegalStateException {
        if (decimalPlaces == 0) {
            appendBase10(out, num);
            return;
        }

        byte[] numberBuffer = BYTE_ARRAY_TL.get();
        int endIndex;
        if (num < 0) {
            if (num == Long.MIN_VALUE) {
                numberBuffer = MIN_VALUE_TEXT;
                endIndex = MIN_VALUE_TEXT.length;
            } else {
                out.rawWriteByte((byte) '-');
                num = -num;
                endIndex = appendLong1(numberBuffer, num);
            }
        } else {
            endIndex = appendLong1(numberBuffer, num);
        }
        int digits = numberBuffer.length - endIndex;
        if (decimalPlaces >= digits) {
            out.writeUnsignedByte('0');
            out.writeUnsignedByte('.');
            while (decimalPlaces-- > digits)
                out.writeUnsignedByte('0');
            out.write(numberBuffer, endIndex, digits);
            return;
        }

        int decimalLength = numberBuffer.length - endIndex - decimalPlaces;
        out.write(numberBuffer, endIndex, decimalLength);
        out.writeUnsignedByte('.');
        out.write(numberBuffer, endIndex + decimalLength, digits - decimalLength);
    }

    public static void prepend(@NotNull BytesPrepender out, long num)
            throws BufferOverflowException, ClosedIllegalStateException {
        boolean neg = false;
        if (num < 0) {
            if (num == Long.MIN_VALUE) {
                out.prewrite(MIN_VALUE_TEXT);
                return;
            }
            neg = true;
            num = -num;
        }
        do {
            out.prewriteByte((byte) (num % 10 + '0'));
            num /= 10;
        } while (num > 0);
        if (neg)
            out.prewriteByte((byte) '-');
    }

    /**
     * The length of the number must be fixed otherwise short numbers will not overwrite longer
     * numbers
     *
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    public static void append(@NotNull RandomDataOutput out, @NonNegative long offset, long num, int digits)
            throws BufferOverflowException, IllegalArgumentException, ClosedIllegalStateException, ThreadingIllegalStateException {
        boolean negative = num < 0;
        num = Math.abs(num);

        for (int i = digits - 1; i > 0; i--) {
            out.writeByte(offset + i, (byte) (num % 10 + '0'));
            num /= 10;
        }
        if (negative) {
            if (num != 0)
                numberTooLarge(digits);
            out.writeByte(offset, (byte) '-');

        } else {
            if (num > 9)
                numberTooLarge(digits);
            out.writeByte(offset, (byte) (num % 10 + '0'));
        }
    }

    /**
     * Appends given long value with given decimalPlaces to RandomDataOutput out
     *
     * @param width Maximum width. I will be padded with zeros to the left if necessary
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    public static void appendDecimal(@NotNull RandomDataOutput out, long num, @NonNegative long offset, int decimalPlaces, int width)
            throws IORuntimeException, IllegalArgumentException, BufferOverflowException, ArithmeticException, ClosedIllegalStateException, ThreadingIllegalStateException {
        if (decimalPlaces == 0) {
            append(out, offset, num, width);
            return;
        }

        byte[] numberBuffer = BYTE_ARRAY_TL.get();
        int endIndex;
        if (num < 0) {
            if (num == Long.MIN_VALUE) {
                numberBuffer = MIN_VALUE_TEXT;
                endIndex = MIN_VALUE_TEXT.length;
            } else {
                out.writeByte(offset++, (byte) '-');
                num = -num;
                endIndex = appendLong1(numberBuffer, num);
            }
        } else {
            endIndex = appendLong1(numberBuffer, num);
        }
        int digits = numberBuffer.length - endIndex;

        if (decimalPlaces >= digits) {
            int numDigitsRequired = 2 + decimalPlaces;
            if (numDigitsRequired > width)
                throw new IllegalArgumentException("Value do not fit in " + width + " digits");
            out.writeUnsignedByte(offset++, '0');
            out.writeUnsignedByte(offset++, '.');
            while (decimalPlaces-- > digits)
                out.writeUnsignedByte(offset++, '0');
            out.write(offset, numberBuffer, endIndex, digits);
            return;
        } else {
            int numDigitsRequired = digits + 1;
            if (numDigitsRequired > width)
                throw new IllegalArgumentException("Value do not fit in " + width + " digits");
        }

        while (width-- > (digits + 1)) {
            out.writeUnsignedByte(offset++, '0');
        }

        int decimalLength = numberBuffer.length - endIndex - decimalPlaces;
        out.write(offset, numberBuffer, endIndex, decimalLength);
        offset += decimalLength;
        out.writeUnsignedByte(offset++, '.');
        out.write(offset, numberBuffer, endIndex + decimalLength, digits - decimalLength);
    }

    private static void numberTooLarge(int digits)
            throws IllegalArgumentException {
        throw new IllegalArgumentException("Number too large for " + digits + "digits");
    }

    private static void appendLong0(@NotNull StreamingDataOutput out, long num)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        if (num < 0) {
            if (num == Long.MIN_VALUE) {
                out.write(MIN_VALUE_TEXT);
                return;
            }
            out.rawWriteByte((byte) '-');
            num = -num;
        }
        if (num < 10) {
            out.rawWriteByte((byte) ('0' + num));

        } else if (num < 100) {
            out.writeShort((short) (num / 10 + (num % 10 << 8) + '0' * 0x101));

        } else {
            byte[] numberBuffer = BYTE_ARRAY_TL.get();
            // Extract digits into the end of the numberBuffer
            int endIndex = appendLong1(numberBuffer, num);

            // Bulk copy the digits into the front of the buffer
            out.write(numberBuffer, endIndex, numberBuffer.length - endIndex);
        }
    }

    private static int appendLong1(byte[] numberBuffer, long num) {
        numberBuffer[19] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 19;
        numberBuffer[18] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 18;
        numberBuffer[17] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 17;
        numberBuffer[16] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 16;
        numberBuffer[15] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 15;
        numberBuffer[14] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 14;
        numberBuffer[13] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 13;
        numberBuffer[12] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 12;
        numberBuffer[11] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 11;
        numberBuffer[10] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 10;
        numberBuffer[9] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 9;
        numberBuffer[8] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 8;
        numberBuffer[7] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 7;
        numberBuffer[6] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 6;
        numberBuffer[5] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 5;
        numberBuffer[4] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 4;
        numberBuffer[3] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 3;
        numberBuffer[2] = (byte) (num % 10L + '0');
        num /= 10;
        if (num <= 0)
            return 2;
        numberBuffer[1] = (byte) (num % 10L + '0');
        return 1;
    }

    public static void append(@NotNull StreamingDataOutput out, double d)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        long val = Double.doubleToRawLongBits(d);
        int sign = (int) (val >>> 63);
        int exp = (int) ((val >>> 52) & 2047);
        long mantissa = val & ((1L << 52) - 1);
        if (sign != 0) {
            out.rawWriteByte((byte) '-');
        }
        if (exp == 0 && mantissa == 0) {
            out.rawWriteByte((byte) '0');
            out.rawWriteByte((byte) '.');
            out.rawWriteByte((byte) '0');
            return;

        } else if (exp == 2047) {
            if (mantissa == 0) {
                out.write(INFINITY_BYTES);

            } else {
                out.write(NAN_BYTES);
            }
            return;

        } else if (exp > 0) {
            mantissa += 1L << 52;
        }
        final int shift = (1023 + 52) - exp;
        if (shift > 0) {
            // integer and faction
            if (shift < 53) {
                long intValue = mantissa >> shift;
                appendLong0(out, intValue);
                mantissa -= intValue << shift;
                if (mantissa > 0) {
                    out.rawWriteByte((byte) '.');
                    mantissa <<= 1;
                    mantissa++;
                    int precision = shift + 1;
                    long error = 1;

                    long value = intValue;
                    int decimalPlaces = 0;
                    while (mantissa > error) {
                        // times 5*2 = 10
                        mantissa *= 5;
                        error *= 5;
                        precision--;
                        long num = (mantissa >> precision);
                        value = value * 10 + num;
                        out.rawWriteByte((byte) ('0' + num));
                        mantissa -= num << precision;

                        int deci = ++decimalPlaces;
                        final double parsedValue = Maths.asDouble(value, 0, sign != 0, deci);
                        if (parsedValue == d)
                            break;
                    }
                } else {
                    out.rawWriteByte((byte) '.');
                    out.rawWriteByte((byte) '0');
                }
                return;

            } else {
                // faction.
                out.rawWriteByte((byte) '0');
                out.rawWriteByte((byte) '.');
                mantissa <<= 6;
                mantissa += (1 << 5);
                int precision = shift + 6;

                long error = (1 << 5);

                long value = 0;
                int decimalPlaces = 0;
                while (mantissa > error) {
                    while (mantissa > MAX_VALUE_DIVIDE_5) {
                        mantissa >>>= 1;
                        error = (error + 1) >>> 1;
                        precision--;
                    }
                    // times 5*2 = 10
                    mantissa *= 5;
                    error *= 5;
                    precision--;
                    if (precision >= 64) {
                        decimalPlaces++;
                        out.rawWriteByte((byte) '0');
                        continue;
                    }
                    long num = (mantissa >>> precision);
                    value = value * 10 + num;
                    final char c = (char) ('0' + num);
                    assert !(c < '0' || c > '9');
                    out.rawWriteByte((byte) c);
                    mantissa -= num << precision;
                    int deci = ++decimalPlaces;
                    final double parsedValue = Maths.asDouble(value, 0, sign != 0, deci);
                    if (parsedValue == d)
                        break;
                }
                return;
            }
        }
        // large number
        mantissa <<= 10;
        int precision = -10 - shift;
        int digits = 0;
        while ((precision > 53 || mantissa > Long.MAX_VALUE >> precision) && precision > 0) {
            digits++;
            precision--;
            long mod = mantissa % 5;
            mantissa /= 5;
            int modDiv = 1;
            while (mantissa < MAX_VALUE_DIVIDE_5 && precision > 1) {
                precision -= 1;
                mantissa <<= 1;
                modDiv <<= 1;
            }
            mantissa += modDiv * mod / 5;
        }
        long val2 = precision > 0 ? mantissa << precision : mantissa >>> -precision;

        appendLong0(out, val2);
        for (int i = 0; i < digits; i++)
            out.rawWriteByte((byte) '0');
    }

    /**
     * Appends a formatted double value to a {@link ByteStringAppender} with a specified number of decimal places.
     * This method provides a high-performance way to append double values, optimizing for cases with up to 18 decimal places and up to 15 significant digits.
     * For higher precision, it falls back to using {@link BigDecimal}.
     *
     * @param bytesStringAppender the {@link ByteStringAppender} to append the formatted double to.
     * @param d                   the double value to format and append.
     * @param decimalPlaces       the number of decimal places to use in the formatted output. Must be non-negative.
     * @throws BufferOverflowException     if there is not enough space left in the {@link ByteStringAppender}.
     * @throws IllegalArgumentException    if the number of decimal places is negative.
     * @throws ClosedIllegalStateException if the {@link ByteStringAppender} has been closed.
     * @throws ArithmeticException         if an error occurs during arithmetic operations.
     */
    public static void append(@NotNull ByteStringAppender bytesStringAppender, double d, int decimalPlaces)
            throws BufferOverflowException, IllegalArgumentException, ClosedIllegalStateException, ArithmeticException {
        if (decimalPlaces < 0)
            throw new IllegalArgumentException("Number of decimal places cannot be negative");

        // For up to 18 decimal places, use fast path
        if (decimalPlaces > 18) {
            bytesStringAppender.append(d);
            return;
        }
        long factor = Maths.tens(decimalPlaces);
        // convert to double
        double d1 = d;
        // check for negative
        boolean neg = d1 < 0;
        d1 = Math.abs(d1);
        // scale it by the factor
        final double df = d1 * factor;
        if (df < 1e15) { // if the result up to 15 significant digits
            long ldf = (long) df; // truncate as a long
            // estimate the error in truncating
            final double residual = df - ldf + Math.ulp(d1) * (factor * 0.983);
            // should it round up.
            if (residual >= 0.5)
                ldf++;

            // restore the sign
            if (neg)
                ldf = -ldf;
            long round = ldf;

            if (bytesStringAppender.canWriteDirect(20L + decimalPlaces)) {
                long address = bytesStringAppender.addressForWritePosition();
                long address2 = UnsafeText.appendBase10d(address, round, decimalPlaces);
                bytesStringAppender.writeSkip(address2 - address);
            } else {
                bytesStringAppender.appendDecimal(round, decimalPlaces);
            }
            return;
        }
        // Fallback to BigDecimal for high precision cases
        bytesStringAppender.append(BigDecimal.valueOf(d).setScale(decimalPlaces, RoundingMode.HALF_UP));
    }

    @Nullable
    public static String readUtf8(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, IORuntimeException, ClosedIllegalStateException, ArithmeticException {
        throwExceptionIfReleased(in);
        if (in.peekUnsignedByte() == 0x80 && in instanceof RandomDataInput) {
            RandomDataInput rdi = (RandomDataInput) in;
            if (rdi.peekUnsignedByte(in.readPosition() + 1) == 0) {
                in.readSkip(2);
                return null;
            }
        }
        try (ScopedResource stlSb = acquireStringBuilderScoped()) {
            StringBuilder sb = stlSb.get();
            return in.readUtf8(sb) ? SI.intern(sb) : null;
        }
    }

    @Nullable
    public static String readUtf8(@NotNull RandomDataInput in, @NonNegative long offset, @NonNegative int maxUtf8Len)
            throws BufferUnderflowException, IllegalArgumentException,
            ClosedIllegalStateException, IORuntimeException {
        throwExceptionIfReleased(in);
        try (ScopedResource stlSb = acquireStringBuilderScoped()) {
            StringBuilder sb = stlSb.get();
            return in.readUtf8Limited(offset, sb, maxUtf8Len) > 0 ? SI.intern(sb) : null;
        }
    }

    public static ScopedResource acquireStringBuilderScoped() {
        return STRING_BUILDER_SCOPED_RESOURCE_POOL.get();
    }

    /**
     * Acquire a scoped, thread-local bytes instance
     */
    public static ScopedResource> acquireBytesScoped() {
        return BYTES_SCOPED_THREAD_LOCAL.get();
    }

    @SuppressWarnings("unchecked")
    @Nullable
    public static String read8bit(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, IORuntimeException, ArithmeticException, ClosedIllegalStateException {
        throwExceptionIfReleased(in);
        if (in.peekUnsignedByte() == 0x80 && in instanceof RandomDataInput) {
            RandomDataInput rdi = (RandomDataInput) in;
            // checks if the string was null
            if (rdi.peekUnsignedByte(in.readPosition() + 1) == 0) {
                in.readSkip(2);
                return null;
            }
        }
        try (ScopedResource> stlBytes = BytesInternal.acquireBytesScoped()) {
            Bytes bytes = stlBytes.get();
            return in.read8bit(bytes) ? SI.intern(bytes, (int) bytes.readRemaining()) : null;
        }
    }

    @Nullable
    public static String parseUtf8(@NotNull StreamingDataInput bytes, @NotNull StopCharTester tester)
            throws ClosedIllegalStateException, ArithmeticException {
        throwExceptionIfReleased(bytes);
        requireNonNull(tester);
        try (ScopedResource stlSb = acquireStringBuilderScoped()) {
            StringBuilder utfReader = stlSb.get();
            parseUtf8(bytes, utfReader, tester);
            return SI.intern(utfReader);
        }
    }

    public static void parseUtf8(@NotNull StreamingDataInput bytes, @NotNull Appendable builder,
                                 @NotNull StopCharTester tester)
            throws BufferUnderflowException, ClosedIllegalStateException, ArithmeticException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(builder);
        requireNonNull(tester);
        try {
            if (builder instanceof StringBuilder
                    && bytes.isDirectMemory()) {
                @NotNull Bytes vb = (Bytes) bytes;
                @NotNull StringBuilder sb = (StringBuilder) builder;
                sb.setLength(0);
                readUtf8_SB1(vb, sb, tester);
            } else {
                AppendableUtil.setLength(builder, 0);
                readUtf81(bytes, builder, tester);
            }
        } catch (UTFDataFormatException e) {
            @NotNull UTFDataFormatRuntimeException e2 = new UTFDataFormatRuntimeException("Unable to parse invalid UTF-8 code", e);
            throw e2;

        } catch (IOException | IllegalArgumentException e) {
            throw Jvm.rethrow(e);
        }
    }

    private static void readUtf8_SB1(
            @NotNull Bytes bytes, @NotNull StringBuilder appendable, @NotNull StopCharTester tester)
            throws IOException, ClosedIllegalStateException {

        @Nullable final NativeBytesStore nb = (NativeBytesStore) bytes.bytesStore();
        int i = 0;
        final int len = (int) Math.min(bytes.realReadRemaining(), Integer.MAX_VALUE);
        final long address = nb.address + nb.translate(bytes.readPosition());
        @Nullable final Memory memory = nb.memory;

        if (Jvm.isJava9Plus()) {
            final int appendableLength = appendable.capacity();
            for (; i < len && i < appendableLength; i++) {
                int c = memory.readByte(address + i);
                if (c < 0) // we have hit a non-ASCII character.
                    break;
                if (tester.isStopChar(c)) {
                    bytes.readSkip(i + 1L);
                    StringUtils.setCount(appendable, i);
                    return;
                }
                appendable.append((char) c);
            }
        } else {
            final char[] chars = StringUtils.extractChars(appendable);
            for (; i < len && i < chars.length; i++) {
                int c = memory.readByte(address + i);
                if (c < 0) // we have hit a non-ASCII character.
                    break;
                if (tester.isStopChar(c)) {
                    bytes.readSkip(i + 1L);
                    StringUtils.setCount(appendable, i);
                    return;
                }
                chars[i] = (char) c;
            }
        }
        StringUtils.setCount(appendable, i);
        bytes.readSkip(i);
        if (i < len) {
            readUtf8_SB2(bytes, appendable, tester);
        }
    }

    private static void readUtf8_SB2(@NotNull StreamingDataInput bytes, @NotNull StringBuilder appendable, @NotNull StopCharTester tester)
            throws UTFDataFormatException, ClosedIllegalStateException {
        while (true) {
            int c = bytes.readUnsignedByte();
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    if (tester.isStopChar(c))
                        return;
                    appendable.append((char) c);
                    break;

                case 12:
                case 13: {
                    /* 110x xxxx 10xx xxxx */
                    int char2 = bytes.readUnsignedByte();
                    if ((char2 & 0xC0) != 0x80)
                        throw newUTFDataFormatException(-1, "");
                    int c2 = (char) (((c & 0x1F) << 6) |
                            (char2 & 0x3F));
                    if (tester.isStopChar(c2))
                        return;
                    appendable.append((char) c2);
                    break;
                }

                case 14: {
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    int char2 = bytes.readUnsignedByte();
                    int char3 = bytes.readUnsignedByte();

                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw newUTFDataFormatException(-1, "");
                    int c3 = (char) (((c & 0x0F) << 12) |
                            ((char2 & 0x3F) << 6) |
                            (char3 & 0x3F));
                    if (tester.isStopChar(c3))
                        return;
                    appendable.append((char) c3);
                    break;
                }

                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw newUTFDataFormatException(-1, "");
            }
        }
    }

    private static UTFDataFormatException newUTFDataFormatException(@NonNegative final long offset, final String suffix) {
        return new UTFDataFormatException(MALFORMED_INPUT_AROUND_BYTE + offset + " " + suffix);
    }

    private static UTFDataFormatRuntimeException newUTFDataFormatRuntimeException(@NonNegative final long offset, final String suffix) {
        return new UTFDataFormatRuntimeException(MALFORMED_INPUT_AROUND_BYTE + offset + " " + suffix);
    }

    private static void readUtf81(@NotNull StreamingDataInput bytes, @NotNull Appendable appendable, @NotNull StopCharTester tester)
            throws IOException, BufferUnderflowException, ArithmeticException, ClosedIllegalStateException {
        int len = (int) Math.min(bytes.readRemaining(), Integer.MAX_VALUE);
        while (len-- > 0) {
            int c = bytes.rawReadByte() & 0xff;
            if (c >= 128) {
                bytes.readSkip(-1);
                break;
            }
            if (tester.isStopChar(c))
                return;
            appendable.append((char) c);
        }
        if (len <= 0)
            return;

        readUtf82(bytes, appendable, tester);
    }

    private static void readUtf82(@NotNull StreamingDataInput bytes, @NotNull Appendable appendable, @NotNull StopCharTester tester)
            throws IOException, ClosedIllegalStateException {
        while (true) {
            int c = bytes.readUnsignedByte();
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    if (tester.isStopChar(c))
                        return;
                    appendable.append((char) c);
                    break;

                case 12:
                case 13: {
                    /* 110x xxxx 10xx xxxx */
                    int char2 = bytes.readUnsignedByte();
                    if ((char2 & 0xC0) != 0x80)
                        throw new UTFDataFormatException(
                                "malformed input around byte");
                    int c2 = (char) (((c & 0x1F) << 6) |
                            (char2 & 0x3F));
                    if (tester.isStopChar(c2))
                        return;
                    appendable.append((char) c2);
                    break;
                }

                case 14: {
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    int char2 = bytes.readUnsignedByte();
                    int char3 = bytes.readUnsignedByte();

                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw new UTFDataFormatException(
                                MALFORMED_INPUT_AROUND_BYTE);
                    int c3 = (char) (((c & 0x0F) << 12) |
                            ((char2 & 0x3F) << 6) |
                            (char3 & 0x3F));
                    if (tester.isStopChar(c3))
                        return;
                    appendable.append((char) c3);
                    break;
                }

                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw new UTFDataFormatException(
                            MALFORMED_INPUT_AROUND_BYTE);
            }
        }
    }

    public static void parseUtf8(@NotNull StreamingDataInput bytes, @NotNull Appendable builder, @NotNull StopCharsTester tester)
            throws BufferUnderflowException, IORuntimeException, ClosedIllegalStateException {
        try {
            AppendableUtil.setLength(builder, 0);
            AppendableUtil.readUtf8AndAppend(bytes, builder, tester);
        } catch (IOException | IllegalArgumentException e) {
            throw Jvm.rethrow(e);
        }
    }

    public static void parse8bit(@NotNull StreamingDataInput bytes, @NotNull StringBuilder builder, @NotNull StopCharsTester tester)
            throws ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        requireNonNull(builder);
        requireNonNull(tester);
        builder.setLength(0);
        AppendableUtil.read8bitAndAppend(bytes, builder, tester);
    }

    public static void parse8bit(@NotNull StreamingDataInput bytes, @NotNull Bytes builder, @NotNull StopCharsTester tester)
            throws BufferUnderflowException, BufferOverflowException, ClosedIllegalStateException, ArithmeticException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(builder);
        requireNonNull(tester);
        builder.readPosition(0);
        read8bitAndAppend(bytes, builder, tester);
    }

    public static void parse8bit(@NotNull StreamingDataInput bytes, @NotNull StringBuilder builder, @NotNull StopCharTester tester)
            throws ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        requireNonNull(tester);
        builder.setLength(0);
        read8bitAndAppend(bytes, builder, tester);
    }

    public static void parse8bit(@NotNull StreamingDataInput bytes, @NotNull Bytes builder, @NotNull StopCharTester tester)
            throws BufferUnderflowException, BufferOverflowException, ClosedIllegalStateException, ArithmeticException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(builder);
        requireNonNull(tester);
        builder.clear();

        read8bitAndAppend(bytes, builder, tester);
    }

    private static void read8bitAndAppend(@NotNull StreamingDataInput bytes, @NotNull StringBuilder appendable, @NotNull StopCharTester tester)
            throws ClosedIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(appendable);
        requireNonNull(tester);
        while (true) {
            int c = bytes.readUnsignedByte();
            if (tester.isStopChar(c))
                return;
            appendable.append((char) c);
            if (bytes.readRemaining() == 0)
                return;
        }
    }

    private static void read8bitAndAppend(@NotNull StreamingDataInput bytes, @NotNull Bytes bytes2, @NotNull StopCharTester tester)
            throws BufferOverflowException, ClosedIllegalStateException, ArithmeticException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(bytes2);
        requireNonNull(tester);
        while (true) {
            int c = bytes.readUnsignedByte();
            if (tester.isStopChar(c))
                return;
            bytes2.writeUnsignedByte(c);
            if (bytes.readRemaining() == 0)
                return;
        }
    }

    private static void read8bitAndAppend(@NotNull StreamingDataInput bytes, @NotNull Bytes bytes2, @NotNull StopCharsTester tester)
            throws BufferUnderflowException, BufferOverflowException, ClosedIllegalStateException, ArithmeticException, ThreadingIllegalStateException {
        throwExceptionIfReleased(bytes);
        throwExceptionIfReleased(bytes2);
        requireNonNull(tester);
        int ch = bytes.readUnsignedByte();
        do {
            int next = bytes.readUnsignedByte();
            if (tester.isStopChar(ch, next)) {
                bytes.readSkip(-1);
                return;
            }
            bytes2.writeUnsignedByte(ch);
            ch = next;
        } while (bytes.readRemaining() > 0);

        if (tester.isStopChar(ch, -1)) {
            bytes.readSkip(-1);
            return;
        }
        bytes2.writeUnsignedByte(ch);
    }

    public static long parseFlexibleLong(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, ClosedIllegalStateException, IORuntimeException {
        long absValue = 0; // Math.abs(absValue) == absValue
        int sign = 1;
        int decimalPlaces = Integer.MIN_VALUE;
        boolean digits = false;
        int ch;
        do {
            ch = in.rawReadByte() & 0xFF;
        } while (ch == ' ' && in.readRemaining() > 0);

        try {
            switch (ch) {
                case 'N':
                    if (compareRest(in, "aN"))
                        throw new IORuntimeException("Expected flexible long, but got: NaN");
                    in.readSkip(-1);

                    throw new IORuntimeException("Expected flexible long, but got: N");
                case 'I':
                    //noinspection SpellCheckingInspection
                    if (compareRest(in, "nfinity"))
                        throw new IORuntimeException("Expected flexible long, but got: Infinity");
                    in.readSkip(-1);
                    throw new IORuntimeException("Expected flexible long, but got: I");
                case '-':
                    if (compareRest(in, INFINITY))
                        throw new IORuntimeException("Expected flexible long, but got: -Infinity");
                    sign = -1;
                    ch = in.rawReadByte();
                    break;
                case '+':
                    if (compareRest(in, INFINITY))
                        throw new IORuntimeException("Expected flexible long, but got: +Infinity");
                    ch = in.rawReadByte();
                    break;
                default:
                    // Do nothing
            }

            int tens = 0;
            IORuntimeException parsingError = null;
            while (true) {
                if (ch >= '0' && ch <= '9') {
                    // -absValue is always negative!
                    if (-absValue < -MAX_VALUE_DIVIDE_10) {
                        if (ch == '0')
                            tens++;
                        else if (parsingError == null) {
                            parsingError = new IORuntimeException(CAN_T_PARSE_FLEXIBLE_LONG_WITHOUT_PRECISION_LOSS +
                                    (sign * absValue) + " <- " + ((char) ch));
                        }

                    } else if (absValue == MAX_VALUE_DIVIDE_10) {
                        if (ch <= '7' || (sign < 0 && ch == '8'))
                            absValue = absValue * 10 + (ch - '0');
                        else if (parsingError == null) {
                            parsingError = new IORuntimeException(CAN_T_PARSE_FLEXIBLE_LONG_WITHOUT_PRECISION_LOSS +
                                    (sign * absValue) + " <- " + ((char) ch));
                        }
                    } else {
                        absValue = absValue * 10 + (ch - '0');
                    }
                    decimalPlaces++;
                    digits = true;

                } else if (ch == '.') {
                    decimalPlaces = 0;

                } else if (ch == 'E' || ch == 'e') {
                    tens += (int) parseLong(in);
                    break;

                } else {
                    break;

                }
                if (in.readRemaining() == 0)
                    break;
                ch = in.rawReadByte();
            }

            if (parsingError != null)
                throw parsingError;

            if (!digits)
                return 0L;

            if (decimalPlaces < 0)
                decimalPlaces = 0;

            tens -= decimalPlaces;

            if (tens <= 0) {
                absValue *= sign;

                for (int i = 0; i < -tens; i++) {
                    int truncatingDigit = (int) Math.abs(absValue % 10);

                    if (truncatingDigit != 0) {
                        throw new IORuntimeException(CAN_T_PARSE_FLEXIBLE_LONG_WITHOUT_PRECISION_LOSS +
                                "division of " + absValue + " by 10");
                    }

                    absValue /= 10;
                }

                return absValue;
            } else {
                for (int i = 0; i < tens; i++) {
                    if (-absValue < -MAX_VALUE_DIVIDE_10) {
                        throw new IORuntimeException("Can't parse flexible long as it goes beyond the range: " +
                                "multiplication of " + absValue + " by 10");
                    } else
                        absValue *= 10;
                }

                return sign * absValue;
            }
        } finally {
            final ByteStringParser bsp = (ByteStringParser) in;
            bsp.lastDecimalPlaces(decimalPlaces);
            bsp.lastNumberHadDigits(digits);
        }
    }

    public static double parseDouble(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, ClosedIllegalStateException {
        long value = 0;
        int exp = 0;
        boolean negative = false;
        int decimalPlaces = Integer.MIN_VALUE;
        boolean digits = false;
        int ch = ' ';
        while (in.readRemaining() > 0) {
            ch = in.peekUnsignedByte() & 0xFF;
            if (ch != ' ')
                break;
            else
                in.readSkip(1);
        }

        try {
            switch (ch) {
                case 'N':
                    if (compareRest(in, NAN))
                        return Double.NaN;

                    return Double.NaN;
                case 'I':
                    if (compareRest(in, INFINITY))
                        return Double.POSITIVE_INFINITY;

                    return Double.NaN;
                case '-':
                    negative = true;
                    in.readSkip(1);
                    if (compareRest(in, INFINITY))
                        return Double.NEGATIVE_INFINITY;
                    break;
                case '+':
                    in.readSkip(1);
                    if (compareRest(in, INFINITY))
                        return Double.POSITIVE_INFINITY;
                    break;
                default:
                    // do nothing
            }
            int tens = 0;
            while (in.readRemaining() > 0) {
                ch = in.readUnsignedByte() & 0xFF;
                if (ch >= '0' && ch <= '9') {
                    while (value >= MAX_VALUE_DIVIDE_10) {
                        value >>>= 1;
                        exp++;
                    }
                    value = value * 10 + (ch - '0');
                    decimalPlaces++;
                    digits = true;

                } else if (ch == '.') {
                    decimalPlaces = 0;

                } else if (ch == 'E' || ch == 'e') {
                    tens = (int) parseLong(in);
                    break;

                } else {
                    break;

                }
            }
            if (!digits)
                return -0.0;
            if (decimalPlaces < 0)
                decimalPlaces = 0;

            decimalPlaces = decimalPlaces - tens;

            return Maths.asDouble(value, exp, negative, decimalPlaces);
        } finally {
            final ByteStringParser bsp = (ByteStringParser) in;
            bsp.lastDecimalPlaces(decimalPlaces);
            bsp.lastNumberHadDigits(digits);
        }
    }

    static boolean compareRest(@NotNull StreamingDataInput in, @NotNull String s)
            throws BufferUnderflowException, ClosedIllegalStateException {
        if (s.length() > in.readRemaining())
            return false;
        long position = in.readPosition();
        for (int i = 0; i < s.length(); i++) {
            if (in.readUnsignedByte() != s.charAt(i)) {
                in.readPosition(position);
                return false;
            }
        }
        int ch = in.readUnsignedByte();
        if (Character.isLetterOrDigit(ch)) {
            in.readPosition(position);
            return false;
        }
        while (Character.isWhitespace(ch) && ch >= ' ')
            ch = in.readUnsignedByte();
        return true;
    }

    public static long parseLong(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, ClosedIllegalStateException {
        long num = 0;
        boolean negative = false;
        int b = in.peekUnsignedByte();
        while (b > 0 && b <= ' ') {
            in.readSkip(1);
            b = in.peekUnsignedByte();
        }
        boolean digits = false;
        if (b == '0') {
            in.readSkip(1);
            b = in.peekUnsignedByte();
            digits = true;
            if (b == 'x' || b == 'X') {
                in.readSkip(1);
                return parseLongHexaDecimal(in);
            }
        }
        while (in.readRemaining() > 0) {
            b = in.rawReadByte();
            if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE) {
                num = num * 10 + b - '0';
                digits = true;
            } else if (b == '-') {
                negative = true;
            } else if (b == ']' || b == '}') {
                in.readSkip(-1);
                break;
            } else if (b == '.') {
                consumeDecimals(in);
                break;
            } else if (b == '_' || b == '+') {
                // ignore
            } else {
                break;
            }
        }
        ((ByteStringParser) in).lastNumberHadDigits(digits);
        return negative ? -num : num;
    }

    private static long parseLongHexaDecimal(@NotNull StreamingDataInput in)
            throws ClosedIllegalStateException, BufferUnderflowException {
        long num = 0;
        while (in.readRemaining() > 0) {
            int b = in.readUnsignedByte();
            if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE) {
                num = (num << 4) + b - '0';
            } else if ((b - ('A' + Integer.MIN_VALUE)) < 6 + Integer.MIN_VALUE) {
                num = (num << 4) + b - ('A' - 10);
            } else if ((b - ('a' + Integer.MIN_VALUE)) < 6 + Integer.MIN_VALUE) {
                num = (num << 4) + b - ('a' - 10);
            } else if (b == ']' || b == '}') {
                in.readSkip(-1);
                break;
            } else if (b == '.') {
                consumeDecimals(in);
                break;
            } else if (b == '_') {
                // ignore
            } else {
                break;
            }
        }
        return num;
    }

    static void consumeDecimals(@NotNull StreamingDataInput in)
            throws ClosedIllegalStateException {
        int b;
        while (in.readRemaining() > 0) {
            b = in.readUnsignedByte();
            if (b < '0' || b > '9') {
                break;
            }
        }
    }

    public static long parseLongDecimal(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, ClosedIllegalStateException {
        long num = 0;
        boolean negative = false;
        int decimalPlaces = Integer.MIN_VALUE;
        boolean digits = false;
        boolean first = true;
        while (in.readRemaining() > 0) {
            int b = in.readUnsignedByte();
            if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE) {
                num = num * 10 + b - '0';
                decimalPlaces++;
                digits = true;
                first = false;
            } else if (b == '.') {
                decimalPlaces = 0;
                first = false;
            } else if (b == '-') {
                negative = true;
                first = false;
            } else if (b == ']' || b == '}') {
                in.readSkip(-1);
                break;
            } else if (b == '_' || b == '+') {
                // ignore
                first = false;
            } else if (!first || b > ' ') {
                break;
            } else if (b == 0) {
                break;
            }
        }
        final ByteStringParser bsp = (ByteStringParser) in;
        bsp.lastDecimalPlaces(decimalPlaces);
        bsp.lastNumberHadDigits(digits);
        return negative ? -num : num;
    }

    public static long parseHexLong(@NotNull StreamingDataInput in)
            throws BufferUnderflowException, ClosedIllegalStateException {
        long num = 0;
        while (in.readRemaining() > 0) {
            int b = in.readUnsignedByte();
            if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE) {
                num = num * 16 + b - '0';
            } else if ((b - ('A' + Integer.MIN_VALUE)) <= 6 + Integer.MIN_VALUE) {
                num = num * 16 + b - 'A' + 10;
            } else if ((b - ('a' + Integer.MIN_VALUE)) <= 6 + Integer.MIN_VALUE) {
                num = num * 16 + b - 'a' + 10;
            } else if (b == ']' || b == '}') {
                in.readSkip(-1);
                break;
            } else if (b == '_') {
                // ignore
            } else {
                break;
            }
        }
        return num;
    }

    public static long parseLong(@NotNull RandomDataInput in, @NonNegative long offset)
            throws BufferUnderflowException, ClosedIllegalStateException {
        long num = 0;
        boolean negative = false;
        while (true) {
            int b = in.peekUnsignedByte(offset++);
            if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE)
                num = num * 10 + b - '0';
            else if (b == '-')
                negative = true;
            else if (b != '_' && b != '+')
                break;
        }
        return negative ? -num : num;
    }

    public static boolean skipTo(@NotNull ByteStringParser parser, @NotNull StopCharTester tester)
            throws ClosedIllegalStateException {
        while (parser.readRemaining() > 0) {
            int ch = parser.readUnsignedByte();
            if (tester.isStopChar(ch))
                return true;
        }
        return false;
    }

    public static float addAndGetFloat(@NotNull BytesStore in, @NonNegative long offset, float adding)
            throws BufferUnderflowException, ClosedIllegalStateException {
        for (; ; ) {
            int value = in.readVolatileInt(offset);
            float value1 = Float.intBitsToFloat(value) + adding;
            int value2 = Float.floatToRawIntBits(value1);
            if (in.compareAndSwapInt(offset, value, value2))
                return value1;
        }
    }

    public static double addAndGetDouble(@NotNull BytesStore in, @NonNegative long offset, double adding)
            throws BufferUnderflowException, ClosedIllegalStateException {
        for (; ; ) {
            long value = in.readVolatileLong(offset);
            double value1 = Double.longBitsToDouble(value) + adding;
            long value2 = Double.doubleToRawLongBits(value1);
            if (in.compareAndSwapLong(offset, value, value2))
                return value1;
        }
    }

    public static int addAndGetInt(@NotNull BytesStore in, @NonNegative long offset, int adding)
            throws BufferUnderflowException, ClosedIllegalStateException {
        for (; ; ) {
            int value = in.readVolatileInt(offset);
            int value2 = value + adding;
            if (in.compareAndSwapInt(offset, value, value2))
                return value2;
        }
    }

    public static long addAndGetLong(@NotNull BytesStore in, @NonNegative long offset, long adding)
            throws BufferUnderflowException, ClosedIllegalStateException {
        for (; ; ) {
            long value = in.readVolatileLong(offset);
            long value2 = value + adding;
            if (in.compareAndSwapLong(offset, value, value2))
                return value2;
        }
    }

    /**
     * Converts the content of the provided Bytes buffer to a hexadecimal string representation
     * along with comments describing the meaning of the bytes.
     * 

* The method reads the data from the offset with maxLength of the given bytes. Each line of the * output string contains hexadecimal representation of 16 bytes, followed by comments describing * the meaning of those bytes. *

* For example, a buffer containing bytes representing the ASCII string "VMH" would produce an * output like this: *

     * c3 76 6d 68                                     # vmh:
     * b6 03 56 4d 48                                  # VMH
     * 
* * @param bytes The buffer whose content is to be converted to a hexadecimal string. * Must not be null. * @param offset The starting offset within the buffer to begin the hexadecimal conversion. * @param maxLength The number of bytes to convert from the buffer. * @return A hexadecimal representation of the buffer content with comments describing the bytes. * Each line of the string contains the hexadecimal representation of 16 bytes. * @throws BufferUnderflowException If there is not enough data in the buffer. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws IllegalArgumentException If the provided offset or maxLength are negative. */ public static String toHexString(@NotNull final Bytes bytes, @NonNegative long offset, @NonNegative long maxLength) throws BufferUnderflowException { try { throwExceptionIfReleased(bytes); } catch (ClosedIllegalStateException e) { return e.toString(); } if (maxLength == 0) return ""; int width = 16; int[] lastLine = new int[width]; @NotNull String sep = ""; long position = bytes.readPosition(); long limit = bytes.readLimit(); try { bytes.readPositionRemaining(offset, maxLength); @NotNull final StringBuilder builder = new StringBuilder(); long start = offset / width * width; long end = (offset + maxLength + width - 1) / width * width; for (long i = start; i < end; i += width) { // check for duplicate rows if (i + width < end) { boolean same = true; for (int j = 0; j < width && i + j < offset + maxLength; j++) { int ch = bytes.readUnsignedByte(i + j); same &= (ch == lastLine[j]); lastLine[j] = ch; } if (i > start && same) { sep = "........\n"; continue; } } builder.append(sep); sep = ""; String str = Long.toHexString(i); for (int j = str.length(); j < 8; j++) builder.append('0'); builder.append(str); for (int j = 0; j < width; j++) { if (j == width / 2) builder.append(' '); if (i + j < offset || i + j >= offset + maxLength) { builder.append(" "); } else { builder.append(' '); int ch = bytes.readUnsignedByte(i + j); builder.append(HEXADECIMAL[ch >> 4]); builder.append(HEXADECIMAL[ch & 15]); } } builder.append(' '); for (int j = 0; j < width; j++) { if (j == width / 2) builder.append(' '); if (i + j < offset || i + j >= offset + maxLength) { builder.append(' '); } else { int ch = bytes.readUnsignedByte(i + j); if (ch < ' ' || ch > 126) ch = '\u00B7'; builder.append((char) ch); } } builder.append("\n"); } return builder.toString(); } catch (ClosedIllegalStateException e) { return e.toString(); } finally { bytes.readLimit(limit); bytes.readPosition(position); } } public static void appendTimeMillis(@NotNull ByteStringAppender b, long timeInMS) throws BufferOverflowException, ClosedIllegalStateException, IllegalArgumentException, ThreadingIllegalStateException { int hours = (int) (timeInMS / (60 * 60 * 1000)); if (hours > 99) { b.append(hours); // can have over 24 hours. } else { b.rawWriteByte((byte) (hours / 10 + '0')); b.rawWriteByte((byte) (hours % 10 + '0')); } b.rawWriteByte((byte) ':'); int minutes = (int) ((timeInMS / (60 * 1000)) % 60); b.rawWriteByte((byte) (minutes / 10 + '0')); b.rawWriteByte((byte) (minutes % 10 + '0')); b.rawWriteByte((byte) ':'); int seconds = (int) ((timeInMS / 1000) % 60); b.rawWriteByte((byte) (seconds / 10 + '0')); b.rawWriteByte((byte) (seconds % 10 + '0')); b.rawWriteByte((byte) '.'); int millis = (int) (timeInMS % 1000); b.rawWriteByte((byte) (millis / 100 + '0')); b.rawWriteByte((byte) (millis / 10 % 10 + '0')); b.rawWriteByte((byte) (millis % 10 + '0')); } public static boolean equalBytesAny(@NotNull BytesStore b1, @NotNull BytesStore b2, @NonNegative long readRemaining) throws BufferUnderflowException, ClosedIllegalStateException { if (Math.min(b1.readRemaining(), b2.readRemaining()) < readRemaining) return false; long i = 0; long rp1 = b1.readPosition(); long rp2 = b2.readPosition(); for (; i < readRemaining - 7 && canReadBytesAt(b1, rp1 + i, 8) && canReadBytesAt(b2, rp2 + i, 8); i += 8) { long l1 = b1.readLong(rp1 + i); long l2 = b2.readLong(rp2 + i); if (l1 != l2) return false; } for (; i < readRemaining && canReadBytesAt(b1, rp1 + i, 1) && canReadBytesAt(b2, rp2 + i, 1); i++) { byte i1 = b1.readByte(rp1 + i); byte i2 = b2.readByte(rp2 + i); if (i1 != i2) return false; } return true; } public static void appendDateMillis(@NotNull ByteStringAppender b, long timeInMS) throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException { DateCache dateCache = dateCacheTL.get(); if (dateCache == null) { dateCache = new DateCache(); dateCacheTL.set(dateCache); } final long date = timeInMS / 86400000; if (dateCache.lastDay != date) { dateCache.lastDateStr = dateCache.dateFormat.format(new Date(timeInMS)).getBytes(ISO_8859_1); dateCache.lastDay = date; } else { assert dateCache.lastDateStr != null; } b.write(dateCache.lastDateStr); } @SuppressWarnings("unchecked") @NotNull public static , S extends StreamingDataInput> E readEnum(@NotNull StreamingDataInput input, @NotNull Class eClass) throws BufferUnderflowException, IORuntimeException, BufferOverflowException, ClosedIllegalStateException, ArithmeticException { try (ScopedResource> stlBytes = BytesInternal.acquireBytesScoped()) { Bytes bytes = stlBytes.get(); input.read8bit(bytes); return (E) EnumInterner.ENUM_INTERNER.get(eClass).intern(bytes); } } public static void writeFully(@NotNull final RandomDataInput bytes, @NonNegative final long offset, @NonNegative final long length, @NotNull final StreamingDataOutput sdo) throws BufferUnderflowException, BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException { long i = 0; if (bytes instanceof HasUncheckedRandomDataInput) { // Do boundary checking outside the inner loop if (length + offset > bytes.capacity()) { throw new DecoratedBufferOverflowException("Cannot read " + length + " bytes as offset is " + offset + " and capacity is " + bytes.capacity()); } final UncheckedRandomDataInput uBytes = ((HasUncheckedRandomDataInput) bytes).acquireUncheckedInput(); for (; i < length - 7; i += 8) sdo.rawWriteLong(uBytes.readLong(offset + i)); if (i < length - 3) { sdo.rawWriteInt(uBytes.readInt(offset + i)); i += 4; } for (; i < length; i++) sdo.rawWriteByte(uBytes.readByte(offset + i)); } else { for (; i < length - 7; i += 8) sdo.rawWriteLong(bytes.readLong(offset + i)); if (i < length - 3) { sdo.rawWriteInt(bytes.readInt(offset + i)); i += 4; } for (; i < length; i++) sdo.rawWriteByte(bytes.readByte(offset + i)); } } public static void copyMemory(long from, long to, int length) { UnsafeMemory.copyMemory(from, to, length); } @NotNull public static byte[] toByteArray(@NotNull RandomDataInput in) throws ClosedIllegalStateException { final int len = (int) Math.min(Bytes.MAX_HEAP_CAPACITY, in.readRemaining()); throwExceptionIfReleased(in); @NotNull byte[] bytes = new byte[len]; in.read(in.readPosition(), bytes, 0, bytes.length); return bytes; } public static void copy(@NotNull final RandomDataInput input, @NotNull final OutputStream output) throws IOException, ClosedIllegalStateException { requireNonNull(input); requireNonNull(output); throwExceptionIfReleased(input); final byte[] bytes = new byte[512]; final long start = input.readPosition(); long i = 0; for (int len; (len = (int) input.read(start + i, bytes, 0, bytes.length)) > 0; i += len) { output.write(bytes, 0, len); } } public static void copy(@NotNull InputStream input, @NotNull StreamingDataOutput output) throws IOException, BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException { @NotNull byte[] bytes = new byte[512]; for (int len; (len = input.read(bytes)) > 0; ) { output.write(bytes, 0, len); } } public static Boolean parseBoolean(@NotNull ByteStringParser parser, @NotNull StopCharTester tester) throws BufferUnderflowException, ClosedIllegalStateException, ArithmeticException { try (ScopedResource> stlBytes = BytesInternal.acquireBytesScoped()) { Bytes sb = stlBytes.get(); parseUtf8(parser, sb, tester); if (sb.length() == 0) return null; switch (sb.charAt(0)) { case 't': case 'T': return sb.length() == 1 || StringUtils.equalsCaseIgnore(sb, "true") ? true : null; case 'y': case 'Y': return sb.length() == 1 || StringUtils.equalsCaseIgnore(sb, "yes") ? true : null; case '0': return sb.length() == 1 ? false : null; case '1': return sb.length() == 1 ? true : null; case 'f': case 'F': return sb.length() == 1 || StringUtils.equalsCaseIgnore(sb, "false") ? false : null; case 'n': case 'N': return sb.length() == 1 || StringUtils.equalsCaseIgnore(sb, "no") ? false : null; default: return null; } } } @NotNull public static BytesStore subBytes(RandomDataInput from, @NonNegative long start, @NonNegative long length) throws BufferUnderflowException, ClosedIllegalStateException { @NotNull BytesStore ret; if (from.isDirectMemory()) { ret = BytesStore.nativeStore(Math.max(0, length)); } else { ret = BytesStore.wrap(new byte[Math.toIntExact(length)]); } ret.write(0L, from, start, length); return ret; } public static long findByte(@NotNull RandomDataInput bytes, byte stopByte) throws ClosedIllegalStateException { long start = bytes.readPosition(); long remaining = bytes.readRemaining(); for (long i = 0; i < remaining; i++) { if (bytes.readByte(start + i) == stopByte) return i; } return -1; } @NotNull public static Bytes fromHexString(@NotNull String s) { Bytes in = Bytes.from(s); try { Bytes out = Bytes.allocateElasticOnHeap(); OUTER: while (in.readRemaining() > 0) { in.parseHexLong(); for (int i = 0; i < 16; i++) { if (in.peekUnsignedByte() == ' ') { in.readSkip(1); if (in.peekUnsignedByte() == ' ') break OUTER; } long value = in.parseHexLong(); out.rawWriteByte((byte) value); } if (in.readByte(in.readPosition() - 1) <= ' ') in.readSkip(-1); in.skipTo(StopCharTesters.CONTROL_STOP); } return out; } finally { in.releaseLast(); } } public static void readHistogram(@NotNull StreamingDataInput in, @NotNull Histogram histogram) throws ClosedIllegalStateException, BufferUnderflowException, ArithmeticException { requireNonNull(histogram); throwExceptionIfReleased(in); int powersOf2 = Maths.toUInt31(in.readStopBit()); int fractionBits = Maths.toUInt31(in.readStopBit()); long overRange = in.readStopBit(); long totalCount = in.readStopBit(); long floor = in.readStopBit(); histogram.init(powersOf2, fractionBits, overRange, totalCount, floor); int length = Maths.toUInt31(in.readStopBit()); int[] ints = histogram.sampleCount(); for (int i = 0; i < length; i++) ints[i] = Maths.toUInt31(in.readStopBit()); } public static void writeHistogram(@NotNull StreamingDataOutput out, @NotNull Histogram histogram) throws BufferOverflowException, ClosedIllegalStateException { requireNonNull(histogram); throwExceptionIfReleased(out); out.writeStopBit(histogram.powersOf2()); out.writeStopBit(histogram.fractionBits()); out.writeStopBit(histogram.overRange()); out.writeStopBit(histogram.totalCount()); out.writeStopBit(histogram.floor()); int[] ints = histogram.sampleCount(); out.writeStopBit(ints.length); for (int i : ints) out.writeStopBit(i); } public static ByteBuffer asByteBuffer(@NotNull BytesStore bytesStore) throws BufferUnderflowException, ClosedIllegalStateException { return asByteBuffer(BYTE_BUFFER_TL, bytesStore); } public static ByteBuffer asByteBuffer2(@NotNull BytesStore bytesStore) throws BufferUnderflowException, ClosedIllegalStateException { return asByteBuffer(BYTE_BUFFER2_TL, bytesStore); } private static ByteBuffer asByteBuffer(@NotNull ThreadLocal byteBufferTL, @NotNull BytesStore bytesStore) throws BufferUnderflowException, ClosedIllegalStateException { ByteBuffer byteBuffer = byteBufferTL.get(); assignBytesStoreToByteBuffer(bytesStore, byteBuffer); return byteBuffer; } public static void assignBytesStoreToByteBuffer(@NotNull BytesStore bytesStore, @NotNull ByteBuffer byteBuffer) throws BufferUnderflowException, ClosedIllegalStateException { long address = bytesStore.addressForRead(bytesStore.readPosition()); long capacity = bytesStore.realReadRemaining(); ByteBuffers.setAddressCapacity(byteBuffer, address, capacity); byteBuffer.clear(); } private static boolean canReadBytesAt( final BytesStore bs, final long offset, final int length) { return bs.readLimit() - offset >= length; } public static String parse8bit(ByteStringParser bsp, StopCharTester stopCharTester) throws ClosedIllegalStateException { try (ScopedResource stlSb = acquireStringBuilderScoped()) { StringBuilder sb = stlSb.get(); BytesInternal.parse8bit(bsp, sb, stopCharTester); return BytesInternal.SI.intern(sb); } } public static void copy8bit(BytesStore bs, long addressForWrite, @NonNegative long length) throws ClosedIllegalStateException { throwExceptionIfReleased(bs); int length0 = Math.toIntExact(length); int i = 0; for (; i < length0 - 7; i += 8) MEMORY.writeLong(addressForWrite + i, bs.readLong(i)); for (; i < length0; i++) MEMORY.writeByte(addressForWrite + i, bs.readByte(i)); } public static int digitsForExponent(int exponent) { return 21 + Math.abs(exponent); } static class DateCache { final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); private long lastDay = Long.MIN_VALUE; private byte[] lastDateStr = null; DateCache() { dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); } } public static , U> BytesStore failIfBytesOnBytes(BytesStore bytesStore) { // MappedBytes don't have a backing BytesStore so we have to allow them to be used this way if (bytesStore instanceof Bytes && !(bytesStore instanceof MappedBytes)) { throw new IllegalArgumentException("A BytesStore is required as backing but a Bytes has been provided: " + bytesStore.getClass().getSimpleName()); } return bytesStore; } @SuppressWarnings("unchecked") public static T uncheckedCast(Object o) { return (T) o; } }