diff --git a/iguana/detail/charconv.h b/iguana/detail/charconv.h index c17e52e6..16b34be7 100644 --- a/iguana/detail/charconv.h +++ b/iguana/detail/charconv.h @@ -18,25 +18,23 @@ namespace detail { template std::pair from_chars(const char *first, const char *last, U &value) { -#define CHECK_NUM \ - if (p != last || ec != std::errc{}) \ - IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } using T = std::decay_t; if constexpr (std::is_floating_point_v) { auto [p, ec] = fast_float::from_chars(first, last, value); if constexpr (check_number) { - CHECK_NUM + if (p != last || ec != std::errc{}) + IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } } return {p, ec}; } else { auto [p, ec] = std::from_chars(first, last, value); if constexpr (check_number) { - CHECK_NUM + if (p != last || ec != std::errc{}) + IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } } return {p, ec}; } -#undef CHECK_NUM } // not support uint8 for now diff --git a/iguana/json_reader.hpp b/iguana/json_reader.hpp index d99ef08a..1dcd9a58 100644 --- a/iguana/json_reader.hpp +++ b/iguana/json_reader.hpp @@ -69,10 +69,7 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } const auto start = &*it; auto [p, ec] = detail::from_chars(start, start + size, value); - // TODO: improve by static array - if (ec != std::errc{} || - !(*p == '}' || *p == ']' || *p == ',' || *p == ' ' || *p == '\0' || - *p == '"' || *p == '\n')) + if (ec != std::errc{} || !can_follow_number(*p)) IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } it += (p - &*it); } diff --git a/iguana/json_util.hpp b/iguana/json_util.hpp index 1b0f5db3..f1bf3a33 100644 --- a/iguana/json_util.hpp +++ b/iguana/json_util.hpp @@ -211,4 +211,28 @@ IGUANA_INLINE bool is_numeric(char c) noexcept { return static_cast(is_num[static_cast(c)]); } +// '\t' '\r' '\n' '"' '}' ']' ',' ' ' '\0' +IGUANA_INLINE bool can_follow_number(char c) noexcept { + static constexpr int can_follow_num[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + return static_cast(can_follow_num[static_cast(c)]); +} + } // namespace iguana