new strtod/ld/f function
This commit is contained in:
parent
60bba02cc6
commit
22f3f88771
201
src/json.hpp
201
src/json.hpp
@ -8800,64 +8800,187 @@ basic_json_parser_63:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// non locale aware isspace
|
||||||
|
bool nl_isspace(const char c) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
c == 0x20 or
|
||||||
|
c == 0x09 or
|
||||||
|
c == 0x0a or
|
||||||
|
c == 0x0b or
|
||||||
|
c == 0x0c or
|
||||||
|
c == 0x0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// non locale aware isdigit
|
||||||
|
// Microsoft in 1252 codepage and others may classify additional single-byte characters as digits using std::isdigit
|
||||||
|
bool nl_isdigit(const char c) const
|
||||||
|
{
|
||||||
|
return c >= '0' and c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief parse floating point number
|
@brief parse string to floating point number
|
||||||
|
|
||||||
This function (and its overloads) serves to select the most approprate
|
This function is a reimplementation of the strtold family without
|
||||||
standard floating point number parsing function based on the type
|
regard to locale
|
||||||
supplied via the first parameter. Set this to @a
|
|
||||||
static_cast<number_float_t*>(nullptr).
|
|
||||||
|
|
||||||
@param[in] type the @ref number_float_t in use
|
@tparam T a is_floating_point type
|
||||||
|
|
||||||
|
@param[in] st the string we will parse
|
||||||
|
|
||||||
@param[in,out] endptr recieves a pointer to the first character after
|
@param[in,out] endptr recieves a pointer to the first character after
|
||||||
the number
|
the number
|
||||||
|
|
||||||
@return the floating point number
|
@return the floating point number
|
||||||
*/
|
*/
|
||||||
long double str_to_float_t(long double* /* type */, char** endptr) const
|
template <typename T, typename = typename std::enable_if<
|
||||||
|
std::is_floating_point<T>::value>::type>
|
||||||
|
T strtox(const char *st, char **endptr) const
|
||||||
{
|
{
|
||||||
return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
|
constexpr std::array<long double, 9> powerof10 {
|
||||||
}
|
{1.e1L, 1.e2L, 1.e4L, 1.e8L, 1.e16L, 1.e32L, 1.e64L, 1.e128L, 1.e256L}
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
T result = 0;
|
||||||
@brief parse floating point number
|
const char *fst = st;
|
||||||
|
bool successful_parse = false;
|
||||||
|
|
||||||
This function (and its overloads) serves to select the most approprate
|
while (nl_isspace(*fst))
|
||||||
standard floating point number parsing function based on the type
|
{
|
||||||
supplied via the first parameter. Set this to @a
|
++fst;
|
||||||
static_cast<number_float_t*>(nullptr).
|
}
|
||||||
|
|
||||||
@param[in] type the @ref number_float_t in use
|
char cp = *fst;
|
||||||
|
int exp = 0; // exponent
|
||||||
|
{
|
||||||
|
const bool negative_sign = cp == '-';
|
||||||
|
|
||||||
@param[in,out] endptr recieves a pointer to the first character after
|
if (cp == '-' or cp == '+')
|
||||||
the number
|
{
|
||||||
|
++fst;
|
||||||
|
successful_parse = true;
|
||||||
|
}
|
||||||
|
|
||||||
@return the floating point number
|
// read in fractional part of number, until an 'e' is reached.
|
||||||
*/
|
// count digits after decimal point.
|
||||||
double str_to_float_t(double* /* type */, char** endptr) const
|
while (nl_isdigit(cp = *fst))
|
||||||
{
|
{
|
||||||
return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
|
result = result * 10 + (cp - '0');
|
||||||
}
|
successful_parse = true;
|
||||||
|
++fst;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
if (cp == '.')
|
||||||
@brief parse floating point number
|
{
|
||||||
|
while (nl_isdigit(cp = *++fst))
|
||||||
|
{
|
||||||
|
result = result * 10 + (cp - '0');
|
||||||
|
successful_parse = true;
|
||||||
|
--exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
This function (and its overloads) serves to select the most approprate
|
// if negative number, reverse sign
|
||||||
standard floating point number parsing function based on the type
|
if (negative_sign)
|
||||||
supplied via the first parameter. Set this to @a
|
{
|
||||||
static_cast<number_float_t*>(nullptr).
|
result = -result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@param[in] type the @ref number_float_t in use
|
// read in explicit exponent and calculate real exponent.
|
||||||
|
// if exponent is bogus (i.e. "1.234empty" or "1.234e+mpty") restore
|
||||||
|
// bogus exponent back onto returned string (endptr).
|
||||||
|
|
||||||
@param[in,out] endptr recieves a pointer to the first character after
|
if (successful_parse and (*fst == 'e' or *fst == 'E'))
|
||||||
the number
|
{
|
||||||
|
cp = *++fst;
|
||||||
|
bool negative_exp = cp == '-'; // read in exponent sign (+/-)
|
||||||
|
|
||||||
@return the floating point number
|
bool plus_or_minus = false;
|
||||||
*/
|
if (cp == '-' or cp == '+')
|
||||||
float str_to_float_t(float* /* type */, char** endptr) const
|
{
|
||||||
{
|
cp = *++fst;
|
||||||
return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
|
plus_or_minus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0; // exponent calculation
|
||||||
|
if (! nl_isdigit(cp))
|
||||||
|
{
|
||||||
|
if (plus_or_minus)
|
||||||
|
{
|
||||||
|
*--fst;
|
||||||
|
}
|
||||||
|
|
||||||
|
*--fst;
|
||||||
|
goto skip_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (nl_isdigit(cp))
|
||||||
|
{
|
||||||
|
constexpr int imax = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
if ((imax - std::abs(exp) - (cp - '0')) / 10 > count)
|
||||||
|
{
|
||||||
|
count *= 10;
|
||||||
|
count += cp - '0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = imax - exp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = *++fst;
|
||||||
|
}
|
||||||
|
skip_loop:
|
||||||
|
exp += negative_exp ? -count : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust number by powers of ten specified by format and exponent.
|
||||||
|
if (result != 0.0)
|
||||||
|
{
|
||||||
|
if (exp > std::numeric_limits<T>::max_exponent10)
|
||||||
|
{
|
||||||
|
errno = ERANGE;
|
||||||
|
constexpr T inf = std::numeric_limits<T>::infinity();
|
||||||
|
result = (result < 0) ? -inf : inf;
|
||||||
|
}
|
||||||
|
else if (exp < std::numeric_limits<T>::min_exponent10)
|
||||||
|
{
|
||||||
|
errno = ERANGE;
|
||||||
|
result = 0.0;
|
||||||
|
}
|
||||||
|
else if (exp < 0)
|
||||||
|
{
|
||||||
|
exp = -exp;
|
||||||
|
|
||||||
|
for (std::size_t count = 0; exp; count++, exp >>= 1)
|
||||||
|
{
|
||||||
|
if (exp & 1)
|
||||||
|
{
|
||||||
|
result /= powerof10[count];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (std::size_t count = 0; exp; count++, exp >>= 1)
|
||||||
|
{
|
||||||
|
if (exp & 1)
|
||||||
|
{
|
||||||
|
result *= powerof10[count];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr != nullptr)
|
||||||
|
{
|
||||||
|
*endptr = const_cast<char *>(successful_parse ? fst : st);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -8959,7 +9082,7 @@ basic_json_parser_63:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parse with strtod
|
// parse with strtod
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
|
result.m_value.number_float = strtox<number_float_t>(reinterpret_cast<typename string_t::const_pointer>(m_start), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the type
|
// save the type
|
||||||
|
|||||||
@ -8097,64 +8097,187 @@ class basic_json
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// non locale aware isspace
|
||||||
|
bool nl_isspace(const char c) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
c == 0x20 or
|
||||||
|
c == 0x09 or
|
||||||
|
c == 0x0a or
|
||||||
|
c == 0x0b or
|
||||||
|
c == 0x0c or
|
||||||
|
c == 0x0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// non locale aware isdigit
|
||||||
|
// Microsoft in 1252 codepage and others may classify additional single-byte characters as digits using std::isdigit
|
||||||
|
bool nl_isdigit(const char c) const
|
||||||
|
{
|
||||||
|
return c >= '0' and c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief parse floating point number
|
@brief parse string to floating point number
|
||||||
|
|
||||||
This function (and its overloads) serves to select the most approprate
|
This function is a reimplementation of the strtold family without
|
||||||
standard floating point number parsing function based on the type
|
regard to locale
|
||||||
supplied via the first parameter. Set this to @a
|
|
||||||
static_cast<number_float_t*>(nullptr).
|
|
||||||
|
|
||||||
@param[in] type the @ref number_float_t in use
|
@tparam T a is_floating_point type
|
||||||
|
|
||||||
|
@param[in] st the string we will parse
|
||||||
|
|
||||||
@param[in,out] endptr recieves a pointer to the first character after
|
@param[in,out] endptr recieves a pointer to the first character after
|
||||||
the number
|
the number
|
||||||
|
|
||||||
@return the floating point number
|
@return the floating point number
|
||||||
*/
|
*/
|
||||||
long double str_to_float_t(long double* /* type */, char** endptr) const
|
template <typename T, typename = typename std::enable_if<
|
||||||
|
std::is_floating_point<T>::value>::type>
|
||||||
|
T strtox(const char *st, char **endptr) const
|
||||||
{
|
{
|
||||||
return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
|
constexpr std::array<long double, 9> powerof10 {
|
||||||
}
|
{1.e1L, 1.e2L, 1.e4L, 1.e8L, 1.e16L, 1.e32L, 1.e64L, 1.e128L, 1.e256L}
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
T result = 0;
|
||||||
@brief parse floating point number
|
const char *fst = st;
|
||||||
|
bool successful_parse = false;
|
||||||
|
|
||||||
This function (and its overloads) serves to select the most approprate
|
while (nl_isspace(*fst))
|
||||||
standard floating point number parsing function based on the type
|
{
|
||||||
supplied via the first parameter. Set this to @a
|
++fst;
|
||||||
static_cast<number_float_t*>(nullptr).
|
}
|
||||||
|
|
||||||
@param[in] type the @ref number_float_t in use
|
char cp = *fst;
|
||||||
|
int exp = 0; // exponent
|
||||||
|
{
|
||||||
|
const bool negative_sign = cp == '-';
|
||||||
|
|
||||||
@param[in,out] endptr recieves a pointer to the first character after
|
if (cp == '-' or cp == '+')
|
||||||
the number
|
{
|
||||||
|
++fst;
|
||||||
|
successful_parse = true;
|
||||||
|
}
|
||||||
|
|
||||||
@return the floating point number
|
// read in fractional part of number, until an 'e' is reached.
|
||||||
*/
|
// count digits after decimal point.
|
||||||
double str_to_float_t(double* /* type */, char** endptr) const
|
while (nl_isdigit(cp = *fst))
|
||||||
{
|
{
|
||||||
return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
|
result = result * 10 + (cp - '0');
|
||||||
}
|
successful_parse = true;
|
||||||
|
++fst;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
if (cp == '.')
|
||||||
@brief parse floating point number
|
{
|
||||||
|
while (nl_isdigit(cp = *++fst))
|
||||||
|
{
|
||||||
|
result = result * 10 + (cp - '0');
|
||||||
|
successful_parse = true;
|
||||||
|
--exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
This function (and its overloads) serves to select the most approprate
|
// if negative number, reverse sign
|
||||||
standard floating point number parsing function based on the type
|
if (negative_sign)
|
||||||
supplied via the first parameter. Set this to @a
|
{
|
||||||
static_cast<number_float_t*>(nullptr).
|
result = -result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@param[in] type the @ref number_float_t in use
|
// read in explicit exponent and calculate real exponent.
|
||||||
|
// if exponent is bogus (i.e. "1.234empty" or "1.234e+mpty") restore
|
||||||
|
// bogus exponent back onto returned string (endptr).
|
||||||
|
|
||||||
@param[in,out] endptr recieves a pointer to the first character after
|
if (successful_parse and (*fst == 'e' or *fst == 'E'))
|
||||||
the number
|
{
|
||||||
|
cp = *++fst;
|
||||||
|
bool negative_exp = cp == '-'; // read in exponent sign (+/-)
|
||||||
|
|
||||||
@return the floating point number
|
bool plus_or_minus = false;
|
||||||
*/
|
if (cp == '-' or cp == '+')
|
||||||
float str_to_float_t(float* /* type */, char** endptr) const
|
{
|
||||||
{
|
cp = *++fst;
|
||||||
return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
|
plus_or_minus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0; // exponent calculation
|
||||||
|
if (! nl_isdigit(cp))
|
||||||
|
{
|
||||||
|
if (plus_or_minus)
|
||||||
|
{
|
||||||
|
*--fst;
|
||||||
|
}
|
||||||
|
|
||||||
|
*--fst;
|
||||||
|
goto skip_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (nl_isdigit(cp))
|
||||||
|
{
|
||||||
|
constexpr int imax = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
if ((imax - std::abs(exp) - (cp - '0')) / 10 > count)
|
||||||
|
{
|
||||||
|
count *= 10;
|
||||||
|
count += cp - '0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = imax - exp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = *++fst;
|
||||||
|
}
|
||||||
|
skip_loop:
|
||||||
|
exp += negative_exp ? -count : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust number by powers of ten specified by format and exponent.
|
||||||
|
if (result != 0.0)
|
||||||
|
{
|
||||||
|
if (exp > std::numeric_limits<T>::max_exponent10)
|
||||||
|
{
|
||||||
|
errno = ERANGE;
|
||||||
|
constexpr T inf = std::numeric_limits<T>::infinity();
|
||||||
|
result = (result < 0) ? -inf : inf;
|
||||||
|
}
|
||||||
|
else if (exp < std::numeric_limits<T>::min_exponent10)
|
||||||
|
{
|
||||||
|
errno = ERANGE;
|
||||||
|
result = 0.0;
|
||||||
|
}
|
||||||
|
else if (exp < 0)
|
||||||
|
{
|
||||||
|
exp = -exp;
|
||||||
|
|
||||||
|
for (std::size_t count = 0; exp; count++, exp >>= 1)
|
||||||
|
{
|
||||||
|
if (exp & 1)
|
||||||
|
{
|
||||||
|
result /= powerof10[count];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (std::size_t count = 0; exp; count++, exp >>= 1)
|
||||||
|
{
|
||||||
|
if (exp & 1)
|
||||||
|
{
|
||||||
|
result *= powerof10[count];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr != nullptr)
|
||||||
|
{
|
||||||
|
*endptr = const_cast<char *>(successful_parse ? fst : st);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -8256,7 +8379,7 @@ class basic_json
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parse with strtod
|
// parse with strtod
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
|
result.m_value.number_float = strtox<number_float_t>(reinterpret_cast<typename string_t::const_pointer>(m_start), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the type
|
// save the type
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user