#include #include // numeric_limits #include // move() #include #include // strto*() #include // enable_if, is_* #include // strlen() namespace butl { namespace json { inline invalid_json_input:: invalid_json_input (std::string n, std::uint64_t l, std::uint64_t c, std::uint64_t p, const std::string& d) : invalid_json_input (move (n), l, c, p, d.c_str ()) { } inline invalid_json_input:: invalid_json_input (std::string n, std::uint64_t l, std::uint64_t c, std::uint64_t p, const char* d) : invalid_argument (d), name (std::move (n)), line (l), column (c), position (p) { } inline parser:: parser (std::istream& is, const std::string& n, bool mv, const char* sep) noexcept : parser (is, n.c_str (), mv, sep) { } inline parser:: parser (const void* t, std::size_t s, const std::string& n, bool mv, const char* sep) noexcept : parser (t, s, n.c_str (), mv, sep) { } inline parser:: parser (const std::string& t, const std::string& n, bool mv, const char* sep) noexcept : parser (t.data (), t.size (), n.c_str (), mv, sep) { } inline parser:: parser (const std::string& t, const char* n, bool mv, const char* sep) noexcept : parser (t.data (), t.size (), n, mv, sep) { } inline parser:: parser (const char* t, const std::string& n, bool mv, const char* sep) noexcept : parser (t, std::strlen (t), n.c_str (), mv, sep) { } inline parser:: parser (const char* t, const char* n, bool mv, const char* sep) noexcept : parser (t, std::strlen (t), n, mv, sep) { } inline const std::string& parser:: name () { if (!name_p_) { assert (parsed_ && !peeked_ && !value_p_); cache_parsed_data (); assert (name_p_); } return name_; } inline std::string& parser:: value () { if (!value_p_) { assert (parsed_ && !peeked_ && !name_p_); cache_parsed_data (); assert (value_p_); } return value_; } // Note: one day we will be able to use C++17 from_chars() which was made // exactly for this. // template inline typename std::enable_if::value, T>::type parse_value (const char* b, size_t, const parser&) { return *b == 't'; } template inline typename std::enable_if< std::is_integral::value && std::is_signed::value && !std::is_same::value, T>::type parse_value (const char* b, size_t n, const parser& p) { char* e (nullptr); errno = 0; // We must clear it according to POSIX. std::int64_t v (strtoll (b, &e, 10)); // Can't throw. if (e == b || e != b + n || errno == ERANGE || v < std::numeric_limits::min () || v > std::numeric_limits::max ()) p.throw_invalid_value ("signed integer", b, n); return static_cast (v); } template inline typename std::enable_if< std::is_integral::value && std::is_unsigned::value && !std::is_same::value, T>::type parse_value (const char* b, size_t n, const parser& p) { char* e (nullptr); errno = 0; // We must clear it according to POSIX. std::uint64_t v (strtoull (b, &e, 10)); // Can't throw. if (e == b || e != b + n || errno == ERANGE || v > std::numeric_limits::max ()) p.throw_invalid_value ("unsigned integer", b, n); return static_cast (v); } template inline typename std::enable_if::value, T>::type parse_value (const char* b, size_t n, const parser& p) { char* e (nullptr); errno = 0; // We must clear it according to POSIX. T r (std::strtof (b, &e)); if (e == b || e != b + n || errno == ERANGE) p.throw_invalid_value ("float", b, n); return r; } template inline typename std::enable_if::value, T>::type parse_value (const char* b, size_t n, const parser& p) { char* e (nullptr); errno = 0; // We must clear it according to POSIX. T r (std::strtod (b, &e)); if (e == b || e != b + n || errno == ERANGE) p.throw_invalid_value ("double", b, n); return r; } template inline typename std::enable_if::value, T>::type parse_value (const char* b, size_t n, const parser& p) { char* e (nullptr); errno = 0; // We must clear it according to POSIX. T r (std::strtold (b, &e)); if (e == b || e != b + n || errno == ERANGE) p.throw_invalid_value ("long double", b, n); return r; } template inline T parser:: value () const { if (!value_p_) { assert (parsed_ && !peeked_ && value_event (translate (*parsed_))); return parse_value (raw_s_, raw_n_, *this); } return parse_value (value_.data (), value_.size (), *this); } } }