Alternative handling of integer types relying on strto[u]ll
This commit is contained in:
parent
c75efedc6e
commit
e41a956782
2 changed files with 88 additions and 4 deletions
46
src/json.hpp
46
src/json.hpp
|
@ -9073,6 +9073,8 @@ basic_json_parser_66:
|
||||||
|
|
||||||
note: in floating-point case strtod may parse
|
note: in floating-point case strtod may parse
|
||||||
past the token's end - this is not an error.
|
past the token's end - this is not an error.
|
||||||
|
|
||||||
|
any leading blanks are not handled.
|
||||||
*/
|
*/
|
||||||
struct strtonum
|
struct strtonum
|
||||||
{
|
{
|
||||||
|
@ -9232,6 +9234,45 @@ basic_json_parser_66:
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 1 // parsing with strto[u]ll - easier to understand but slightly slower
|
||||||
|
|
||||||
|
signed long long parse_integral(
|
||||||
|
char** endptr,
|
||||||
|
/*is_signed*/std::true_type) const
|
||||||
|
{
|
||||||
|
return std::strtoll(m_start, endptr, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long parse_integral(
|
||||||
|
char** endptr,
|
||||||
|
/*is_signed*/std::false_type) const
|
||||||
|
{
|
||||||
|
return std::strtoull(m_start, endptr, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool parse(T& value, /*is_integral=*/std::true_type) const
|
||||||
|
{
|
||||||
|
char* endptr = nullptr;
|
||||||
|
errno = 0; // these are thread-local
|
||||||
|
const auto x = parse_integral(&endptr, std::is_signed<T>());
|
||||||
|
|
||||||
|
static_assert(std::is_signed<T>() // called right overload?
|
||||||
|
== std::is_signed<decltype(x)>(), "");
|
||||||
|
|
||||||
|
value = static_cast<T>(x);
|
||||||
|
|
||||||
|
return x == static_cast<decltype(x)>(value) // x fits into destination T
|
||||||
|
and (x != 0 or is_integral()) // strto[u]ll did nto fail
|
||||||
|
and errno == 0 // strto[u]ll did not overflow
|
||||||
|
and m_start < m_end // token was not empty
|
||||||
|
and endptr == m_end // parsed entire token exactly
|
||||||
|
and (x < 0) == (*m_start == '-'); // input was sign-compatible
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // parsing integral types manually
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool parse(T& value, /*is_integral=*/std::true_type) const
|
bool parse(T& value, /*is_integral=*/std::true_type) const
|
||||||
{
|
{
|
||||||
|
@ -9240,7 +9281,7 @@ basic_json_parser_66:
|
||||||
|
|
||||||
if (beg == end)
|
if (beg == end)
|
||||||
{
|
{
|
||||||
return false;
|
return false; // empty token
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_negative = (*beg == '-');
|
const bool is_negative = (*beg == '-');
|
||||||
|
@ -9261,7 +9302,7 @@ basic_json_parser_66:
|
||||||
|
|
||||||
bool valid = beg < end // must have some digits;
|
bool valid = beg < end // must have some digits;
|
||||||
and ( T(-1) < 0 // type must be signed
|
and ( T(-1) < 0 // type must be signed
|
||||||
or !is_negative); // if value is negative
|
or !is_negative); // ...if value is negative
|
||||||
|
|
||||||
while (beg < end and valid)
|
while (beg < end and valid)
|
||||||
{
|
{
|
||||||
|
@ -9288,6 +9329,7 @@ basic_json_parser_66:
|
||||||
// into positives is for edge cases, e.g. -2^63
|
// into positives is for edge cases, e.g. -2^63
|
||||||
return valid && (is_negative == (value < 0));
|
return valid && (is_negative == (value < 0));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -8222,6 +8222,8 @@ class basic_json
|
||||||
|
|
||||||
note: in floating-point case strtod may parse
|
note: in floating-point case strtod may parse
|
||||||
past the token's end - this is not an error.
|
past the token's end - this is not an error.
|
||||||
|
|
||||||
|
any leading blanks are not handled.
|
||||||
*/
|
*/
|
||||||
struct strtonum
|
struct strtonum
|
||||||
{
|
{
|
||||||
|
@ -8381,6 +8383,45 @@ class basic_json
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 1 // parsing with strto[u]ll - easier to understand but slightly slower
|
||||||
|
|
||||||
|
signed long long parse_integral(
|
||||||
|
char** endptr,
|
||||||
|
/*is_signed*/std::true_type) const
|
||||||
|
{
|
||||||
|
return std::strtoll(m_start, endptr, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long parse_integral(
|
||||||
|
char** endptr,
|
||||||
|
/*is_signed*/std::false_type) const
|
||||||
|
{
|
||||||
|
return std::strtoull(m_start, endptr, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool parse(T& value, /*is_integral=*/std::true_type) const
|
||||||
|
{
|
||||||
|
char* endptr = nullptr;
|
||||||
|
errno = 0; // these are thread-local
|
||||||
|
const auto x = parse_integral(&endptr, std::is_signed<T>());
|
||||||
|
|
||||||
|
static_assert(std::is_signed<T>() // called right overload?
|
||||||
|
== std::is_signed<decltype(x)>(), "");
|
||||||
|
|
||||||
|
value = static_cast<T>(x);
|
||||||
|
|
||||||
|
return x == static_cast<decltype(x)>(value) // x fits into destination T
|
||||||
|
and (x != 0 or is_integral()) // strto[u]ll did nto fail
|
||||||
|
and errno == 0 // strto[u]ll did not overflow
|
||||||
|
and m_start < m_end // token was not empty
|
||||||
|
and endptr == m_end // parsed entire token exactly
|
||||||
|
and (x < 0) == (*m_start == '-'); // input was sign-compatible
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // parsing integral types manually
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool parse(T& value, /*is_integral=*/std::true_type) const
|
bool parse(T& value, /*is_integral=*/std::true_type) const
|
||||||
{
|
{
|
||||||
|
@ -8389,7 +8430,7 @@ class basic_json
|
||||||
|
|
||||||
if (beg == end)
|
if (beg == end)
|
||||||
{
|
{
|
||||||
return false;
|
return false; // empty token
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_negative = (*beg == '-');
|
const bool is_negative = (*beg == '-');
|
||||||
|
@ -8410,7 +8451,7 @@ class basic_json
|
||||||
|
|
||||||
bool valid = beg < end // must have some digits;
|
bool valid = beg < end // must have some digits;
|
||||||
and ( T(-1) < 0 // type must be signed
|
and ( T(-1) < 0 // type must be signed
|
||||||
or !is_negative); // if value is negative
|
or !is_negative); // ...if value is negative
|
||||||
|
|
||||||
while (beg < end and valid)
|
while (beg < end and valid)
|
||||||
{
|
{
|
||||||
|
@ -8437,6 +8478,7 @@ class basic_json
|
||||||
// into positives is for edge cases, e.g. -2^63
|
// into positives is for edge cases, e.g. -2^63
|
||||||
return valid && (is_negative == (value < 0));
|
return valid && (is_negative == (value < 0));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
Loading…
Reference in a new issue