mirror of
https://github.com/boostorg/parser.git
synced 2026-01-19 04:22:13 +00:00
Use std::from_chars, if available; otherwise, use boost::charconv::from_chars,
if available; otherwise, use the Spirit X3 number parsers. Fixes #113.
This commit is contained in:
@@ -12,12 +12,29 @@
|
||||
#ifndef BOOST_PARSER_DETAIL_NUMERIC_HPP
|
||||
#define BOOST_PARSER_DETAIL_NUMERIC_HPP
|
||||
|
||||
#include <boost/parser/detail/text/unpack.hpp>
|
||||
|
||||
#include <version>
|
||||
#if defined(__cpp_lib_to_chars)
|
||||
#include <charconv>
|
||||
#define BOOST_PARSER_HAVE_STD_CHARCONV
|
||||
#elif __has_include(<boost/charconv.hpp>)
|
||||
#include <boost/charconv.hpp>
|
||||
#define BOOST_PARSER_HAVE_BOOST_CHARCONV
|
||||
#endif
|
||||
#include <type_traits>
|
||||
#include <cmath>
|
||||
|
||||
#if defined(BOOST_PARSER_HAVE_STD_CHARCONV) || \
|
||||
defined(BOOST_PARSER_HAVE_BOOST_CHARCONV)
|
||||
#define BOOST_PARSER_HAVE_CHARCONV
|
||||
#endif
|
||||
|
||||
namespace boost { namespace parser { namespace detail_spirit_x3 {
|
||||
|
||||
struct unused_type{};
|
||||
namespace boost::parser::detail_spirit_x3 {
|
||||
|
||||
struct unused_type
|
||||
{};
|
||||
|
||||
// Copied from boost/spirit/home/support/char_class.hpp (Boost 1.71), and
|
||||
// modified not to use Boost.TypeTraits.
|
||||
@@ -963,7 +980,104 @@ namespace boost { namespace parser { namespace detail_spirit_x3 {
|
||||
{
|
||||
static bool const expect_dot = true;
|
||||
};
|
||||
}
|
||||
|
||||
}}}
|
||||
namespace boost::parser::detail::numeric {
|
||||
|
||||
template<typename I, typename S>
|
||||
constexpr bool common_range = std::is_same_v<I, S>;
|
||||
|
||||
template<typename I, typename S>
|
||||
using unpacked_iter = decltype(text::unpack_iterator_and_sentinel(
|
||||
std::declval<I>(), std::declval<S>())
|
||||
.first);
|
||||
|
||||
template<typename I, typename S>
|
||||
constexpr bool unpacks_to_chars =
|
||||
std::is_pointer_v<unpacked_iter<I, S>> && std::is_same_v<
|
||||
std::remove_cv_t<std::remove_reference_t<
|
||||
std::remove_pointer_t<unpacked_iter<I, S>>>>,
|
||||
char>;
|
||||
|
||||
template<int MinDigits, int MaxDigits, typename I, typename S>
|
||||
#if defined(BOOST_PARSER_HAVE_CHARCONV)
|
||||
constexpr bool use_charconv_int =
|
||||
MinDigits == 1 && MaxDigits == -1 &&
|
||||
common_range<I, S> && unpacks_to_chars<I, S>;
|
||||
#else
|
||||
constexpr bool use_charconv_int = false;
|
||||
#endif
|
||||
|
||||
template<
|
||||
bool Signed,
|
||||
int Radix,
|
||||
int MinDigits,
|
||||
int MaxDigits,
|
||||
typename I,
|
||||
typename S,
|
||||
typename T>
|
||||
bool parse_int(I & first, S last, T & attr)
|
||||
{
|
||||
if constexpr (use_charconv_int<MinDigits, MaxDigits, I, S>) {
|
||||
#if defined(BOOST_PARSER_HAVE_CHARCONV)
|
||||
auto unpacked = text::unpack_iterator_and_sentinel(first, last);
|
||||
#if defined(BOOST_PARSER_HAVE_STD_CHARCONV)
|
||||
std::from_chars_result const result = std::from_chars(
|
||||
#else
|
||||
charconv::from_chars_result const result = charconv::from_chars(
|
||||
#endif
|
||||
unpacked.first, unpacked.last, attr, Radix);
|
||||
if (result.ec == std::errc()) {
|
||||
first = unpacked.repack(result.ptr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
} else if constexpr (Signed) {
|
||||
using extract =
|
||||
detail_spirit_x3::extract_int<T, Radix, MinDigits, MaxDigits>;
|
||||
return extract::call(first, last, attr);
|
||||
} else {
|
||||
using extract =
|
||||
detail_spirit_x3::extract_uint<T, Radix, MinDigits, MaxDigits>;
|
||||
return extract::call(first, last, attr);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename I, typename S>
|
||||
#if defined(BOOST_PARSER_HAVE_CHARCONV)
|
||||
constexpr bool use_charconv_real =
|
||||
common_range<I, S> && unpacks_to_chars<I, S>;
|
||||
#else
|
||||
constexpr bool use_charconv_real = false;
|
||||
#endif
|
||||
|
||||
template<typename I, typename S, typename T>
|
||||
bool parse_real(I & first, S last, T & attr)
|
||||
{
|
||||
if constexpr (use_charconv_real<I, S>) {
|
||||
#if defined(BOOST_PARSER_HAVE_CHARCONV)
|
||||
auto unpacked = text::unpack_iterator_and_sentinel(first, last);
|
||||
#if defined(BOOST_PARSER_HAVE_STD_CHARCONV)
|
||||
std::from_chars_result const result = std::from_chars(
|
||||
#else
|
||||
charconv::from_chars_result const result = charconv::from_chars(
|
||||
#endif
|
||||
unpacked.first, unpacked.last, attr);
|
||||
if (result.ec == std::errc()) {
|
||||
first = unpacked.repack(result.ptr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
detail_spirit_x3::real_policies<T> policies;
|
||||
using extract = detail_spirit_x3::
|
||||
extract_real<T, detail_spirit_x3::real_policies<T>>;
|
||||
return extract::parse(first, last, attr, policies);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6882,11 +6882,12 @@ namespace boost { namespace parser {
|
||||
{
|
||||
auto _ = detail::scoped_trace(
|
||||
*this, first, last, context, flags, retval);
|
||||
using extract =
|
||||
detail_spirit_x3::extract_uint<T, Radix, MinDigits, MaxDigits>;
|
||||
T attr = 0;
|
||||
success = extract::call(first, last, attr);
|
||||
if (attr != detail::resolve(context, expected_))
|
||||
auto const initial = first;
|
||||
success =
|
||||
detail::numeric::parse_int<false, Radix, MinDigits, MaxDigits>(
|
||||
first, last, attr);
|
||||
if (first == initial || attr != detail::resolve(context, expected_))
|
||||
success = false;
|
||||
if (success)
|
||||
detail::assign(retval, attr);
|
||||
@@ -6993,11 +6994,11 @@ namespace boost { namespace parser {
|
||||
{
|
||||
auto _ = detail::scoped_trace(
|
||||
*this, first, last, context, flags, retval);
|
||||
using extract =
|
||||
detail_spirit_x3::extract_int<T, Radix, MinDigits, MaxDigits>;
|
||||
T attr = 0;
|
||||
auto const initial = first;
|
||||
success = extract::call(first, last, attr);
|
||||
success =
|
||||
detail::numeric::parse_int<true, Radix, MinDigits, MaxDigits>(
|
||||
first, last, attr);
|
||||
if (first == initial || attr != detail::resolve(context, expected_))
|
||||
success = false;
|
||||
if (success)
|
||||
@@ -7081,12 +7082,9 @@ namespace boost { namespace parser {
|
||||
{
|
||||
auto _ = detail::scoped_trace(
|
||||
*this, first, last, context, flags, retval);
|
||||
detail_spirit_x3::real_policies<T> policies;
|
||||
using extract = detail_spirit_x3::
|
||||
extract_real<T, detail_spirit_x3::real_policies<T>>;
|
||||
T attr = 0;
|
||||
auto const initial = first;
|
||||
success = extract::parse(first, last, attr, policies);
|
||||
success = detail::numeric::parse_real(first, last, attr);
|
||||
if (first == initial)
|
||||
success = false;
|
||||
if (success)
|
||||
|
||||
Reference in New Issue
Block a user