PNUMBER StringToNumber()

in src/CalcManager/Ratpack/conv.cpp [612:743]


PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precision)
{
    int32_t expSign = 1L;  // expSign is exponent sign ( +/- 1 )
    int32_t expValue = 0L; // expValue is exponent mantissa, should be unsigned

    PNUMBER pnumret = nullptr;
    createnum(pnumret, static_cast<uint32_t>(numberString.length()));
    pnumret->sign = 1L;
    pnumret->cdigit = 0;
    pnumret->exp = 0;
    MANTTYPE* pmant = pnumret->mant + numberString.length() - 1;

    uint8_t state = START; // state is the state of the input state machine.
    for (const auto& c : numberString)
    {
        // If the character is the decimal separator, use L'.' for the purposes of the state machine.
        wchar_t curChar = (c == g_decimalSeparator ? L'.' : c);

        // Switch states based on the character we encountered
        switch (curChar)
        {
        case L'-':
        case L'+':
            state = machine[state][SG];
            break;
        case L'.':
            state = machine[state][DP];
            break;
        case L'0':
            state = machine[state][ZR];
            break;
        case L'^':
        case L'e':
            if (curChar == L'^' || radix == 10)
            {
                state = machine[state][EX];
                break;
            }
            // Drop through in the 'e'-as-a-digit case
            [[fallthrough]];
        default:
            state = machine[state][NZ];
            break;
        }

        // Now update our result value based on the state we are in
        switch (state)
        {
        case MANTS:
            pnumret->sign = (curChar == L'-') ? -1 : 1;
            break;
        case EXPSZ:
        case EXPS:
            expSign = (curChar == L'-') ? -1 : 1;
            break;
        case EXPDZ:
        case EXPD:
        {
            curChar = NormalizeCharDigit(curChar, radix);

            size_t pos = DIGITS.find(curChar);
            if (pos != wstring_view::npos)
            {
                expValue *= radix;
                expValue += static_cast<int32_t>(pos);
            }
            else
            {
                state = ERR;
            }
        }
        break;
        case LD:
            pnumret->exp++;
            [[fallthrough]];
        case DD:
        {
            curChar = NormalizeCharDigit(curChar, radix);

            size_t pos = DIGITS.find(curChar);
            if (pos != wstring_view::npos && pos < static_cast<size_t>(radix))
            {
                *pmant-- = static_cast<MANTTYPE>(pos);
                pnumret->exp--;
                pnumret->cdigit++;
            }
            else
            {
                state = ERR;
            }
        }
        break;
        case DZ:
            pnumret->exp--;
            break;
        case LZ:
        case LZDP:
        case DDP:
            break;
        }
    }

    if (state == DZ || state == EXPDZ)
    {
        pnumret->cdigit = 1;
        pnumret->exp = 0;
        pnumret->sign = 1;
    }
    else
    {
        while (pnumret->cdigit < static_cast<int32_t>(numberString.length()))
        {
            pnumret->cdigit++;
            pnumret->exp--;
        }

        pnumret->exp += expSign * expValue;
    }

    // If we don't have a number, clear our result.
    if (pnumret->cdigit == 0)
    {
        destroynum(pnumret);
        pnumret = nullptr;
    }
    else
    {
        stripzeroesnum(pnumret, precision);
    }

    return pnumret;
}