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

commonMain.androidx.compose.ui.graphics.vector.FastFloatParser.kt Maven / Gradle / Ivy

/*
 * Copyright 2023 The Android Open Source Project
 *
 * 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("NOTHING_TO_INLINE")
@file:OptIn(ExperimentalUnsignedTypes::class, ExperimentalUnsignedTypes::class)

package androidx.compose.ui.graphics.vector

import androidx.compose.ui.util.doubleFromBits
import androidx.compose.ui.util.floatFromBits

/**
 * The code below is adapted from:
 *     https://github.com/fastfloat/fast_float
 *     https://github.com/lemire/fast_double_parser/
 * The original C++ implementations are licensed under Apache 2.0
 */

private const val FloatMinExponent = -10
private const val FloatMaxExponent = 10
private const val FloatSmallestExponent = -325
private const val FloatMaxExponentNumber = 1024

// internal to bypass synthetic accessor
@Suppress("MemberVisibilityCanBePrivate")
internal val PowersOfTen = floatArrayOf(
    1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, 1e6f, 1e7f, 1e8f, 1e9f, 1e10f
)

internal inline val Long.index get() = (this ushr 32).toInt()
internal inline val Long.floatValue get() = floatFromBits((this and 0xFFFFFFFFL).toInt())

/**
 * Parses the next float in the char sequence [s], starting at offset [start], until at most
 * the end offset [end]. The result is returned as [Long] with the most significant 32 bits
 * encoding the index in the string [s] where parsing stop, and with the least significant
 * 32 bits encoding the parsed float value. To access these values easily, use [Long.index]
 * and [Long.floatValue]. When parsing is unsuccessful, [Long.floatValue] returns NaN.
 */
@OptIn(kotlin.ExperimentalStdlibApi::class)
internal fun nextFloat(s: String, start: Int, end: Int): Long {
    // NOTE: It would be nice to encode invalid parsing with a NaN marker
    // (for instance 0x7FD55555), but doing so prevents us from defining
    // the value as a const val which causes static field accesses
    if (start == end) return pack(start, Float.NaN)

    var index = start
    var c = s[index]

    // Check for leading negative sign
    val isNegative = c == '-'
    if (isNegative) {
        index++
        if (index == end) return pack(index, Float.NaN)

        // Safe access, we just checked the bounds
        c = s[index]
        if (!c.isDigit && c != '.') return pack(index, Float.NaN)
    }

    // TODO: Should we use an unsigned long here?
    var significand = 0L
    val significandStartIndex = index

    // Parse the integer part
    val dataLength = s.length
    while (index != end && c.isDigit) {
        significand = 10L * significand + (c.code - '0'.code).toLong()
        index++
        c = if (index < dataLength) s[index] else '\u0000'
    }

    val significandEndIndex = index
    var digitCount = index - significandStartIndex

    var exponent = 0
    var exponentStartIndex = index
    var exponentEndIndex = index

    // Parse the fraction
    if (index != end && c == '.') {
        index++
        exponentStartIndex = index

        while (end - index >= 4) {
            val digits = parseFourDigits(s, index)
            if (digits < 0) break
            significand = 10_000L * significand + digits.toLong()
            index += 4
        }

        c = if (index < dataLength) s[index] else '\u0000'
        while (index != end && c.isDigit) {
            significand = 10L * significand + (c.code - '0'.code).toLong()
            index++
            c = if (index < dataLength) s[index] else '\u0000'
        }

        exponent = exponentStartIndex - index
        exponentEndIndex = index
        digitCount -= exponent
    }

    if (digitCount == 0) return pack(index, Float.NaN)

    // Parse the exponent part of the float, if present
    var exponentNumber = 0
    if ((c.code or 0x20) == 'e'.code) {
        index++
        c = if (index < dataLength) s[index] else '\u0000'

        val isExponentNegative = c == '-'
        if (isExponentNegative || c == '+') {
            index++
        }

        c = s[index]
        while (index != end && c.isDigit) {
            if (exponentNumber < FloatMaxExponentNumber) {
                exponentNumber = 10 * exponentNumber + (c.code - '0'.code)
            }
            index++
            c = if (index < dataLength) s[index] else '\u0000'
        }

        if (isExponentNegative) exponentNumber = -exponentNumber
        exponent += exponentNumber
    }

    // TODO: check for f/F suffix?

    var tooManyDigits = false

    // If we have too many digits we need to retry differently and avoid overflows
    if (digitCount > 19) {
        var retryIndex = significandStartIndex
        c = s[retryIndex]

        // First check for the case where the number is 0.0000000xxxx (could be all zeroes)
        while (index != end && (c == '0' || c == '.')) {
            if (c == '0') digitCount--
            retryIndex++
            c = if (retryIndex < dataLength) s[retryIndex] else '\u0000'
        }

        if (digitCount > 19) {
            tooManyDigits = true

            significand = 0
            retryIndex = significandStartIndex
            c = s[retryIndex]

            while (
                retryIndex != significandEndIndex &&
                significand.toULong() < 1000000000000000000UL
            ) {
                significand = 10L * significand + (c.code - '0'.code).toLong()
                retryIndex++
                c = if (retryIndex < dataLength) s[retryIndex] else '\u0000'
            }

            if (significand.toULong() >= 1000000000000000000UL) {
                exponent = significandEndIndex - retryIndex + exponentNumber
            } else {
                retryIndex = exponentStartIndex
                c = s[retryIndex]

                while (
                    retryIndex != exponentEndIndex &&
                    significand.toULong() < 1000000000000000000UL
                ) {
                    significand = 10L * significand + (c.code - '0'.code).toLong()
                    retryIndex++
                    c = if (retryIndex < dataLength) s[retryIndex] else '\u0000'
                }
                exponent = exponentStartIndex - retryIndex + exponentNumber
            }
        }
    }

    // Fast path
    if (exponent in FloatMinExponent..FloatMaxExponent &&
        !tooManyDigits &&
        significand.toULong() <= 1UL shl 24
    ) {
        var f = significand.toFloat()
        if (exponent < 0) {
            f /= PowersOfTen[-exponent]
        } else {
            f *= PowersOfTen[exponent]
        }

        return pack(index, if (isNegative) -f else f)
    }

    // Now we need to take the slow path, please refer to the original C++ code for a
    // complete description of the algorithm

    if (significand == 0L) {
        return pack(index, if (isNegative) -0.0f else 0.0f)
    }

    if (exponent !in -126..127) {
        return pack(index, s.substring(start, index).toFloat())
    }

    val significandFactor = Mantissa64[exponent - FloatSmallestExponent].toLong()
    var lz = significand.countLeadingZeroBits()
    significand = significand shl lz

    val upper = fullMultiplicationHighBits(significand, significandFactor)
    val upperBit = (upper ushr 63).toInt()
    var mantissa = upper ushr (upperBit + 9)
    lz += 1 xor upperBit

    if (upper and 0x1ff == 0x1ffL || upper and 0x1ff == 0L && mantissa and 3L == 1L) {
        return pack(index, s.substring(start, index).toFloat())
    }

    mantissa += 1
    mantissa = mantissa ushr 1

    if (mantissa >= 1L shl 53) {
        mantissa = 1L shl 52
        lz--
    }

    mantissa = mantissa and (1L shl 52).inv()

    val adjustedExponent = (((152170L + 65536L) * exponent) shr 16) + 1024 + 63
    val realExponent = adjustedExponent - lz
    if (realExponent < 1 || realExponent > 2046) {
        return pack(index, s.substring(start, index).toFloat())
    }

    mantissa = mantissa or (realExponent shl 52)
    mantissa = mantissa or if (isNegative) 1L shl 63 else 0L

    return pack(index, doubleFromBits(mantissa).toFloat())
}

// internal to bypass synthetic accessor
@Suppress("MemberVisibilityCanBePrivate")
internal val Mantissa64 = ulongArrayOf(
    0xa5ced43b7e3e9188UL, 0xcf42894a5dce35eaUL,
    0x818995ce7aa0e1b2UL, 0xa1ebfb4219491a1fUL,
    0xca66fa129f9b60a6UL, 0xfd00b897478238d0UL,
    0x9e20735e8cb16382UL, 0xc5a890362fddbc62UL,
    0xf712b443bbd52b7bUL, 0x9a6bb0aa55653b2dUL,
    0xc1069cd4eabe89f8UL, 0xf148440a256e2c76UL,
    0x96cd2a865764dbcaUL, 0xbc807527ed3e12bcUL,
    0xeba09271e88d976bUL, 0x93445b8731587ea3UL,
    0xb8157268fdae9e4cUL, 0xe61acf033d1a45dfUL,
    0x8fd0c16206306babUL, 0xb3c4f1ba87bc8696UL,
    0xe0b62e2929aba83cUL, 0x8c71dcd9ba0b4925UL,
    0xaf8e5410288e1b6fUL, 0xdb71e91432b1a24aUL,
    0x892731ac9faf056eUL, 0xab70fe17c79ac6caUL,
    0xd64d3d9db981787dUL, 0x85f0468293f0eb4eUL,
    0xa76c582338ed2621UL, 0xd1476e2c07286faaUL,
    0x82cca4db847945caUL, 0xa37fce126597973cUL,
    0xcc5fc196fefd7d0cUL, 0xff77b1fcbebcdc4fUL,
    0x9faacf3df73609b1UL, 0xc795830d75038c1dUL,
    0xf97ae3d0d2446f25UL, 0x9becce62836ac577UL,
    0xc2e801fb244576d5UL, 0xf3a20279ed56d48aUL,
    0x9845418c345644d6UL, 0xbe5691ef416bd60cUL,
    0xedec366b11c6cb8fUL, 0x94b3a202eb1c3f39UL,
    0xb9e08a83a5e34f07UL, 0xe858ad248f5c22c9UL,
    0x91376c36d99995beUL, 0xb58547448ffffb2dUL,
    0xe2e69915b3fff9f9UL, 0x8dd01fad907ffc3bUL,
    0xb1442798f49ffb4aUL, 0xdd95317f31c7fa1dUL,
    0x8a7d3eef7f1cfc52UL, 0xad1c8eab5ee43b66UL,
    0xd863b256369d4a40UL, 0x873e4f75e2224e68UL,
    0xa90de3535aaae202UL, 0xd3515c2831559a83UL,
    0x8412d9991ed58091UL, 0xa5178fff668ae0b6UL,
    0xce5d73ff402d98e3UL, 0x80fa687f881c7f8eUL,
    0xa139029f6a239f72UL, 0xc987434744ac874eUL,
    0xfbe9141915d7a922UL, 0x9d71ac8fada6c9b5UL,
    0xc4ce17b399107c22UL, 0xf6019da07f549b2bUL,
    0x99c102844f94e0fbUL, 0xc0314325637a1939UL,
    0xf03d93eebc589f88UL, 0x96267c7535b763b5UL,
    0xbbb01b9283253ca2UL, 0xea9c227723ee8bcbUL,
    0x92a1958a7675175fUL, 0xb749faed14125d36UL,
    0xe51c79a85916f484UL, 0x8f31cc0937ae58d2UL,
    0xb2fe3f0b8599ef07UL, 0xdfbdcece67006ac9UL,
    0x8bd6a141006042bdUL, 0xaecc49914078536dUL,
    0xda7f5bf590966848UL, 0x888f99797a5e012dUL,
    0xaab37fd7d8f58178UL, 0xd5605fcdcf32e1d6UL,
    0x855c3be0a17fcd26UL, 0xa6b34ad8c9dfc06fUL,
    0xd0601d8efc57b08bUL, 0x823c12795db6ce57UL,
    0xa2cb1717b52481edUL, 0xcb7ddcdda26da268UL,
    0xfe5d54150b090b02UL, 0x9efa548d26e5a6e1UL,
    0xc6b8e9b0709f109aUL, 0xf867241c8cc6d4c0UL,
    0x9b407691d7fc44f8UL, 0xc21094364dfb5636UL,
    0xf294b943e17a2bc4UL, 0x979cf3ca6cec5b5aUL,
    0xbd8430bd08277231UL, 0xece53cec4a314ebdUL,
    0x940f4613ae5ed136UL, 0xb913179899f68584UL,
    0xe757dd7ec07426e5UL, 0x9096ea6f3848984fUL,
    0xb4bca50b065abe63UL, 0xe1ebce4dc7f16dfbUL,
    0x8d3360f09cf6e4bdUL, 0xb080392cc4349decUL,
    0xdca04777f541c567UL, 0x89e42caaf9491b60UL,
    0xac5d37d5b79b6239UL, 0xd77485cb25823ac7UL,
    0x86a8d39ef77164bcUL, 0xa8530886b54dbdebUL,
    0xd267caa862a12d66UL, 0x8380dea93da4bc60UL,
    0xa46116538d0deb78UL, 0xcd795be870516656UL,
    0x806bd9714632dff6UL, 0xa086cfcd97bf97f3UL,
    0xc8a883c0fdaf7df0UL, 0xfad2a4b13d1b5d6cUL,
    0x9cc3a6eec6311a63UL, 0xc3f490aa77bd60fcUL,
    0xf4f1b4d515acb93bUL, 0x991711052d8bf3c5UL,
    0xbf5cd54678eef0b6UL, 0xef340a98172aace4UL,
    0x9580869f0e7aac0eUL, 0xbae0a846d2195712UL,
    0xe998d258869facd7UL, 0x91ff83775423cc06UL,
    0xb67f6455292cbf08UL, 0xe41f3d6a7377eecaUL,
    0x8e938662882af53eUL, 0xb23867fb2a35b28dUL,
    0xdec681f9f4c31f31UL, 0x8b3c113c38f9f37eUL,
    0xae0b158b4738705eUL, 0xd98ddaee19068c76UL,
    0x87f8a8d4cfa417c9UL, 0xa9f6d30a038d1dbcUL,
    0xd47487cc8470652bUL, 0x84c8d4dfd2c63f3bUL,
    0xa5fb0a17c777cf09UL, 0xcf79cc9db955c2ccUL,
    0x81ac1fe293d599bfUL, 0xa21727db38cb002fUL,
    0xca9cf1d206fdc03bUL, 0xfd442e4688bd304aUL,
    0x9e4a9cec15763e2eUL, 0xc5dd44271ad3cdbaUL,
    0xf7549530e188c128UL, 0x9a94dd3e8cf578b9UL,
    0xc13a148e3032d6e7UL, 0xf18899b1bc3f8ca1UL,
    0x96f5600f15a7b7e5UL, 0xbcb2b812db11a5deUL,
    0xebdf661791d60f56UL, 0x936b9fcebb25c995UL,
    0xb84687c269ef3bfbUL, 0xe65829b3046b0afaUL,
    0x8ff71a0fe2c2e6dcUL, 0xb3f4e093db73a093UL,
    0xe0f218b8d25088b8UL, 0x8c974f7383725573UL,
    0xafbd2350644eeacfUL, 0xdbac6c247d62a583UL,
    0x894bc396ce5da772UL, 0xab9eb47c81f5114fUL,
    0xd686619ba27255a2UL, 0x8613fd0145877585UL,
    0xa798fc4196e952e7UL, 0xd17f3b51fca3a7a0UL,
    0x82ef85133de648c4UL, 0xa3ab66580d5fdaf5UL,
    0xcc963fee10b7d1b3UL, 0xffbbcfe994e5c61fUL,
    0x9fd561f1fd0f9bd3UL, 0xc7caba6e7c5382c8UL,
    0xf9bd690a1b68637bUL, 0x9c1661a651213e2dUL,
    0xc31bfa0fe5698db8UL, 0xf3e2f893dec3f126UL,
    0x986ddb5c6b3a76b7UL, 0xbe89523386091465UL,
    0xee2ba6c0678b597fUL, 0x94db483840b717efUL,
    0xba121a4650e4ddebUL, 0xe896a0d7e51e1566UL,
    0x915e2486ef32cd60UL, 0xb5b5ada8aaff80b8UL,
    0xe3231912d5bf60e6UL, 0x8df5efabc5979c8fUL,
    0xb1736b96b6fd83b3UL, 0xddd0467c64bce4a0UL,
    0x8aa22c0dbef60ee4UL, 0xad4ab7112eb3929dUL,
    0xd89d64d57a607744UL, 0x87625f056c7c4a8bUL,
    0xa93af6c6c79b5d2dUL, 0xd389b47879823479UL,
    0x843610cb4bf160cbUL, 0xa54394fe1eedb8feUL,
    0xce947a3da6a9273eUL, 0x811ccc668829b887UL,
    0xa163ff802a3426a8UL, 0xc9bcff6034c13052UL,
    0xfc2c3f3841f17c67UL, 0x9d9ba7832936edc0UL,
    0xc5029163f384a931UL, 0xf64335bcf065d37dUL,
    0x99ea0196163fa42eUL, 0xc06481fb9bcf8d39UL,
    0xf07da27a82c37088UL, 0x964e858c91ba2655UL,
    0xbbe226efb628afeaUL, 0xeadab0aba3b2dbe5UL,
    0x92c8ae6b464fc96fUL, 0xb77ada0617e3bbcbUL,
    0xe55990879ddcaabdUL, 0x8f57fa54c2a9eab6UL,
    0xb32df8e9f3546564UL, 0xdff9772470297ebdUL,
    0x8bfbea76c619ef36UL, 0xaefae51477a06b03UL,
    0xdab99e59958885c4UL, 0x88b402f7fd75539bUL,
    0xaae103b5fcd2a881UL, 0xd59944a37c0752a2UL,
    0x857fcae62d8493a5UL, 0xa6dfbd9fb8e5b88eUL,
    0xd097ad07a71f26b2UL, 0x825ecc24c873782fUL,
    0xa2f67f2dfa90563bUL, 0xcbb41ef979346bcaUL,
    0xfea126b7d78186bcUL, 0x9f24b832e6b0f436UL,
    0xc6ede63fa05d3143UL, 0xf8a95fcf88747d94UL,
    0x9b69dbe1b548ce7cUL, 0xc24452da229b021bUL,
    0xf2d56790ab41c2a2UL, 0x97c560ba6b0919a5UL,
    0xbdb6b8e905cb600fUL, 0xed246723473e3813UL,
    0x9436c0760c86e30bUL, 0xb94470938fa89bceUL,
    0xe7958cb87392c2c2UL, 0x90bd77f3483bb9b9UL,
    0xb4ecd5f01a4aa828UL, 0xe2280b6c20dd5232UL,
    0x8d590723948a535fUL, 0xb0af48ec79ace837UL,
    0xdcdb1b2798182244UL, 0x8a08f0f8bf0f156bUL,
    0xac8b2d36eed2dac5UL, 0xd7adf884aa879177UL,
    0x86ccbb52ea94baeaUL, 0xa87fea27a539e9a5UL,
    0xd29fe4b18e88640eUL, 0x83a3eeeef9153e89UL,
    0xa48ceaaab75a8e2bUL, 0xcdb02555653131b6UL,
    0x808e17555f3ebf11UL, 0xa0b19d2ab70e6ed6UL,
    0xc8de047564d20a8bUL, 0xfb158592be068d2eUL,
    0x9ced737bb6c4183dUL, 0xc428d05aa4751e4cUL,
    0xf53304714d9265dfUL, 0x993fe2c6d07b7fabUL,
    0xbf8fdb78849a5f96UL, 0xef73d256a5c0f77cUL,
    0x95a8637627989aadUL, 0xbb127c53b17ec159UL,
    0xe9d71b689dde71afUL, 0x9226712162ab070dUL,
    0xb6b00d69bb55c8d1UL, 0xe45c10c42a2b3b05UL,
    0x8eb98a7a9a5b04e3UL, 0xb267ed1940f1c61cUL,
    0xdf01e85f912e37a3UL, 0x8b61313bbabce2c6UL,
    0xae397d8aa96c1b77UL, 0xd9c7dced53c72255UL,
    0x881cea14545c7575UL, 0xaa242499697392d2UL,
    0xd4ad2dbfc3d07787UL, 0x84ec3c97da624ab4UL,
    0xa6274bbdd0fadd61UL, 0xcfb11ead453994baUL,
    0x81ceb32c4b43fcf4UL, 0xa2425ff75e14fc31UL,
    0xcad2f7f5359a3b3eUL, 0xfd87b5f28300ca0dUL,
    0x9e74d1b791e07e48UL, 0xc612062576589ddaUL,
    0xf79687aed3eec551UL, 0x9abe14cd44753b52UL,
    0xc16d9a0095928a27UL, 0xf1c90080baf72cb1UL,
    0x971da05074da7beeUL, 0xbce5086492111aeaUL,
    0xec1e4a7db69561a5UL, 0x9392ee8e921d5d07UL,
    0xb877aa3236a4b449UL, 0xe69594bec44de15bUL,
    0x901d7cf73ab0acd9UL, 0xb424dc35095cd80fUL,
    0xe12e13424bb40e13UL, 0x8cbccc096f5088cbUL,
    0xafebff0bcb24aafeUL, 0xdbe6fecebdedd5beUL,
    0x89705f4136b4a597UL, 0xabcc77118461cefcUL,
    0xd6bf94d5e57a42bcUL, 0x8637bd05af6c69b5UL,
    0xa7c5ac471b478423UL, 0xd1b71758e219652bUL,
    0x83126e978d4fdf3bUL, 0xa3d70a3d70a3d70aUL,
    0xccccccccccccccccUL, 0x8000000000000000UL,
    0xa000000000000000UL, 0xc800000000000000UL,
    0xfa00000000000000UL, 0x9c40000000000000UL,
    0xc350000000000000UL, 0xf424000000000000UL,
    0x9896800000000000UL, 0xbebc200000000000UL,
    0xee6b280000000000UL, 0x9502f90000000000UL,
    0xba43b74000000000UL, 0xe8d4a51000000000UL,
    0x9184e72a00000000UL, 0xb5e620f480000000UL,
    0xe35fa931a0000000UL, 0x8e1bc9bf04000000UL,
    0xb1a2bc2ec5000000UL, 0xde0b6b3a76400000UL,
    0x8ac7230489e80000UL, 0xad78ebc5ac620000UL,
    0xd8d726b7177a8000UL, 0x878678326eac9000UL,
    0xa968163f0a57b400UL, 0xd3c21bcecceda100UL,
    0x84595161401484a0UL, 0xa56fa5b99019a5c8UL,
    0xcecb8f27f4200f3aUL, 0x813f3978f8940984UL,
    0xa18f07d736b90be5UL, 0xc9f2c9cd04674edeUL,
    0xfc6f7c4045812296UL, 0x9dc5ada82b70b59dUL,
    0xc5371912364ce305UL, 0xf684df56c3e01bc6UL,
    0x9a130b963a6c115cUL, 0xc097ce7bc90715b3UL,
    0xf0bdc21abb48db20UL, 0x96769950b50d88f4UL,
    0xbc143fa4e250eb31UL, 0xeb194f8e1ae525fdUL,
    0x92efd1b8d0cf37beUL, 0xb7abc627050305adUL,
    0xe596b7b0c643c719UL, 0x8f7e32ce7bea5c6fUL,
    0xb35dbf821ae4f38bUL, 0xe0352f62a19e306eUL,
    0x8c213d9da502de45UL, 0xaf298d050e4395d6UL,
    0xdaf3f04651d47b4cUL, 0x88d8762bf324cd0fUL,
    0xab0e93b6efee0053UL, 0xd5d238a4abe98068UL,
    0x85a36366eb71f041UL, 0xa70c3c40a64e6c51UL,
    0xd0cf4b50cfe20765UL, 0x82818f1281ed449fUL,
    0xa321f2d7226895c7UL, 0xcbea6f8ceb02bb39UL,
    0xfee50b7025c36a08UL, 0x9f4f2726179a2245UL,
    0xc722f0ef9d80aad6UL, 0xf8ebad2b84e0d58bUL,
    0x9b934c3b330c8577UL, 0xc2781f49ffcfa6d5UL,
    0xf316271c7fc3908aUL, 0x97edd871cfda3a56UL,
    0xbde94e8e43d0c8ecUL, 0xed63a231d4c4fb27UL,
    0x945e455f24fb1cf8UL, 0xb975d6b6ee39e436UL,
    0xe7d34c64a9c85d44UL, 0x90e40fbeea1d3a4aUL,
    0xb51d13aea4a488ddUL, 0xe264589a4dcdab14UL,
    0x8d7eb76070a08aecUL, 0xb0de65388cc8ada8UL,
    0xdd15fe86affad912UL, 0x8a2dbf142dfcc7abUL,
    0xacb92ed9397bf996UL, 0xd7e77a8f87daf7fbUL,
    0x86f0ac99b4e8dafdUL, 0xa8acd7c0222311bcUL,
    0xd2d80db02aabd62bUL, 0x83c7088e1aab65dbUL,
    0xa4b8cab1a1563f52UL, 0xcde6fd5e09abcf26UL,
    0x80b05e5ac60b6178UL, 0xa0dc75f1778e39d6UL,
    0xc913936dd571c84cUL, 0xfb5878494ace3a5fUL,
    0x9d174b2dcec0e47bUL, 0xc45d1df942711d9aUL,
    0xf5746577930d6500UL, 0x9968bf6abbe85f20UL,
    0xbfc2ef456ae276e8UL, 0xefb3ab16c59b14a2UL,
    0x95d04aee3b80ece5UL, 0xbb445da9ca61281fUL,
    0xea1575143cf97226UL, 0x924d692ca61be758UL,
    0xb6e0c377cfa2e12eUL, 0xe498f455c38b997aUL,
    0x8edf98b59a373fecUL, 0xb2977ee300c50fe7UL,
    0xdf3d5e9bc0f653e1UL, 0x8b865b215899f46cUL,
    0xae67f1e9aec07187UL, 0xda01ee641a708de9UL,
    0x884134fe908658b2UL, 0xaa51823e34a7eedeUL,
    0xd4e5e2cdc1d1ea96UL, 0x850fadc09923329eUL,
    0xa6539930bf6bff45UL, 0xcfe87f7cef46ff16UL,
    0x81f14fae158c5f6eUL, 0xa26da3999aef7749UL,
    0xcb090c8001ab551cUL, 0xfdcb4fa002162a63UL,
    0x9e9f11c4014dda7eUL, 0xc646d63501a1511dUL,
    0xf7d88bc24209a565UL, 0x9ae757596946075fUL,
    0xc1a12d2fc3978937UL, 0xf209787bb47d6b84UL,
    0x9745eb4d50ce6332UL, 0xbd176620a501fbffUL,
    0xec5d3fa8ce427affUL, 0x93ba47c980e98cdfUL,
    0xb8a8d9bbe123f017UL, 0xe6d3102ad96cec1dUL,
    0x9043ea1ac7e41392UL, 0xb454e4a179dd1877UL,
    0xe16a1dc9d8545e94UL, 0x8ce2529e2734bb1dUL,
    0xb01ae745b101e9e4UL, 0xdc21a1171d42645dUL,
    0x899504ae72497ebaUL, 0xabfa45da0edbde69UL,
    0xd6f8d7509292d603UL, 0x865b86925b9bc5c2UL,
    0xa7f26836f282b732UL, 0xd1ef0244af2364ffUL,
    0x8335616aed761f1fUL, 0xa402b9c5a8d3a6e7UL,
    0xcd036837130890a1UL, 0x802221226be55a64UL,
    0xa02aa96b06deb0fdUL, 0xc83553c5c8965d3dUL,
    0xfa42a8b73abbf48cUL, 0x9c69a97284b578d7UL,
    0xc38413cf25e2d70dUL, 0xf46518c2ef5b8cd1UL,
    0x98bf2f79d5993802UL, 0xbeeefb584aff8603UL,
    0xeeaaba2e5dbf6784UL, 0x952ab45cfa97a0b2UL,
    0xba756174393d88dfUL, 0xe912b9d1478ceb17UL,
    0x91abb422ccb812eeUL, 0xb616a12b7fe617aaUL,
    0xe39c49765fdf9d94UL, 0x8e41ade9fbebc27dUL,
    0xb1d219647ae6b31cUL, 0xde469fbd99a05fe3UL,
    0x8aec23d680043beeUL, 0xada72ccc20054ae9UL,
    0xd910f7ff28069da4UL, 0x87aa9aff79042286UL,
    0xa99541bf57452b28UL, 0xd3fa922f2d1675f2UL,
    0x847c9b5d7c2e09b7UL, 0xa59bc234db398c25UL,
    0xcf02b2c21207ef2eUL, 0x8161afb94b44f57dUL,
    0xa1ba1ba79e1632dcUL, 0xca28a291859bbf93UL,
    0xfcb2cb35e702af78UL, 0x9defbf01b061adabUL,
    0xc56baec21c7a1916UL, 0xf6c69a72a3989f5bUL,
    0x9a3c2087a63f6399UL, 0xc0cb28a98fcf3c7fUL,
    0xf0fdf2d3f3c30b9fUL, 0x969eb7c47859e743UL,
    0xbc4665b596706114UL, 0xeb57ff22fc0c7959UL,
    0x9316ff75dd87cbd8UL, 0xb7dcbf5354e9beceUL,
    0xe5d3ef282a242e81UL, 0x8fa475791a569d10UL,
    0xb38d92d760ec4455UL, 0xe070f78d3927556aUL,
    0x8c469ab843b89562UL, 0xaf58416654a6babbUL,
    0xdb2e51bfe9d0696aUL, 0x88fcf317f22241e2UL,
    0xab3c2fddeeaad25aUL, 0xd60b3bd56a5586f1UL,
    0x85c7056562757456UL, 0xa738c6bebb12d16cUL,
    0xd106f86e69d785c7UL, 0x82a45b450226b39cUL,
    0xa34d721642b06084UL, 0xcc20ce9bd35c78a5UL,
    0xff290242c83396ceUL, 0x9f79a169bd203e41UL,
    0xc75809c42c684dd1UL, 0xf92e0c3537826145UL,
    0x9bbcc7a142b17ccbUL, 0xc2abf989935ddbfeUL,
    0xf356f7ebf83552feUL, 0x98165af37b2153deUL,
    0xbe1bf1b059e9a8d6UL, 0xeda2ee1c7064130cUL,
    0x9485d4d1c63e8be7UL, 0xb9a74a0637ce2ee1UL,
    0xe8111c87c5c1ba99UL, 0x910ab1d4db9914a0UL,
    0xb54d5e4a127f59c8UL, 0xe2a0b5dc971f303aUL,
    0x8da471a9de737e24UL, 0xb10d8e1456105dadUL,
    0xdd50f1996b947518UL, 0x8a5296ffe33cc92fUL,
    0xace73cbfdc0bfb7bUL, 0xd8210befd30efa5aUL,
    0x8714a775e3e95c78UL, 0xa8d9d1535ce3b396UL,
    0xd31045a8341ca07cUL, 0x83ea2b892091e44dUL,
    0xa4e4b66b68b65d60UL, 0xce1de40642e3f4b9UL,
    0x80d2ae83e9ce78f3UL, 0xa1075a24e4421730UL,
    0xc94930ae1d529cfcUL, 0xfb9b7cd9a4a7443cUL,
    0x9d412e0806e88aa5UL, 0xc491798a08a2ad4eUL,
    0xf5b5d7ec8acb58a2UL, 0x9991a6f3d6bf1765UL,
    0xbff610b0cc6edd3fUL, 0xeff394dcff8a948eUL,
    0x95f83d0a1fb69cd9UL, 0xbb764c4ca7a4440fUL,
    0xea53df5fd18d5513UL, 0x92746b9be2f8552cUL,
    0xb7118682dbb66a77UL, 0xe4d5e82392a40515UL,
    0x8f05b1163ba6832dUL, 0xb2c71d5bca9023f8UL,
    0xdf78e4b2bd342cf6UL, 0x8bab8eefb6409c1aUL,
    0xae9672aba3d0c320UL, 0xda3c0f568cc4f3e8UL,
    0x8865899617fb1871UL, 0xaa7eebfb9df9de8dUL,
    0xd51ea6fa85785631UL, 0x8533285c936b35deUL,
    0xa67ff273b8460356UL, 0xd01fef10a657842cUL,
    0x8213f56a67f6b29bUL, 0xa298f2c501f45f42UL,
    0xcb3f2f7642717713UL, 0xfe0efb53d30dd4d7UL,
    0x9ec95d1463e8a506UL, 0xc67bb4597ce2ce48UL,
    0xf81aa16fdc1b81daUL, 0x9b10a4e5e9913128UL,
    0xc1d4ce1f63f57d72UL, 0xf24a01a73cf2dccfUL,
    0x976e41088617ca01UL, 0xbd49d14aa79dbc82UL,
    0xec9c459d51852ba2UL, 0x93e1ab8252f33b45UL,
    0xb8da1662e7b00a17UL, 0xe7109bfba19c0c9dUL,
    0x906a617d450187e2UL, 0xb484f9dc9641e9daUL,
    0xe1a63853bbd26451UL, 0x8d07e33455637eb2UL,
    0xb049dc016abc5e5fUL, 0xdc5c5301c56b75f7UL,
    0x89b9b3e11b6329baUL, 0xac2820d9623bf429UL,
    0xd732290fbacaf133UL, 0x867f59a9d4bed6c0UL,
    0xa81f301449ee8c70UL, 0xd226fc195c6a2f8cUL,
    0x83585d8fd9c25db7UL, 0xa42e74f3d032f525UL,
    0xcd3a1230c43fb26fUL, 0x80444b5e7aa7cf85UL,
    0xa0555e361951c366UL, 0xc86ab5c39fa63440UL,
    0xfa856334878fc150UL, 0x9c935e00d4b9d8d2UL,
    0xc3b8358109e84f07UL, 0xf4a642e14c6262c8UL,
    0x98e7e9cccfbd7dbdUL, 0xbf21e44003acdd2cUL,
    0xeeea5d5004981478UL, 0x95527a5202df0ccbUL,
    0xbaa718e68396cffdUL, 0xe950df20247c83fdUL,
    0x91d28b7416cdd27eUL, 0xb6472e511c81471dUL,
    0xe3d8f9e563a198e5UL, 0x8e679c2f5e44ff8fUL
)

internal inline val Char.isDigit get() = (this - '0').toChar().code < 10

private inline fun pack(index: Int, value: Float): Long {
    return (index.toLong() shl 32) or (value.toRawBits().toLong() and 0xFFFFFFFFL)
}

private inline fun fullMultiplicationHighBits(x: Long, y: Long): Long {
    val xLo = x and 0xffffffffL
    val xHi = x ushr 32
    val yLo = y and 0xffffffffL
    val yHi = y ushr 32

    val xTimesYHi = xHi * yHi
    val xTimesYMid = xLo * yHi
    val yTimesXMid = xHi * yLo
    val xTimesYLo = xLo * yLo

    val carry =
        yTimesXMid +
        (xTimesYLo ushr 32) +
        (xTimesYMid and 0xffffffffL)

    return xTimesYHi + (carry ushr 32) + (xTimesYMid ushr 32)
}

private inline fun parseFourDigits(str: String, offset: Int): Int {
    val v = (str[offset].code.toLong()
        or (str[offset + 1].code.toLong() shl 16)
        or (str[offset + 2].code.toLong() shl 32)
        or (str[offset + 3].code.toLong() shl 48))

    val base = v - 0x0030003000300030L
    val predicate = v + 0x0046004600460046L or base
    return if (predicate and 0xff80_ff80_ff80_ff80UL.toLong() != 0L) {
        -1
    } else {
        (base * 0x03e80064000a0001L ushr 48).toInt()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy