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

dorkbox.bytes.OptimizeUtilsByteArray.kt Maven / Gradle / Ivy

There is a newer version: 2.1
Show newest version
/*
 * Copyright 2023 dorkbox, llc
 *
 * 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.
 */
@file:Suppress("UNUSED_CHANGED_VALUE", "NAME_SHADOWING")

package dorkbox.bytes

@Suppress("unused")
object OptimizeUtilsByteArray {
    /**
     * Gets the version number.
     */
    const val version = BytesInfo.version

    /**
     * Returns the number of bytes that would be written with [.writeInt].
     *
     * @param optimizePositive
     * true if you want to optimize the number of bytes needed to write the length value
     */
    fun intLength(value: Int, optimizePositive: Boolean): Int {
        return OptimizeUtilsByteBuf.intLength(value, optimizePositive)
    }

    /**
     * FROM KRYO
     *
     *
     * look at buffer, and see if we can read the length of the int off of it. (from the reader index)
     *
     * @param position where in the buffer to start reading
     * @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
     */
    fun canReadInt(buffer: ByteArray, position: Int = 0): Boolean {
        var position = position
        val length = buffer.size
        if (length >= 5) {
            return true
        }
        if (position + 1 > length) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == length) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == length) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == length) {
            return false
        }
        return if (buffer[position++].toInt() and 0x80 == 0) {
            true
        } else position != length
    }


    /**
     * FROM KRYO
     *
     *
     * Reads an int from the buffer that was optimized.
     *
     * @param position where in the buffer to start reading
     */
    fun readInt(buffer: ByteArray, position: Int): Int {
        return readInt(buffer, false, position)
    }

    /**
     * FROM KRYO
     *
     *
     * Reads an int from the buffer that was optimized.
     *
     * @param position where in the buffer to start reading
     * @param optimizePositive
     * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (5
     * bytes).  This ultimately means that it will use fewer bytes for positive numbers.
     */
    fun readInt(buffer: ByteArray, optimizePositive: Boolean = false, position: Int = 0): Int {
        var position = position
        var b = buffer[position++].toInt()
        var result = b and 0x7F
        if (b and 0x80 != 0) {
            b = buffer[position++].toInt()
            result = result or (b and 0x7F shl 7)
            if (b and 0x80 != 0) {
                b = buffer[position++].toInt()
                result = result or (b and 0x7F shl 14)
                if (b and 0x80 != 0) {
                    b = buffer[position++].toInt()
                    result = result or (b and 0x7F shl 21)
                    if (b and 0x80 != 0) {
                        b = buffer[position++].toInt()
                        result = result or (b and 0x7F shl 28)
                    }
                }
            }
        }
        return if (optimizePositive) result else result ushr 1 xor -(result and 1)
    }

    /**
     * FROM KRYO
     *
     *
     * Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
     *
     * @param position where in the buffer to start writing
     * @param optimizePositive
     * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (5
     * bytes).  This ultimately means that it will use fewer bytes for positive numbers.
     *
     * @return the number of bytes written.
     */
    fun writeInt(buffer: ByteArray, value: Int, optimizePositive: Boolean = false, position: Int = 0): Int {
        var value = value
        var position = position
        if (!optimizePositive) {
            value = value shl 1 xor (value shr 31)
        }
        if (value ushr 7 == 0) {
            buffer[position++] = value.toByte()
            return 1
        }
        if (value ushr 14 == 0) {
            buffer[position++] = (value and 0x7F or 0x80).toByte()
            buffer[position++] = (value ushr 7).toByte()
            return 2
        }
        if (value ushr 21 == 0) {
            buffer[position++] = (value and 0x7F or 0x80).toByte()
            buffer[position++] = (value ushr 7 or 0x80).toByte()
            buffer[position++] = (value ushr 14).toByte()
            return 3
        }
        if (value ushr 28 == 0) {
            buffer[position++] = (value and 0x7F or 0x80).toByte()
            buffer[position++] = (value ushr 7 or 0x80).toByte()
            buffer[position++] = (value ushr 14 or 0x80).toByte()
            buffer[position++] = (value ushr 21).toByte()
            return 4
        }
        buffer[position++] = (value and 0x7F or 0x80).toByte()
        buffer[position++] = (value ushr 7 or 0x80).toByte()
        buffer[position++] = (value ushr 14 or 0x80).toByte()
        buffer[position++] = (value ushr 21 or 0x80).toByte()
        buffer[position++] = (value ushr 28).toByte()
        return 5
    }

    /**
     * Returns 1-9 bytes that would be written with [.writeLong].
     *
     * @param optimizePositive
     * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9
     * bytes). This ultimately means that it will use fewer bytes for positive numbers.
     */
    fun longLength(value: Long, optimizePositive: Boolean): Int {
        return OptimizeUtilsByteBuf.longLength(value, optimizePositive)
    }
    // long
    /**
     * FROM KRYO
     *
     *
     * Reads a 1-9 byte long.
     *
     * @param position where in the buffer to start reading
     * @param optimizePositive
     * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9
     * bytes). This ultimately means that it will use fewer bytes for positive numbers.
     */
    fun readLong(buffer: ByteArray, optimizePositive: Boolean = false, position: Int = 0): Long {
        var position = position
        var b = buffer[position++].toInt()
        var result = (b and 0x7F).toLong()
        if (b and 0x80 != 0) {
            b = buffer[position++].toInt()
            result = result or (b and 0x7F shl 7).toLong()
            if (b and 0x80 != 0) {
                b = buffer[position++].toInt()
                result = result or (b and 0x7F shl 14).toLong()
                if (b and 0x80 != 0) {
                    b = buffer[position++].toInt()
                    result = result or (b and 0x7F shl 21).toLong()
                    if (b and 0x80 != 0) {
                        b = buffer[position++].toInt()
                        result = result or ((b and 0x7F).toLong() shl 28)
                        if (b and 0x80 != 0) {
                            b = buffer[position++].toInt()
                            result = result or ((b and 0x7F).toLong() shl 35)
                            if (b and 0x80 != 0) {
                                b = buffer[position++].toInt()
                                result = result or ((b and 0x7F).toLong() shl 42)
                                if (b and 0x80 != 0) {
                                    b = buffer[position++].toInt()
                                    result = result or ((b and 0x7F).toLong() shl 49)
                                    if (b and 0x80 != 0) {
                                        b = buffer[position++].toInt()
                                        result = result or (b.toLong() shl 56)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (!optimizePositive) {
            result = result ushr 1 xor -(result and 1L)
        }
        return result
    }

    /**
     * FROM KRYO
     *
     *
     * Writes a 1-9 byte long.
     *
     * @param position where in the buffer to start writing
     * @param optimizePositive
     * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9
     * bytes).
     *
     * @return the number of bytes written.
     */
    fun writeLong(buffer: ByteArray, value: Long, optimizePositive: Boolean = false, position: Int = 0): Int {
        var value = value
        var position = position
        if (!optimizePositive) {
            value = value shl 1 xor (value shr 63)
        }
        if (value ushr 7 == 0L) {
            buffer[position++] = value.toByte()
            return 1
        }
        if (value ushr 14 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7).toByte()
            return 2
        }
        if (value ushr 21 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7 or 0x80L).toByte()
            buffer[position++] = (value ushr 14).toByte()
            return 3
        }
        if (value ushr 28 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7 or 0x80L).toByte()
            buffer[position++] = (value ushr 14 or 0x80L).toByte()
            buffer[position++] = (value ushr 21).toByte()
            return 4
        }
        if (value ushr 35 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7 or 0x80L).toByte()
            buffer[position++] = (value ushr 14 or 0x80L).toByte()
            buffer[position++] = (value ushr 21 or 0x80L).toByte()
            buffer[position++] = (value ushr 28).toByte()
            return 5
        }
        if (value ushr 42 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7 or 0x80L).toByte()
            buffer[position++] = (value ushr 14 or 0x80L).toByte()
            buffer[position++] = (value ushr 21 or 0x80L).toByte()
            buffer[position++] = (value ushr 28 or 0x80L).toByte()
            buffer[position++] = (value ushr 35).toByte()
            return 6
        }
        if (value ushr 49 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7 or 0x80L).toByte()
            buffer[position++] = (value ushr 14 or 0x80L).toByte()
            buffer[position++] = (value ushr 21 or 0x80L).toByte()
            buffer[position++] = (value ushr 28 or 0x80L).toByte()
            buffer[position++] = (value ushr 35 or 0x80L).toByte()
            buffer[position++] = (value ushr 42).toByte()
            return 7
        }
        if (value ushr 56 == 0L) {
            buffer[position++] = (value and 0x7FL or 0x80L).toByte()
            buffer[position++] = (value ushr 7 or 0x80L).toByte()
            buffer[position++] = (value ushr 14 or 0x80L).toByte()
            buffer[position++] = (value ushr 21 or 0x80L).toByte()
            buffer[position++] = (value ushr 28 or 0x80L).toByte()
            buffer[position++] = (value ushr 35 or 0x80L).toByte()
            buffer[position++] = (value ushr 42 or 0x80L).toByte()
            buffer[position++] = (value ushr 49).toByte()
            return 8
        }
        buffer[position++] = (value and 0x7FL or 0x80L).toByte()
        buffer[position++] = (value ushr 7 or 0x80L).toByte()
        buffer[position++] = (value ushr 14 or 0x80L).toByte()
        buffer[position++] = (value ushr 21 or 0x80L).toByte()
        buffer[position++] = (value ushr 28 or 0x80L).toByte()
        buffer[position++] = (value ushr 35 or 0x80L).toByte()
        buffer[position++] = (value ushr 42 or 0x80L).toByte()
        buffer[position++] = (value ushr 49 or 0x80L).toByte()
        buffer[position++] = (value ushr 56).toByte()
        return 9
    }

    /**
     * look at buffer, and see if we can read the length of the long off of it (from the reader index).
     *
     * @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
     */
    fun canReadLong(buffer: ByteArray): Boolean {
        val position = 0
        return canReadLong(buffer, position)
    }

    /**
     * FROM KRYO
     *
     *
     * look at buffer, and see if we can read the length of the long off of it (from the reader index).
     *
     * @param position where in the buffer to start reading
     * @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
     */
    private fun canReadLong(buffer: ByteArray, position: Int): Boolean {
        var position = position
        val limit = buffer.size
        if (limit >= 9) {
            return true
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        if (buffer[position++].toInt() and 0x80 == 0) {
            return true
        }
        if (position == limit) {
            return false
        }
        return if (buffer[position++].toInt() and 0x80 == 0) {
            true
        } else position != limit
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy