Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should atod fail when different from inf or infinity #102

Open
captain-yoshi opened this issue Dec 28, 2022 · 1 comment
Open

Should atod fail when different from inf or infinity #102

captain-yoshi opened this issue Dec 28, 2022 · 1 comment

Comments

@captain-yoshi
Copy link

A string that begins with inf, regardless of what comes after (except "" and "inity"), will silently succeed :

double d;
char str[] = "Informed"

if (atod(str, &d)) {
    std::cout << "This should fail !" << std::endl;
    std::cout << d << std::endl;
}

// This should fail !
// inf

Does atod do whole string matching ? Is this the intended behavior.


My use case is for decoding primitives not known in advance in a specific order :

    {  // bool
        bool value;
        if (from_chars(substr, &value))
            return XmlRpc::XmlRpcValue(value);
    }

    {  // int
        int value;
        if (from_chars(substr, &value))
            return XmlRpc::XmlRpcValue(value);
    }

    {  // double
        double value;
        if (from_chars(substr, &value))
            return XmlRpc::XmlRpcValue(value);
    }

    {  // string
        std::string value;
        if (from_chars(substr, &value))
            return XmlRpc::XmlRpcValue(value);
    }

Ultimately, is it up to me to check for a inf character is valid ?

@captain-yoshi
Copy link
Author

captain-yoshi commented Dec 29, 2022

So adding this patch, works as expected for my use case (Based on fastfloat/fast_float#164). We would need to check that the string has been fully consumed by fastfloat. Some other functions would maybe need this change :

  • atod -> C4CORE_HAVE_STD_FROMCHARS
  • atof
  • other ?
C4_ALWAYS_INLINE bool atod(csubstr str, double * C4_RESTRICT v) noexcept
{
    C4_ASSERT(str.triml(" \r\t\n").len == str.len);
#if C4CORE_HAVE_FAST_FLOAT
    // fastfloat cannot parse hexadecimal floats
    bool isneg = (str.str[0] == '-');
    csubstr rem = str.sub(isneg || str.str[0] == '+');
    if(!(rem.len >= 2 && (rem.str[0] == '0' && (rem.str[1] == 'x' || rem.str[1] == 'X'))))
    {
        fast_float::from_chars_result result;
        result = fast_float::from_chars(str.str, str.str + str.len, *v);

        // str must be fully consumed to be valid
        if(result.ptr - str.str != str.len)
            result.ec = std::errc::invalid_argument;
        
        return result.ec == std::errc();
    }
    else if(detail::scan_rhex(rem.sub(2), v))
    {
        *v *= isneg ? -1. : 1.;
        return true;
    }
    return false;
#elif C4CORE_HAVE_STD_FROMCHARS
    std::from_chars_result result;
    result = std::from_chars(str.str, str.str + str.len, *v);
    return result.ec == std::errc();
#else
    csubstr rem = str.sub(str.str[0] == '-' || str.str[0] == '+');
    if(!(rem.len >= 2 && (rem.str[0] == '0' && (rem.str[1] == 'x' || rem.str[1] == 'X'))))
        return detail::scan_one(str, "lf", v) != csubstr::npos;
    else
        return detail::scan_one(str, "la", v) != csubstr::npos;
#endif
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant