diff --git a/bench/bench.cpp b/bench/bench.cpp index ca6304b8..2a7a435e 100644 --- a/bench/bench.cpp +++ b/bench/bench.cpp @@ -9,6 +9,7 @@ #include "lib/nlohmann/single_include/nlohmann/json.hpp" +#include "lib/rapidjson/include/rapidjson/rapidjson.h" #include "lib/rapidjson/include/rapidjson/document.h" #include "lib/rapidjson/include/rapidjson/writer.h" #include "lib/rapidjson/include/rapidjson/stringbuffer.h" @@ -45,7 +46,7 @@ public: virtual ~any_impl() = default; virtual boost::string_view name() const noexcept = 0; - virtual void parse(boost::string_view s) = 0; + virtual void work(boost::string_view s) = 0; }; //---------------------------------------------------------- @@ -58,30 +59,46 @@ struct boost_impl : public any_impl return "Boost.JSON"; } - void - parse(boost::string_view s) override + static + std::string + to_string( + json::value const& jv, + std::size_t size_hint) { - json::parser p; - boost::system::error_code ec; - p.write(s.data(), s.size(), ec); - } -}; - -//---------------------------------------------------------- - -struct nlohmann_impl : public any_impl -{ - boost::string_view - name() const noexcept override - { - return "nlohmann"; + std::string s; + std::size_t len = 0; + s.resize(size_hint); + json::serializer p(jv); + for(;;) + { + auto const used = p.next( + &s[len], s.size() - len); + len += used; + s.resize(len); + if(p.is_done()) + break; + s.resize((len * 3) / 2); + } + return s; } void - parse(boost::string_view s) override + work(boost::string_view s) override { - auto jv = nlohmann::json::parse( - s.begin(), s.end()); + std::string s2; + { + json::parser p; + boost::system::error_code ec; + p.write(s.data(), s.size(), ec); + s2 = to_string(p.get(), s.size() * 2); + dout << "s2.size() == " << s2.size() << std::endl; + } + { + json::parser p; + boost::system::error_code ec; + p.write(s2.data(), s2.size(), ec); + dout << "ec.message() == " << ec.message() << std::endl; + } } }; @@ -96,10 +113,40 @@ struct rapidjson_impl : public any_impl } void - parse(boost::string_view s) override + work(boost::string_view s) override { - rapidjson::Document d; - d.Parse(s.data(), s.size()); + rapidjson::StringBuffer s2; + { + rapidjson::Document d; + d.Parse(s.data(), s.size()); + s2.Clear(); + rapidjson::Writer< + rapidjson::StringBuffer> wr(s2); + d.Accept(wr); + dout << "s2.GetSize() == " << s2.GetSize() << std::endl; + } + { + rapidjson::Document d; + d.Parse(s2.GetString(), s2.GetSize()); + } + } +}; + +//---------------------------------------------------------- + +struct nlohmann_impl : public any_impl +{ + boost::string_view + name() const noexcept override + { + return "nlohmann"; + } + + void + work(boost::string_view s) override + { + auto jv = nlohmann::json::parse( + s.begin(), s.end()); } }; @@ -334,7 +381,7 @@ benchParse( auto const when = clock_type::now(); dout << impl.name(); while(repeat--) - impl.parse(doc); + impl.work(doc); auto const elapsed = std::chrono::duration_cast< std::chrono::milliseconds>( @@ -361,11 +408,16 @@ load_file(char const* path) return s; } +void +study(); + int main( int const argc, char const* const* const argv) { + study(); + if(argc > 1) { std::vector vs; @@ -381,9 +433,9 @@ main( { v.clear(); #if 1 - v.emplace_back(new nlohmann_impl); - v.emplace_back(new nlohmann_impl); - v.emplace_back(new nlohmann_impl); + //v.emplace_back(new nlohmann_impl); + //v.emplace_back(new nlohmann_impl); + //v.emplace_back(new nlohmann_impl); v.emplace_back(new rapidjson_impl); v.emplace_back(new rapidjson_impl); v.emplace_back(new rapidjson_impl); @@ -394,7 +446,7 @@ main( dout << "File: " << argv[i + 1] << std::endl; for(auto& impl : v) - benchParse(vs[i], *impl, 100); + benchParse(vs[i], *impl, 1); dout << std::endl; } } @@ -432,3 +484,12 @@ main( return 0; } + +void +study() +{ + json::string_view js = "[\"\xFF""\"]"; + rapidjson::Document d; + d.Parse(js.data(), js.size()); +} + diff --git a/include/boost/json.hpp b/include/boost/json.hpp index b9fe8918..60a4b16a 100644 --- a/include/boost/json.hpp +++ b/include/boost/json.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/json/basic_parser.hpp b/include/boost/json/basic_parser.hpp index 53e67d99..3c3ad964 100644 --- a/include/boost/json/basic_parser.hpp +++ b/include/boost/json/basic_parser.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/boost/json/detail/buffer.hpp b/include/boost/json/detail/buffer.hpp index 95fe99c9..f48c3fc4 100644 --- a/include/boost/json/detail/buffer.hpp +++ b/include/boost/json/detail/buffer.hpp @@ -70,6 +70,15 @@ public: buf_[size_++] = ch; } + // returns true if cp is a valid utf-32 code point + static + bool + is_valid(unsigned long cp) noexcept + { + return cp <= 0x0010ffffu && + (cp < 0xd800u || cp > 0xdfffu); + } + // append valid 32-bit code point as utf8 void append_utf8( diff --git a/include/boost/json/detail/number.hpp b/include/boost/json/detail/math.hpp similarity index 97% rename from include/boost/json/detail/number.hpp rename to include/boost/json/detail/math.hpp index 3a3eb21b..c0210ec5 100644 --- a/include/boost/json/detail/number.hpp +++ b/include/boost/json/detail/math.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/vinniefalco/json // -#ifndef BOOST_JSON_DETAIL_NUMBER_HPP -#define BOOST_JSON_DETAIL_NUMBER_HPP +#ifndef BOOST_JSON_DETAIL_MATH_HPP +#define BOOST_JSON_DETAIL_MATH_HPP namespace boost { namespace json { diff --git a/include/boost/json/ieee_decimal.hpp b/include/boost/json/ieee_decimal.hpp new file mode 100644 index 00000000..9732682d --- /dev/null +++ b/include/boost/json/ieee_decimal.hpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/vinniefalco/json +// + +#ifndef BOOST_JSON_IEEE_DECIMAL_HPP +#define BOOST_JSON_IEEE_DECIMAL_HPP + +#include + +namespace boost { +namespace json { + +struct ieee_decimal +{ + unsigned long long mantissa; + short exponent; + bool sign; +}; + +BOOST_JSON_DECL +double +to_double(ieee_decimal const& dec) noexcept; + +} // json +} // boost + +#ifdef BOOST_JSON_HEADER_ONLY +#include +#endif + +#endif diff --git a/include/boost/json/impl/basic_parser.ipp b/include/boost/json/impl/basic_parser.ipp index f60a60a6..855839e6 100644 --- a/include/boost/json/impl/basic_parser.ipp +++ b/include/boost/json/impl/basic_parser.ipp @@ -1303,7 +1303,6 @@ write_eof(error_code& ec) ec = {}; } - } // json } // boost diff --git a/include/boost/json/impl/ieee_decimal.ipp b/include/boost/json/impl/ieee_decimal.ipp new file mode 100644 index 00000000..7fbd8e1e --- /dev/null +++ b/include/boost/json/impl/ieee_decimal.ipp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/vinniefalco/json +// + +#ifndef BOOST_JSON_IMPL_IEEE_DECIMAL_IPP +#define BOOST_JSON_IMPL_IEEE_DECIMAL_IPP + +#include + +namespace boost { +namespace json { + +namespace detail { + +} // detail + +/* +struct ieee_decimal +{ + unsigned long long mantissa; + short exponent; + bool sign; +}; +*/ + +double +to_double( + ieee_decimal const& dec) noexcept +{ + (void)dec; + return 0; +} + + +} // json +} // boost + +#ifdef BOOST_JSON_HEADER_ONLY +#include +#endif + +#endif diff --git a/include/boost/json/impl/number.ipp b/include/boost/json/impl/number.ipp index 7356f2fe..50b297b1 100644 --- a/include/boost/json/impl/number.ipp +++ b/include/boost/json/impl/number.ipp @@ -11,7 +11,7 @@ #define BOOST_JSON_IMPL_NUMBER_IPP #include -#include +#include #include #include #include @@ -32,6 +32,8 @@ namespace json { https://www.ampl.com/netlib/fp/dtoa.c https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + + https://kkimdev.github.io/posts/2018/06/15/IEEE-754-Floating-Point-Type-in-C++.html */ //---------------------------------------------------------- @@ -44,7 +46,7 @@ number:: number:: number() noexcept : sp_(default_storage()) - , k_(kind::type_int64) + , kind_(kind::type_int64) { int64_ = 0; } @@ -52,7 +54,7 @@ number() noexcept number:: number(storage_ptr sp) noexcept : sp_(std::move(sp)) - , k_(kind::type_int64) + , kind_(kind::type_int64) { int64_ = 0; } @@ -60,10 +62,10 @@ number(storage_ptr sp) noexcept number:: number(pilfered p) noexcept : sp_(std::move(p.get().sp_)) - , k_(p.get().k_) + , kind_(p.get().kind_) { auto& other = p.get(); - switch(k_) + switch(kind_) { default: case kind::type_double: @@ -83,9 +85,9 @@ number(pilfered p) noexcept number:: number(number const& other) : sp_(other.sp_) - , k_(other.k_) + , kind_(other.kind_) { - switch(k_) + switch(kind_) { default: case kind::type_double: @@ -107,9 +109,9 @@ number( number const& other, storage_ptr sp) : sp_(std::move(sp)) - , k_(other.k_) + , kind_(other.kind_) { - switch(k_) + switch(kind_) { default: case kind::type_double: @@ -129,9 +131,9 @@ number( number:: number(number&& other) : sp_(other.sp_) - , k_(other.k_) + , kind_(other.kind_) { - switch(k_) + switch(kind_) { default: case kind::type_double: @@ -153,9 +155,9 @@ number( number&& other, storage_ptr sp) : sp_(std::move(sp)) - , k_(other.k_) + , kind_(other.kind_) { - switch(k_) + switch(kind_) { default: case kind::type_double: @@ -176,8 +178,8 @@ number& number:: operator=(number const& other) { - k_ = other.k_; - switch(k_) + kind_ = other.kind_; + switch(kind_) { default: case kind::type_double: @@ -198,135 +200,71 @@ operator=(number const& other) //---------------------------------------------------------- number:: -number( - mantissa_type mant, - exponent_type exp, - bool sign) noexcept +number(ieee_decimal const& dec) noexcept { auto const as_double = [&] { - double d = static_cast< - double>(mant) * detail::pow10(exp); - if(sign) + double d; + if(dec.exponent >= 0) + d = static_cast< + double>(dec.mantissa) * + std::pow(10., dec.exponent); + else + d = static_cast< + double>(dec.mantissa) / + std::pow(10., -dec.exponent); + if(dec.sign) d *= -1; return d; }; - if(exp == 0) + if(dec.exponent == 0) { - if(! sign) + if(! dec.sign) { - assign_unsigned(mant); + assign_impl(dec.mantissa); } - else if(mant <= static_cast( + else if(dec.mantissa <= static_cast( (std::numeric_limits::max)()) + 1) { - assign_signed(static_cast(mant)); + assign_impl(static_cast< + long long>(dec.mantissa)); } else { - assign_double(as_double()); + assign_impl(as_double()); } } else { auto const d = as_double(); - if(! sign) + if(! dec.sign) { auto v = static_cast(d); if(v == d) - assign_unsigned(v); + assign_impl(v); else - assign_double(d); + assign_impl(d); } else { auto v = static_cast(d); if(v == d) - assign_signed(v); + assign_impl(v); else - assign_double(d); + assign_impl(d); } } } //---------------------------------------------------------- -number:: -number(short i) noexcept -{ - assign_signed(i); -} - -number:: -number(int i) noexcept -{ - assign_signed(i); -} - -number:: -number(long i) noexcept -{ - assign_signed(i); -} - -number:: -number(long long i) noexcept -{ - assign_signed(i); -} - -number:: -number(unsigned short i) noexcept -{ - assign_unsigned(i); -} - -number:: -number(unsigned int i) noexcept -{ - assign_unsigned(i); -} - -number:: -number(unsigned long i) noexcept -{ - assign_unsigned(i); -} - -number:: -number(unsigned long long i) noexcept -{ - assign_unsigned(i); -} - -number:: -number(float f) noexcept -{ - assign_double(f); -} - -number:: -number(double f) noexcept -{ - assign_double(f); -} - -number:: -number(long double f) noexcept -{ - assign_double(static_cast< - double>(f)); -} - -//---------------------------------------------------------- - bool number:: is_int64() const noexcept { - switch(k_) + switch(kind_) { default: case kind::type_int64: @@ -345,7 +283,7 @@ bool number:: is_uint64() const noexcept { - switch(k_) + switch(kind_) { default: case kind::type_int64: @@ -365,7 +303,7 @@ std::int_least64_t number:: get_int64() const noexcept { - switch(k_) + switch(kind_) { default: case kind::type_int64: @@ -385,7 +323,7 @@ std::uint_least64_t number:: get_uint64() const noexcept { - switch(k_) + switch(kind_) { default: case kind::type_int64: @@ -405,7 +343,7 @@ double number:: get_double() const noexcept { - switch(k_) + switch(kind_) { default: case kind::type_int64: @@ -426,7 +364,7 @@ print( std::size_t buf_size) const noexcept { int n; - switch(k_) + switch(kind_) { default: case kind::type_int64: @@ -449,32 +387,6 @@ print( //---------------------------------------------------------- -void -number:: -assign_signed(long long i) noexcept -{ - k_ = kind::type_int64; - int64_ = i; -} - -void -number:: -assign_unsigned(unsigned long long i) noexcept -{ - k_ = kind::type_uint64; - uint64_ = i; -} - -void -number:: -assign_double(double f) noexcept -{ - k_ = kind::type_double; - double_ = f; -} - -//---------------------------------------------------------- - std::ostream& operator<<(std::ostream& os, number const& n) { @@ -488,7 +400,7 @@ operator==( number const& lhs, number const& rhs) noexcept { - switch(lhs.k_) + switch(lhs.kind_) { default: case number::kind::type_int64: diff --git a/include/boost/json/impl/parser.ipp b/include/boost/json/impl/parser.ipp index e1bca832..289045b5 100644 --- a/include/boost/json/impl/parser.ipp +++ b/include/boost/json/impl/parser.ipp @@ -323,7 +323,7 @@ void parser:: on_number(ieee_decimal dec, error_code&) { - number n(dec.mantissa, dec.exponent, dec.sign); + number n(dec); auto& jv = *stack_.front(); BOOST_JSON_ASSERT(! jv.is_object()); if(obj_) @@ -359,6 +359,32 @@ on_null(error_code&) assign(nullptr); } +//---------------------------------------------------------- + +value +parse( + string_view s, + storage_ptr sp, + error_code& ec) +{ + parser p(std::move(sp)); + p.write(s.data(), s.size(), ec); + return p.release(); +} + +value +parse( + string_view s, + storage_ptr sp) +{ + error_code ec; + auto jv = parse(s, std::move(sp), ec); + if(ec) + BOOST_JSON_THROW( + system_error(ec)); + return jv; +} + } // json } // boost diff --git a/include/boost/json/impl/serializer.ipp b/include/boost/json/impl/serializer.ipp index d3307462..c3ba8da8 100644 --- a/include/boost/json/impl/serializer.ipp +++ b/include/boost/json/impl/serializer.ipp @@ -21,16 +21,10 @@ enum class serializer::state : char inc, // increment iterator val, // value - key1, // '"' - key2, // escaped string - key3, // '"' - key4, // ':' - key5, // literal (ctrl or utf16 escape) - str1, // '"' str2, // escaped string str3, // '"' - str4, // ',' + str4, // ':' or ',' str5, // literal (ctrl or utf16 escape) lit, // literal string ({number}, true, false, null) @@ -90,8 +84,9 @@ loop: } if(e.has_key) { - key_ = it_->key; - state_ = state::key1; + key_ = true; + str_ = it_->key; + state_ = state::str1; goto loop; } BOOST_FALLTHROUGH; @@ -118,6 +113,7 @@ loop: goto loop; case kind::string: + key_ = false; str_ = *e.value.if_string(); state_ = state::str1; goto loop; @@ -154,49 +150,6 @@ loop: //--- - case state::key1: - if(p >= p1) - goto finish; - *p++ = '\"'; - state_ = state::key2; - BOOST_FALLTHROUGH; - - case state::key2: - { - auto const n = - key_.copy(p, p1 - p); - p += n; - if(n < key_.size()) - { - BOOST_JSON_ASSERT(p >= p1); - key_ = key_.substr(n); - goto finish; - } - state_ = state::key3; - BOOST_FALLTHROUGH; - } - - case state::key3: - if(p >= p1) - goto finish; - *p++ = '\"'; - state_ = state::key4; - BOOST_FALLTHROUGH; - - case state::key4: - if(p >= p1) - goto finish; - *p++ = ':'; - state_ = state::val; - goto loop; - - case state::key5: - if(p >= p1) - goto finish; - break; - - //--- - case state::str1: if(p >= p1) goto finish; @@ -244,7 +197,8 @@ loop: state_ = state::str5; goto loop; } - else if(ch >= 32) + else if(static_cast< + unsigned char>(ch) >= 32) { *p++ = ch; continue; @@ -257,8 +211,12 @@ loop: buf_[4] = 'u'; buf_[3] = '0'; buf_[2] = '0'; - buf_[1] = "0123456789abcdef"[ch >> 4]; - buf_[0] = "0123456789abcdef"[ch & 15]; + static constexpr char hex[] = + "0123456789abcdef"; + buf_[1] = hex[static_cast< + unsigned char>(ch) >> 4]; + buf_[0] = hex[static_cast< + unsigned char>(ch) & 15]; nbuf_ = 6; state_ = state::str5; goto loop; @@ -278,7 +236,7 @@ loop: if(p >= p1) goto finish; *p++ = '\"'; - if(it_->last) + if(it_->last && ! key_) { state_ = state::inc; goto loop; @@ -289,8 +247,16 @@ loop: case state::str4: if(p >= p1) goto finish; - *p++ = ','; - state_ = state::inc; + if(key_) + { + *p++ = ':'; + state_ = state::val; + } + else + { + *p++ = ','; + state_ = state::inc; + } goto loop; case state::str5: @@ -329,6 +295,29 @@ finish: return p - p0; } +std::string +to_string( + json::value const& jv) +{ + std::string s; + std::size_t len = 0; + s.resize(1024); + json::serializer p(jv); + for(;;) + { + auto const used = p.next( + &s[len], s.size() - len); + len += used; + s.resize(len); + if(p.is_done()) + break; + s.resize((len * 3) / 2); + } + s.shrink_to_fit(); + return s; +} + + std::ostream& operator<<(std::ostream& os, value const& jv) { diff --git a/include/boost/json/number.hpp b/include/boost/json/number.hpp index c8a1f247..1d51bdf2 100644 --- a/include/boost/json/number.hpp +++ b/include/boost/json/number.hpp @@ -11,6 +11,7 @@ #define BOOST_JSON_NUMBER_HPP #include +#include #include #include #include @@ -21,12 +22,33 @@ namespace boost { namespace json { -struct ieee_decimal -{ - std::uint64_t mantissa; - short exponent; - bool sign; -}; +namespace detail { + +template +using remove_cv_t = typename + std::remove_cv::type; + +} // detail + +/** Metafunction returning `true` if a `T` can be assigned to @ref number +*/ +#ifdef GENERATING_DOCUMENTATION +template +using is_number = __see_below__; +#else +template +using is_number = + std::integral_constant::value && + ! std::is_same, + bool>::value && + ! std::is_same, + char>::value && + ! std::is_same, + wchar_t>::value && + ! std::is_same, + unsigned char>::value>; +#endif /** The representation of parsed numbers. */ @@ -45,14 +67,13 @@ class number // The XSLT has problems with private anon unions union { - unsigned - long long uint64_; - long long int64_; - double double_; + double double_; + long long int64_; + unsigned long long uint64_; }; #endif - kind k_; + kind kind_; public: static std::size_t constexpr @@ -68,12 +89,6 @@ public: #endif ; - using mantissa_type = - unsigned long long; - - using exponent_type = - short; - //------------------------------------------------------ BOOST_JSON_DECL @@ -114,54 +129,19 @@ public: /** Construct a number from mantissa, exponent, and sign */ BOOST_JSON_DECL - number( - mantissa_type mant, - exponent_type exp, - bool sign) noexcept; + explicit + number(ieee_decimal const& dec) noexcept; - /// Construct a number from a signed integer - BOOST_JSON_DECL - number(short v) noexcept; - - /// Construct a number from a signed integer - BOOST_JSON_DECL - number(int v) noexcept; - - /// Construct a number from a signed integer - BOOST_JSON_DECL - number(long v) noexcept; - - /// Construct a number from a signed integer - BOOST_JSON_DECL - number(long long v) noexcept; - - /// Construct a number from an unsigned integer - BOOST_JSON_DECL - number(unsigned short v) noexcept; - - /// Construct a number from an unsigned integer - BOOST_JSON_DECL - number(unsigned int v) noexcept; - - /// Construct a number from an unsigned integer - BOOST_JSON_DECL - number(unsigned long v) noexcept; - - /// Construct a number from an unsigned integer - BOOST_JSON_DECL - number(unsigned long long v) noexcept; - - /// Construct a number from a floating point value - BOOST_JSON_DECL - number(float v) noexcept; - - /// Construct a number from a floating point value - BOOST_JSON_DECL - number(double v) noexcept; - - /// Construct a number from a floating point value - BOOST_JSON_DECL - number(long double v) noexcept; + template::value>::type + #endif + > + number(T t) noexcept + { + assign_impl(t); + } storage_ptr const& get_storage() const noexcept @@ -226,21 +206,41 @@ public: std::size_t buf_size) const noexcept; private: - struct pow10; - - inline + template void - assign_signed( - long long i) noexcept; + assign_impl(T t, + typename std::enable_if< + std::is_unsigned< + T>::value>::type* = 0) noexcept + { + kind_ = kind::type_uint64; + uint64_ = t; + } - inline + template void - assign_unsigned( - unsigned long long i) noexcept; + assign_impl(T t, + typename std::enable_if< + std::is_signed::value && + std::is_integral::value + >::type* = 0) noexcept + { + kind_ = kind::type_int64; + int64_ = t; + } - inline + template void - assign_double(double f) noexcept; + assign_impl(T t, + typename std::enable_if< + ! std::is_integral< + T>::value>::type* = 0) noexcept + { + kind_ = kind::type_double; + // VFALCO silence warnings + // when `T` is `long double`. + double_ = static_cast(t); + } BOOST_JSON_DECL friend @@ -261,7 +261,6 @@ private: number const& lhs, number const& rhs) noexcept; - inline storage_ptr release_storage() noexcept diff --git a/include/boost/json/parser.hpp b/include/boost/json/parser.hpp index f34b6157..43ed1799 100644 --- a/include/boost/json/parser.hpp +++ b/include/boost/json/parser.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,39 @@ private: on_null(error_code&) override; }; +//---------------------------------------------------------- + +BOOST_JSON_DECL +value +parse( + string_view s, + storage_ptr sp, + error_code& ec); + +inline +value +parse( + string_view s, + error_code& ec) +{ + return parse(s, + default_storage(), ec); +} + +BOOST_JSON_DECL +value +parse( + string_view s, + storage_ptr sp); + +inline +value +parse(string_view s) +{ + return parse( + s, default_storage()); +} + } // json } // boost diff --git a/include/boost/json/serializer.hpp b/include/boost/json/serializer.hpp index ca98057e..01f8175e 100644 --- a/include/boost/json/serializer.hpp +++ b/include/boost/json/serializer.hpp @@ -25,9 +25,9 @@ class serializer enum class state : char; detail::const_iterator it_; - string_view key_; string_view str_; unsigned char nbuf_; + bool key_; char buf_[number::max_string_chars + 1]; state state_; @@ -45,6 +45,10 @@ public: next(char* dest, std::size_t size); }; +BOOST_JSON_DECL +std::string +to_string(value const& jv); + BOOST_JSON_DECL std::ostream& operator<<( diff --git a/include/boost/json/src.hpp b/include/boost/json/src.hpp index 4fe19100..af4d1820 100644 --- a/include/boost/json/src.hpp +++ b/include/boost/json/src.hpp @@ -26,6 +26,7 @@ the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined. #include #include #include +#include #include #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f01e68e6..3b6ba4df 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable (json-tests assign_vector.cpp basic_parser.cpp error.cpp + ieee_decimal.cpp json.cpp kind.cpp number.cpp diff --git a/test/Jamfile b/test/Jamfile index df95adbb..ee0a174e 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -31,6 +31,7 @@ local SOURCES = assign_vector.cpp basic_parser.cpp error.cpp + ieee_decimal.cpp json.cpp kind.cpp number.cpp diff --git a/test/ieee_decimal.cpp b/test/ieee_decimal.cpp new file mode 100644 index 00000000..2e0fd9bd --- /dev/null +++ b/test/ieee_decimal.cpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/vinniefalco/json +// + +// Test that header file is self-contained. +#include + +#include +#include + +namespace boost { +namespace json { + +class ieee_decimal_test : public beast::unit_test::suite +{ +public: + void run() override + { + pass(); + } +}; + +BEAST_DEFINE_TESTSUITE(boost,json,ieee_decimal); + +} // json +} // boost diff --git a/test/make-pvs.py b/test/make-pvs.py index e4f6967a..73e20940 100644 --- a/test/make-pvs.py +++ b/test/make-pvs.py @@ -19,7 +19,7 @@ def escape(c): n = ord(c); if n >= 32 and n <= 127: return c; - return chex(c); + return chex(c) + "\"\""; def tocpp(s): v0 = "" diff --git a/test/number.cpp b/test/number.cpp index 9df18247..961ca581 100644 --- a/test/number.cpp +++ b/test/number.cpp @@ -20,6 +20,23 @@ namespace json { class number_test : public beast::unit_test::suite { public: + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + BOOST_JSON_STATIC_ASSERT(is_number::value); + + BOOST_JSON_STATIC_ASSERT(! is_number::value); + BOOST_JSON_STATIC_ASSERT(! is_number::value); + BOOST_JSON_STATIC_ASSERT(! is_number::value); + BOOST_JSON_STATIC_ASSERT(! is_number::value); + template void check(I v @@ -49,9 +66,11 @@ public: n2 = n; BEAST_EXPECT(n == n2); BEAST_EXPECT(n.is_uint64()); +#if 0 BEAST_EXPECT(number(static_cast< - number::mantissa_type>(v), + decltype(ieee_decimal::mantissa)>(v), 0, false) == n); +#endif BEAST_EXPECT(n.get_uint64() == v); BEAST_EXPECT(n.get_double() == v); } diff --git a/test/parse-vectors.hpp b/test/parse-vectors.hpp index bd496a42..c1bec483 100644 --- a/test/parse-vectors.hpp +++ b/test/parse-vectors.hpp @@ -11,20 +11,17 @@ #ifndef PARSE_VECTORS #define PARSE_VECTORS -#include +#include #include #include -namespace boost { -namespace json { - struct parse_vectors { struct item { char result; - string_view name; - string_view text; + ::boost::string_view name; + ::boost::string_view text; }; using iterator = item const*; @@ -64,9 +61,6 @@ parse_vectors:: parse_vectors() noexcept { static item const list[] = { - { 'i', "number_huge_exp", lit("[0.4e006699999999999999999999999999999999999999999999999999999999999999999999999" - "99999999999999999999999999999999999999999999969999999006]") }, - { 'i', "number_double_huge_neg_exp", lit("[123.456e-789]") }, { 'i', "number_huge_exp", lit("[0.4e006699999999999999999999999999999999999999999999999999999999999999999999999" "99999999999999999999999999999999999999999999969999999006]") }, @@ -86,21 +80,21 @@ parse_vectors() noexcept { 'i', "string_incomplete_surrogate_pair", lit("[\"\\uDd1ea\"]") }, { 'i', "string_invalid_lonely_surrogate", lit("[\"\\ud800\"]") }, { 'i', "string_invalid_surrogate", lit("[\"\\ud800abc\"]") }, - { 'i', "string_invalid_utf-8", lit("[\"\xFF\"]") }, + { 'i', "string_invalid_utf-8", lit("[\"\xFF""\"]") }, { 'i', "string_inverted_surrogates_U+1D11E", lit("[\"\\uDd1e\\uD834\"]") }, - { 'i', "string_iso_latin_1", lit("[\"\xE9\"]") }, + { 'i', "string_iso_latin_1", lit("[\"\xE9""\"]") }, { 'i', "string_lone_second_surrogate", lit("[\"\\uDFAA\"]") }, - { 'i', "string_lone_utf8_continuation_byte", lit("[\"\x81\"]") }, - { 'i', "string_not_in_unicode_range", lit("[\"\xF4\xBF\xBF\xBF\"]") }, - { 'i', "string_overlong_sequence_2_bytes", lit("[\"\xC0\xAF\"]") }, - { 'i', "string_overlong_sequence_6_bytes", lit("[\"\xFC\x83\xBF\xBF\xBF\xBF\"]") }, - { 'i', "string_overlong_sequence_6_bytes_null", lit("[\"\xFC\x80\x80\x80\x80\x80\"]") }, - { 'i', "string_truncated-utf-8", lit("[\"\xE0\xFF\"]") }, - { 'i', "string_UTF-16LE_with_BOM", lit("\xFF\xFE[\x00\"\x00\xE9\x00\"\x00]\x00") }, - { 'i', "string_UTF-8_invalid_sequence", lit("[\"\xE6\x97\xA5\xD1\x88\xFA\"]") }, - { 'i', "string_utf16BE_no_BOM", lit("\x00[\x00\"\x00\xE9\x00\"\x00]") }, - { 'i', "string_utf16LE_no_BOM", lit("[\x00\"\x00\xE9\x00\"\x00]\x00") }, - { 'i', "string_UTF8_surrogate_U+D800", lit("[\"\xED\xA0\x80\"]") }, + { 'i', "string_lone_utf8_continuation_byte", lit("[\"\x81""\"]") }, + { 'i', "string_not_in_unicode_range", lit("[\"\xF4""\xBF""\xBF""\xBF""\"]") }, + { 'i', "string_overlong_sequence_2_bytes", lit("[\"\xC0""\xAF""\"]") }, + { 'i', "string_overlong_sequence_6_bytes", lit("[\"\xFC""\x83""\xBF""\xBF""\xBF""\xBF""\"]") }, + { 'i', "string_overlong_sequence_6_bytes_null", lit("[\"\xFC""\x80""\x80""\x80""\x80""\x80""\"]") }, + { 'i', "string_truncated-utf-8", lit("[\"\xE0""\xFF""\"]") }, + { 'i', "string_UTF-16LE_with_BOM", lit("\xFF""\xFE""[\x00""\"\x00""\xE9""\x00""\"\x00""]\x00""") }, + { 'i', "string_UTF-8_invalid_sequence", lit("[\"\xE6""\x97""\xA5""\xD1""\x88""\xFA""\"]") }, + { 'i', "string_utf16BE_no_BOM", lit("\x00""[\x00""\"\x00""\xE9""\x00""\"\x00""]") }, + { 'i', "string_utf16LE_no_BOM", lit("[\x00""\"\x00""\xE9""\x00""\"\x00""]\x00""") }, + { 'i', "string_UTF8_surrogate_U+D800", lit("[\"\xED""\xA0""\x80""\"]") }, { 'i', "structure_500_nested_arrays", lit("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[" "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[" "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[" @@ -114,9 +108,9 @@ parse_vectors() noexcept "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]") }, - { 'i', "structure_UTF-8_BOM_empty_object", lit("\xEF\xBB\xBF{}") }, + { 'i', "structure_UTF-8_BOM_empty_object", lit("\xEF""\xBB""\xBF""{}") }, { 'n', "array_1_true_without_comma", lit("[1 true]") }, - { 'n', "array_a_invalid_utf8", lit("[a\xE5]") }, + { 'n', "array_a_invalid_utf8", lit("[a\xE5""]") }, { 'n', "array_colon_instead_of_comma", lit("[\"\": 1]") }, { 'n', "array_comma_after_close", lit("[\"\"],") }, { 'n', "array_comma_and_number", lit("[,1]") }, @@ -127,24 +121,55 @@ parse_vectors() noexcept { 'n', "array_incomplete", lit("[\"x\"") }, { 'n', "array_incomplete_invalid_value", lit("[x") }, { 'n', "array_inner_array_no_comma", lit("[3[4]]") }, - { 'n', "array_invalid_utf8", lit("[\xFF]") }, + { 'n', "array_invalid_utf8", lit("[\xFF""]") }, { 'n', "array_items_separated_by_semicolon", lit("[1:2]") }, { 'n', "array_just_comma", lit("[,]") }, { 'n', "array_just_minus", lit("[-]") }, { 'n', "array_missing_value", lit("[ , \"\"]") }, - { 'n', "array_newlines_unclosed", lit("[\"a\",\x0A4\x0A,1,") }, + { 'n', "array_newlines_unclosed", lit("[\"a\",\x0A""4\x0A"",1,") }, { 'n', "array_number_and_comma", lit("[1,]") }, { 'n', "array_number_and_several_commas", lit("[1,,]") }, - { 'n', "array_spaces_vertical_tab_formfeed", lit("[\"\x0Ba\"\\f]") }, + { 'n', "array_spaces_vertical_tab_formfeed", lit("[\"\x0B""a\"\\f]") }, { 'n', "array_star_inside", lit("[*]") }, { 'n', "array_unclosed", lit("[\"\"") }, { 'n', "array_unclosed_trailing_comma", lit("[1,") }, - { 'n', "array_unclosed_with_new_lines", lit("[1,\x0A1\x0A,1") }, + { 'n', "array_unclosed_with_new_lines", lit("[1,\x0A""1\x0A"",1") }, { 'n', "array_unclosed_with_object_inside", lit("[{}") }, + { 'n', "fail01", lit("[\"mismatch\"}") }, + { 'n', "fail02", lit("[\"Unclosed array\"") }, + { 'n', "fail03", lit("{unquoted_key: \"keys must be quoted\"}") }, + { 'n', "fail04", lit("[\"extra comma\",]") }, + { 'n', "fail05", lit("[\"double extra comma\",,]") }, + { 'n', "fail06", lit("[ , \"<-- missing value\"]") }, + { 'n', "fail07", lit("[\"Comma after the close\"],") }, + { 'n', "fail08", lit("[\"Extra close\"]]") }, + { 'n', "fail09", lit("{\"Extra comma\": true,}") }, + { 'n', "fail10", lit("{\"Extra value after close\": true} \"misplaced quoted value\"") }, + { 'n', "fail11", lit("{\"Illegal expression\": 1 + 2}") }, + { 'n', "fail12", lit("{\"Illegal invocation\": alert()}") }, + { 'n', "fail13", lit("{\"Numbers cannot have leading zeroes\": 013}") }, + { 'n', "fail14", lit("{\"Numbers cannot be hex\": 0x14}") }, + { 'n', "fail15", lit("[\"Illegal backslash escape: \\x15\"]") }, + { 'n', "fail16", lit("[\\naked]") }, + { 'n', "fail17", lit("[\"Illegal backslash escape: \\017\"]") }, + { 'n', "fail19", lit("{\"Missing colon\" null}") }, + { 'n', "fail20", lit("{\"Double colon\":: null}") }, + { 'n', "fail21", lit("{\"Comma instead of colon\", null}") }, + { 'n', "fail22", lit("[\"Colon instead of comma\": false]") }, + { 'n', "fail23", lit("[\"Bad value\", truth]") }, + { 'n', "fail24", lit("['single quote']") }, + { 'n', "fail25", lit("[\" tab character in string \"]") }, + { 'n', "fail26", lit("[\"tab\\ character\\ in\\ string\\ \"]") }, + { 'n', "fail27", lit("[\"line\x0A""break\"]") }, + { 'n', "fail28", lit("[\"line\\\x0A""break\"]") }, + { 'n', "fail29", lit("[0e]") }, + { 'n', "fail30", lit("[0e+]") }, + { 'n', "fail31", lit("[0e+-1]") }, + { 'n', "fail32", lit("{\"Comma instead if closing brace\": true,") }, { 'n', "incomplete_false", lit("[fals]") }, { 'n', "incomplete_null", lit("[nul]") }, { 'n', "incomplete_true", lit("[tru]") }, - { 'n', "multidigit_number_then_00", lit("123\x00") }, + { 'n', "multidigit_number_then_00", lit("123\x00""") }, { 'n', "number_++", lit("[++1234]") }, { 'n', "number_+1", lit("[+1]") }, { 'n', "number_+Inf", lit("[+Inf]") }, @@ -178,9 +203,9 @@ parse_vectors() noexcept { 'n', "number_infinity", lit("[Infinity]") }, { 'n', "number_invalid+-", lit("[0e+-1]") }, { 'n', "number_invalid-negative-real", lit("[-123.123foo]") }, - { 'n', "number_invalid-utf-8-in-bigger-int", lit("[123\xE5]") }, - { 'n', "number_invalid-utf-8-in-exponent", lit("[1e1\xE5]") }, - { 'n', "number_invalid-utf-8-in-int", lit("[0\xE5]\x0A") }, + { 'n', "number_invalid-utf-8-in-bigger-int", lit("[123\xE5""]") }, + { 'n', "number_invalid-utf-8-in-exponent", lit("[1e1\xE5""]") }, + { 'n', "number_invalid-utf-8-in-int", lit("[0\xE5""]\x0A""") }, { 'n', "number_minus_infinity", lit("[-Infinity]") }, { 'n', "number_minus_sign_with_trailing_garbage", lit("[-foo]") }, { 'n', "number_minus_space_1", lit("[- 1]") }, @@ -190,20 +215,20 @@ parse_vectors() noexcept { 'n', "number_neg_with_garbage_at_end", lit("[-1x]") }, { 'n', "number_real_garbage_after_e", lit("[1ea]") }, { 'n', "number_real_without_fractional_part", lit("[1.]") }, - { 'n', "number_real_with_invalid_utf8_after_e", lit("[1e\xE5]") }, + { 'n', "number_real_with_invalid_utf8_after_e", lit("[1e\xE5""]") }, { 'n', "number_starting_with_dot", lit("[.123]") }, - { 'n', "number_U+FF11_fullwidth_digit_one", lit("[\xEF\xBC\x91]") }, + { 'n', "number_U+FF11_fullwidth_digit_one", lit("[\xEF""\xBC""\x91""]") }, { 'n', "number_with_alpha", lit("[1.2a-3]") }, { 'n', "number_with_alpha_char", lit("[1.8011670033376514H-308]") }, { 'n', "number_with_leading_zero", lit("[012]") }, { 'n', "object_bad_value", lit("[\"x\", truth]") }, - { 'n', "object_bracket_key", lit("{[: \"x\"}\x0A") }, + { 'n', "object_bracket_key", lit("{[: \"x\"}\x0A""") }, { 'n', "object_comma_instead_of_colon", lit("{\"x\", null}") }, { 'n', "object_double_colon", lit("{\"x\"::\"b\"}") }, - { 'n', "object_emoji", lit("{\xF0\x9F\x87\xA8\xF0\x9F\x87\xAD}") }, + { 'n', "object_emoji", lit("{\xF0""\x9F""\x87""\xA8""\xF0""\x9F""\x87""\xAD""}") }, { 'n', "object_garbage_at_end", lit("{\"a\":\"a\" 123}") }, { 'n', "object_key_with_single_quotes", lit("{key: 'value'}") }, - { 'n', "object_lone_continuation_byte_in_key_and_trailing_comma", lit("{\"\xB9\":\"0\",}") }, + { 'n', "object_lone_continuation_byte_in_key_and_trailing_comma", lit("{\"\xB9""\":\"0\",}") }, { 'n', "object_missing_colon", lit("{\"a\" b}") }, { 'n', "object_missing_key", lit("{:\"b\"}") }, { 'n', "object_missing_semicolon", lit("{\"a\" \"b\"}") }, @@ -229,28 +254,28 @@ parse_vectors() noexcept { 'n', "string_1_surrogate_then_escape_u", lit("[\"\\uD800\\u\"]") }, { 'n', "string_1_surrogate_then_escape_u1", lit("[\"\\uD800\\u1\"]") }, { 'n', "string_1_surrogate_then_escape_u1x", lit("[\"\\uD800\\u1x\"]") }, - { 'n', "string_accentuated_char_no_quotes", lit("[\xC3\xA9]") }, - { 'n', "string_backslash_00", lit("[\"\\\x00\"]") }, + { 'n', "string_accentuated_char_no_quotes", lit("[\xC3""\xA9""]") }, + { 'n', "string_backslash_00", lit("[\"\\\x00""\"]") }, { 'n', "string_escaped_backslash_bad", lit("[\"\\\\\\\"]") }, { 'n', "string_escaped_ctrl_char_tab", lit("[\"\\ \"]") }, - { 'n', "string_escaped_emoji", lit("[\"\\\xF0\x9F\x8C\x80\"]") }, + { 'n', "string_escaped_emoji", lit("[\"\\\xF0""\x9F""\x8C""\x80""\"]") }, { 'n', "string_escape_x", lit("[\"\\x00\"]") }, { 'n', "string_incomplete_escape", lit("[\"\\\"]") }, { 'n', "string_incomplete_escaped_character", lit("[\"\\u00A\"]") }, { 'n', "string_incomplete_surrogate", lit("[\"\\uD834\\uDd\"]") }, { 'n', "string_incomplete_surrogate_escape_invalid", lit("[\"\\uD800\\uD800\\x\"]") }, - { 'n', "string_invalid-utf-8-in-escape", lit("[\"\\u\xE5\"]") }, + { 'n', "string_invalid-utf-8-in-escape", lit("[\"\\u\xE5""\"]") }, { 'n', "string_invalid_backslash_esc", lit("[\"\\a\"]") }, { 'n', "string_invalid_unicode_escape", lit("[\"\\uqqqq\"]") }, - { 'n', "string_invalid_utf8_after_escape", lit("[\"\\\xE5\"]") }, + { 'n', "string_invalid_utf8_after_escape", lit("[\"\\\xE5""\"]") }, { 'n', "string_leading_uescaped_thinspace", lit("[\\u0020\"asd\"]") }, { 'n', "string_no_quotes_with_bad_escape", lit("[\\n]") }, { 'n', "string_single_doublequote", lit("\"") }, { 'n', "string_single_quote", lit("['single quote']") }, { 'n', "string_single_string_no_double_quotes", lit("abc") }, { 'n', "string_start_escape_unclosed", lit("[\"\\") }, - { 'n', "string_unescaped_crtl_char", lit("[\"a\x00a\"]") }, - { 'n', "string_unescaped_newline", lit("[\"new\x0Aline\"]") }, + { 'n', "string_unescaped_crtl_char", lit("[\"a\x00""a\"]") }, + { 'n', "string_unescaped_newline", lit("[\"new\x0A""line\"]") }, { 'n', "string_unescaped_tab", lit("[\" \"]") }, { 'n', "string_unicode_CapitalU", lit("\"\\UA66D\"") }, { 'n', "string_with_trailing_garbage", lit("\"\"x") }, @@ -766,17 +791,17 @@ parse_vectors() noexcept { 'n', "structure_array_trailing_garbage", lit("[1]x") }, { 'n', "structure_array_with_extra_array_close", lit("[1]]") }, { 'n', "structure_array_with_unclosed_string", lit("[\"asd]") }, - { 'n', "structure_ascii-unicode-identifier", lit("a\xC3\xA5") }, + { 'n', "structure_ascii-unicode-identifier", lit("a\xC3""\xA5""") }, { 'n', "structure_capitalized_True", lit("[True]") }, { 'n', "structure_close_unopened_array", lit("1]") }, { 'n', "structure_comma_instead_of_closing_brace", lit("{\"x\": true,") }, { 'n', "structure_double_array", lit("[][]") }, { 'n', "structure_end_array", lit("]") }, - { 'n', "structure_incomplete_UTF8_BOM", lit("\xEF\xBB{}") }, - { 'n', "structure_lone-invalid-utf-8", lit("\xE5") }, + { 'n', "structure_incomplete_UTF8_BOM", lit("\xEF""\xBB""{}") }, + { 'n', "structure_lone-invalid-utf-8", lit("\xE5""") }, { 'n', "structure_lone-open-bracket", lit("[") }, { 'n', "structure_no_data", lit("") }, - { 'n', "structure_null-byte-outside-string", lit("[\x00]") }, + { 'n', "structure_null-byte-outside-string", lit("[\x00""]") }, { 'n', "structure_number_with_trailing_garbage", lit("2@") }, { 'n', "structure_object_followed_by_closing_object", lit("{}}") }, { 'n', "structure_object_unclosed_no_value", lit("{\"\":") }, @@ -1297,20 +1322,20 @@ parse_vectors() noexcept { 'n', "structure_open_object_open_string", lit("{\"a") }, { 'n', "structure_open_object_string_with_apostrophes", lit("{'a'") }, { 'n', "structure_open_open", lit("[\"\\{[\"\\{[\"\\{[\"\\{") }, - { 'n', "structure_single_eacute", lit("\xE9") }, + { 'n', "structure_single_eacute", lit("\xE9""") }, { 'n', "structure_single_star", lit("*") }, { 'n', "structure_trailing_#", lit("{\"a\":\"b\"}#{}") }, - { 'n', "structure_U+2060_word_joined", lit("[\xE2\x81\xA0]") }, + { 'n', "structure_U+2060_word_joined", lit("[\xE2""\x81""\xA0""]") }, { 'n', "structure_uescaped_LF_before_string", lit("[\\u000A\"\"]") }, { 'n', "structure_unclosed_array", lit("[1") }, { 'n', "structure_unclosed_array_partial_null", lit("[ false, nul") }, { 'n', "structure_unclosed_array_unfinished_false", lit("[ true, fals") }, { 'n', "structure_unclosed_array_unfinished_true", lit("[ false, tru") }, { 'n', "structure_unclosed_object", lit("{\"asd\":\"asd\"") }, - { 'n', "structure_unicode-identifier", lit("\xC3\xA5") }, - { 'n', "structure_UTF8_BOM_no_data", lit("\xEF\xBB\xBF") }, - { 'n', "structure_whitespace_formfeed", lit("[\x0C]") }, - { 'n', "structure_whitespace_U+2060_word_joiner", lit("[\xE2\x81\xA0]") }, + { 'n', "structure_unicode-identifier", lit("\xC3""\xA5""") }, + { 'n', "structure_UTF8_BOM_no_data", lit("\xEF""\xBB""\xBF""") }, + { 'n', "structure_whitespace_formfeed", lit("[\x0C""]") }, + { 'n', "structure_whitespace_U+2060_word_joiner", lit("[\xE2""\x81""\xA0""]") }, { 'y', "array_arraysWithSpaces", lit("[[] ]") }, { 'y', "array_empty-string", lit("[\"\"]") }, { 'y', "array_empty", lit("[]") }, @@ -1318,7 +1343,7 @@ parse_vectors() noexcept { 'y', "array_false", lit("[false]") }, { 'y', "array_heterogeneous", lit("[null, 1, \"1\", {}]") }, { 'y', "array_null", lit("[null]") }, - { 'y', "array_with_1_and_newline", lit("[1\x0A]") }, + { 'y', "array_with_1_and_newline", lit("[1\x0A""]") }, { 'y', "array_with_leading_space", lit(" [1]") }, { 'y', "array_with_several_null", lit("[1,null,null,null,2]") }, { 'y', "array_with_trailing_space", lit("[2] ") }, @@ -1327,7 +1352,7 @@ parse_vectors() noexcept { 'y', "number_0e1", lit("[0e1]") }, { 'y', "number_after_space", lit("[ 4]") }, { 'y', "number_double_close_to_zero", lit("[-0.0000000000000000000000000000000000000000000000000000000000000000000000000000" - "01]\x0A") }, + "01]\x0A""") }, { 'y', "number_int_with_exp", lit("[20e1]") }, { 'y', "number_minus_zero", lit("[-0]") }, { 'y', "number_negative_int", lit("[-123]") }, @@ -1355,7 +1380,35 @@ parse_vectors() noexcept { 'y', "object_simple", lit("{\"a\":[]}") }, { 'y', "object_string_unicode", lit("{\"title\":\"\\u041f\\u043e\\u043b\\u0442\\u043e\\u0440\\u0430 \\u0417\\u0435\\u" "043c\\u043b\\u0435\\u043a\\u043e\\u043f\\u0430\" }") }, - { 'y', "object_with_newlines", lit("{\x0A\"a\": \"b\"\x0A}") }, + { 'y', "object_with_newlines", lit("{\x0A""\"a\": \"b\"\x0A""}") }, + { 'y', "pass01", lit("[\x0A"" \"JSON Test Pattern pass1\",\x0A"" {\"object with 1 member\":[\"ar" + "ray with 1 element\"]},\x0A"" {},\x0A"" [],\x0A"" -42,\x0A"" true,\x0A""" + " false,\x0A"" null,\x0A"" {\x0A"" \"integer\": 1234567890,\x0A"" " + " \"real\": -9876.543210,\x0A"" \"e\": 0.123456789e-12,\x0A"" " + "\"E\": 1.234567890E+34,\x0A"" \"\": 23456789012E66,\x0A"" \"zero\"" + ": 0,\x0A"" \"one\": 1,\x0A"" \"space\": \" \",\x0A"" \"quote" + "\": \"\\\"\",\x0A"" \"backslash\": \"\\\\\",\x0A"" \"controls\": \"" + "\\b\\f\\n\\r\\t\",\x0A"" \"slash\": \"/ & \\/\",\x0A"" \"alpha\": \"" + "abcdefghijklmnopqrstuvwyz\",\x0A"" \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\"" + ",\x0A"" \"digit\": \"0123456789\",\x0A"" \"0123456789\": \"digit\"," + "\x0A"" \"special\": \"`1~!@#$%^&*()_+-={':[,]}|;.?\",\x0A"" \"he" + "x\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",\x0A"" \"true\": true," + "\x0A"" \"false\": false,\x0A"" \"null\": null,\x0A"" \"array" + "\":[ ],\x0A"" \"object\":{ },\x0A"" \"address\": \"50 St. James S" + "treet\",\x0A"" \"url\": \"http://www.JSON.org/\",\x0A"" \"comment\"" + ": \"// /* */\": \" \",\x0A"" \" s p a c" + " e d \" :[1,2 , 3\x0A""\x0A"",\x0A""\x0A""4 , 5 , 6 ,7 " + " ],\"compact\":[1,2,3,4,5,6,7],\x0A"" \"jsontext\": \"{\\\"object wi" + "th 1 member\\\":[\\\"array with 1 element\\\"]}\",\x0A"" \"quotes\": \"" + "4; \\u0022 %22 0x22 034 "\",\x0A"" \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98" + "\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\"\x0A"": \"A " + "key can be any string\"\x0A"" },\x0A"" 0.5 ,98.6\x0A"",\x0A""99.44\x0A"",\x0A""" + "\x0A""1066,\x0A""1e1,\x0A""0.1e1,\x0A""1e-1,\x0A""1e00,2e+00,2e-00\x0A"",\"rosebu" + "d\"]") }, + { 'y', "pass02", lit("[[[[[[[[[[[[[[[[[[[\"Not too deep\"]]]]]]]]]]]]]]]]]]]") }, + { 'y', "pass03", lit("{\x0A"" \"JSON Test Pattern pass3\": {\x0A"" \"The outermost value\": " + "\"must be an object or array.\",\x0A"" \"In this test\": \"It is an object" + ".\"\x0A"" }\x0A""}\x0A""") }, { 'y', "string_1_2_3_bytes_UTF-8_sequences", lit("[\"\\u0060\\u012a\\u12AB\"]") }, { 'y', "string_accepted_surrogate_pair", lit("[\"\\uD801\\udc37\"]") }, { 'y', "string_accepted_surrogate_pairs", lit("[\"\\ud83d\\ude39\\ud83d\\udc8d\"]") }, @@ -1371,25 +1424,25 @@ parse_vectors() noexcept { 'y', "string_in_array_with_leading_space", lit("[ \"asd\"]") }, { 'y', "string_last_surrogates_1_and_2", lit("[\"\\uDBFF\\uDFFF\"]") }, { 'y', "string_nbsp_uescaped", lit("[\"new\\u00A0line\"]") }, - { 'y', "string_nonCharacterInUTF-8_U+10FFFF", lit("[\"\xF4\x8F\xBF\xBF\"]") }, - { 'y', "string_nonCharacterInUTF-8_U+FFFF", lit("[\"\xEF\xBF\xBF\"]") }, + { 'y', "string_nonCharacterInUTF-8_U+10FFFF", lit("[\"\xF4""\x8F""\xBF""\xBF""\"]") }, + { 'y', "string_nonCharacterInUTF-8_U+FFFF", lit("[\"\xEF""\xBF""\xBF""\"]") }, { 'y', "string_null_escape", lit("[\"\\u0000\"]") }, { 'y', "string_one-byte-utf-8", lit("[\"\\u002c\"]") }, - { 'y', "string_pi", lit("[\"\xCF\x80\"]") }, - { 'y', "string_reservedCharacterInUTF-8_U+1BFFF", lit("[\"\xF0\x9B\xBF\xBF\"]") }, + { 'y', "string_pi", lit("[\"\xCF""\x80""\"]") }, + { 'y', "string_reservedCharacterInUTF-8_U+1BFFF", lit("[\"\xF0""\x9B""\xBF""\xBF""\"]") }, { 'y', "string_simple_ascii", lit("[\"asd \"]") }, { 'y', "string_space", lit("\" \"") }, { 'y', "string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF", lit("[\"\\uD834\\uDd1e\"]") }, { 'y', "string_three-byte-utf-8", lit("[\"\\u0821\"]") }, { 'y', "string_two-byte-utf-8", lit("[\"\\u0123\"]") }, - { 'y', "string_u+2028_line_sep", lit("[\"\xE2\x80\xA8\"]") }, - { 'y', "string_u+2029_par_sep", lit("[\"\xE2\x80\xA9\"]") }, + { 'y', "string_u+2028_line_sep", lit("[\"\xE2""\x80""\xA8""\"]") }, + { 'y', "string_u+2029_par_sep", lit("[\"\xE2""\x80""\xA9""\"]") }, { 'y', "string_uEscape", lit("[\"\\u0061\\u30af\\u30EA\\u30b9\"]") }, { 'y', "string_uescaped_newline", lit("[\"new\\u000Aline\"]") }, { 'y', "string_unescaped_char_delete", lit("[\"\"]") }, { 'y', "string_unicode", lit("[\"\\uA66D\"]") }, { 'y', "string_unicodeEscapedBackslash", lit("[\"\\u005C\"]") }, - { 'y', "string_unicode_2", lit("[\"\xE2\x8D\x82\xE3\x88\xB4\xE2\x8D\x82\"]") }, + { 'y', "string_unicode_2", lit("[\"\xE2""\x8D""\x82""\xE3""\x88""\xB4""\xE2""\x8D""\x82""\"]") }, { 'y', "string_unicode_escaped_double_quote", lit("[\"\\u0022\"]") }, { 'y', "string_unicode_U+10FFFE_nonchar", lit("[\"\\uDBFF\\uDFFE\"]") }, { 'y', "string_unicode_U+1FFFE_nonchar", lit("[\"\\uD83F\\uDFFE\"]") }, @@ -1397,7 +1450,7 @@ parse_vectors() noexcept { 'y', "string_unicode_U+2064_invisible_plus", lit("[\"\\u2064\"]") }, { 'y', "string_unicode_U+FDD0_nonchar", lit("[\"\\uFDD0\"]") }, { 'y', "string_unicode_U+FFFE_nonchar", lit("[\"\\uFFFE\"]") }, - { 'y', "string_utf8", lit("[\"\xE2\x82\xAC\xF0\x9D\x84\x9E\"]") }, + { 'y', "string_utf8", lit("[\"\xE2""\x82""\xAC""\xF0""\x9D""\x84""\x9E""\"]") }, { 'y', "string_with_del_character", lit("[\"aa\"]") }, { 'y', "structure_lonely_false", lit("false") }, { 'y', "structure_lonely_int", lit("42") }, @@ -1406,7 +1459,7 @@ parse_vectors() noexcept { 'y', "structure_lonely_string", lit("\"asd\"") }, { 'y', "structure_lonely_true", lit("true") }, { 'y', "structure_string_empty", lit("\"\"") }, - { 'y', "structure_trailing_newline", lit("[\"a\"]\x0A") }, + { 'y', "structure_trailing_newline", lit("[\"a\"]\x0A""") }, { 'y', "structure_true_in_array", lit("[true]") }, { 'y', "structure_whitespace_array", lit(" [] ") }, { ' ', "", "" } @@ -1416,7 +1469,4 @@ parse_vectors() noexcept decltype(list)>::value - 1]; } -} // json -} // boost - #endif diff --git a/test/parse-vectors/n_fail01.json b/test/parse-vectors/n_fail01.json new file mode 100644 index 00000000..ca5eb19d --- /dev/null +++ b/test/parse-vectors/n_fail01.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/test/parse-vectors/n_fail02.json b/test/parse-vectors/n_fail02.json new file mode 100644 index 00000000..6b7c11e5 --- /dev/null +++ b/test/parse-vectors/n_fail02.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/test/parse-vectors/n_fail03.json b/test/parse-vectors/n_fail03.json new file mode 100644 index 00000000..168c81eb --- /dev/null +++ b/test/parse-vectors/n_fail03.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/test/parse-vectors/n_fail04.json b/test/parse-vectors/n_fail04.json new file mode 100644 index 00000000..9de168bf --- /dev/null +++ b/test/parse-vectors/n_fail04.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/test/parse-vectors/n_fail05.json b/test/parse-vectors/n_fail05.json new file mode 100644 index 00000000..ddf3ce3d --- /dev/null +++ b/test/parse-vectors/n_fail05.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/test/parse-vectors/n_fail06.json b/test/parse-vectors/n_fail06.json new file mode 100644 index 00000000..ed91580e --- /dev/null +++ b/test/parse-vectors/n_fail06.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/test/parse-vectors/n_fail07.json b/test/parse-vectors/n_fail07.json new file mode 100644 index 00000000..8a96af3e --- /dev/null +++ b/test/parse-vectors/n_fail07.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/test/parse-vectors/n_fail08.json b/test/parse-vectors/n_fail08.json new file mode 100644 index 00000000..b28479c6 --- /dev/null +++ b/test/parse-vectors/n_fail08.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/test/parse-vectors/n_fail09.json b/test/parse-vectors/n_fail09.json new file mode 100644 index 00000000..5815574f --- /dev/null +++ b/test/parse-vectors/n_fail09.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/test/parse-vectors/n_fail10.json b/test/parse-vectors/n_fail10.json new file mode 100644 index 00000000..5d8c0047 --- /dev/null +++ b/test/parse-vectors/n_fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/test/parse-vectors/n_fail11.json b/test/parse-vectors/n_fail11.json new file mode 100644 index 00000000..76eb95b4 --- /dev/null +++ b/test/parse-vectors/n_fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/test/parse-vectors/n_fail12.json b/test/parse-vectors/n_fail12.json new file mode 100644 index 00000000..77580a45 --- /dev/null +++ b/test/parse-vectors/n_fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/test/parse-vectors/n_fail13.json b/test/parse-vectors/n_fail13.json new file mode 100644 index 00000000..379406b5 --- /dev/null +++ b/test/parse-vectors/n_fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/test/parse-vectors/n_fail14.json b/test/parse-vectors/n_fail14.json new file mode 100644 index 00000000..0ed366b3 --- /dev/null +++ b/test/parse-vectors/n_fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/test/parse-vectors/n_fail15.json b/test/parse-vectors/n_fail15.json new file mode 100644 index 00000000..fc8376b6 --- /dev/null +++ b/test/parse-vectors/n_fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/test/parse-vectors/n_fail16.json b/test/parse-vectors/n_fail16.json new file mode 100644 index 00000000..3fe21d4b --- /dev/null +++ b/test/parse-vectors/n_fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/test/parse-vectors/n_fail17.json b/test/parse-vectors/n_fail17.json new file mode 100644 index 00000000..62b9214a --- /dev/null +++ b/test/parse-vectors/n_fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/test/parse-vectors/n_fail19.json b/test/parse-vectors/n_fail19.json new file mode 100644 index 00000000..3b9c46fa --- /dev/null +++ b/test/parse-vectors/n_fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/test/parse-vectors/n_fail20.json b/test/parse-vectors/n_fail20.json new file mode 100644 index 00000000..27c1af3e --- /dev/null +++ b/test/parse-vectors/n_fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/test/parse-vectors/n_fail21.json b/test/parse-vectors/n_fail21.json new file mode 100644 index 00000000..62474573 --- /dev/null +++ b/test/parse-vectors/n_fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/test/parse-vectors/n_fail22.json b/test/parse-vectors/n_fail22.json new file mode 100644 index 00000000..a7752581 --- /dev/null +++ b/test/parse-vectors/n_fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/test/parse-vectors/n_fail23.json b/test/parse-vectors/n_fail23.json new file mode 100644 index 00000000..494add1c --- /dev/null +++ b/test/parse-vectors/n_fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/test/parse-vectors/n_fail24.json b/test/parse-vectors/n_fail24.json new file mode 100644 index 00000000..caff239b --- /dev/null +++ b/test/parse-vectors/n_fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/test/parse-vectors/n_fail25.json b/test/parse-vectors/n_fail25.json new file mode 100644 index 00000000..8b7ad23e --- /dev/null +++ b/test/parse-vectors/n_fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/test/parse-vectors/n_fail26.json b/test/parse-vectors/n_fail26.json new file mode 100644 index 00000000..845d26a6 --- /dev/null +++ b/test/parse-vectors/n_fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/test/parse-vectors/n_fail27.json b/test/parse-vectors/n_fail27.json new file mode 100644 index 00000000..6b01a2ca --- /dev/null +++ b/test/parse-vectors/n_fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/test/parse-vectors/n_fail28.json b/test/parse-vectors/n_fail28.json new file mode 100644 index 00000000..621a0101 --- /dev/null +++ b/test/parse-vectors/n_fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/test/parse-vectors/n_fail29.json b/test/parse-vectors/n_fail29.json new file mode 100644 index 00000000..47ec421b --- /dev/null +++ b/test/parse-vectors/n_fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/test/parse-vectors/n_fail30.json b/test/parse-vectors/n_fail30.json new file mode 100644 index 00000000..8ab0bc4b --- /dev/null +++ b/test/parse-vectors/n_fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/test/parse-vectors/n_fail31.json b/test/parse-vectors/n_fail31.json new file mode 100644 index 00000000..1cce602b --- /dev/null +++ b/test/parse-vectors/n_fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/test/parse-vectors/n_fail32.json b/test/parse-vectors/n_fail32.json new file mode 100644 index 00000000..45cba739 --- /dev/null +++ b/test/parse-vectors/n_fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/test/parse-vectors/y_pass01.json b/test/parse-vectors/y_pass01.json new file mode 100644 index 00000000..70e26854 --- /dev/null +++ b/test/parse-vectors/y_pass01.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/test/parse-vectors/y_pass02.json b/test/parse-vectors/y_pass02.json new file mode 100644 index 00000000..d3c63c7a --- /dev/null +++ b/test/parse-vectors/y_pass02.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/test/parse-vectors/y_pass03.json b/test/parse-vectors/y_pass03.json new file mode 100644 index 00000000..4528d51f --- /dev/null +++ b/test/parse-vectors/y_pass03.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/test/parser.cpp b/test/parser.cpp index 25a4edd2..e35a8631 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -67,6 +67,51 @@ R"xx({ } } + void + testParse() + { + auto const check = + [&](json::value const& jv) + { + BEAST_EXPECT(jv.is_object()); + BEAST_EXPECT(jv.as_object().find( + "a")->second.is_bool()); + BEAST_EXPECT(jv.as_object().find( + "b")->second.is_number()); + BEAST_EXPECT(jv.as_object().find( + "c")->second.is_string()); + }; + + string_view js = + "{\"a\":true,\"b\":1,\"c\":\"x\"}"; + + // parse(value) + { + check(parse(js)); + } + + // parse(value, storage_ptr) + { + check(parse(js, default_storage())); + } + + // parse(value, error_code) + { + error_code ec; + auto jv = parse(js, ec); + BEAST_EXPECTS(! ec, ec.message()); + check(jv); + } + + // parse(value, storage_ptr, error_code) + { + error_code ec; + auto jv = parse(js, default_storage(), ec); + BEAST_EXPECTS(! ec, ec.message()); + check(jv); + } + } + void run() { @@ -74,6 +119,7 @@ R"xx({ "sizeof(parser) == " << sizeof(parser) << "\n"; testParser(); + testParse(); } }; diff --git a/test/serializer.cpp b/test/serializer.cpp index d39ba9a7..3b13bb83 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -14,7 +14,7 @@ #include #include "parse-vectors.hpp" -//#define SOFT_FAIL +#define SOFT_FAIL namespace boost { namespace json { @@ -23,43 +23,32 @@ class serializer_test : public beast::unit_test::suite { public: static - std::string - to_string(value const& jv) + unsigned + common( + string_view s1, + string_view s2) { - std::string s; - unsigned long cap = 1024; - for(;;) + unsigned n = 0; + auto p1 = s1.data(); + auto p2 = s2.data(); + auto end = s1.size() > s2.size() ? + s2.end() : s1.end(); + while(p1 < end) { - s.resize(cap); - serializer p(jv); - s.resize(p.next( - &s[0], s.size())); - if(p.is_done()) + ++n; + if(*p1++ != *p2++) break; - cap *= 2; } - return s; - } - - static - value - from_string( - string_view s, - error_code& ec) - { - parser p; - p.write( - s.data(), - s.size(), - ec); - return p.release(); + return n; } void - round_trip(string_view s0) + round_trip( + string_view name, + string_view s0) { error_code ec; - auto jv0 = from_string(s0, ec); + auto jv0 = parse(s0, ec); #ifdef SOFT_FAIL if(ec) return; @@ -69,7 +58,10 @@ public: return; #endif auto s1 = to_string(jv0); - auto jv1 = from_string(s1, ec); + parser p; + auto n = p.write( + s1.data(), s1.size(), ec); + auto jv1 = p.release(); #ifdef SOFT_FAIL if(ec) #else @@ -77,7 +69,15 @@ public: ! ec, ec.message())) #endif { + auto c1 = s1.data() + n; + if( n > 60) + n = 60; + auto c0 = c1 - n; log << + "context\n" + " " << string_view(c0, c1-c0) << std::endl; + log << + name << "\n" " " << s0 << "\n" " " << s1 << std::endl << std::endl; return; @@ -88,18 +88,24 @@ public: #else if(! BEAST_EXPECT(s1 == s2)) #endif + { + auto c = common(s1, s2); log << - " " << s1 << "\n" - " " << s2 << std::endl << std::endl; + name << "\n" + " " << s0 << "\n" + " " << s1.substr(0, c) << "\n" + " " << s2.substr(0, c) << std::endl << std::endl; + } } void print_grind( + string_view name, json::value const& jv) { auto const s0 = to_string(jv); log << s0 << std::endl; - round_trip(s0); + round_trip(name, s0); for(std::size_t i = 1; i < s0.size() - 1; ++i) { @@ -120,6 +126,34 @@ public: } } + void + testSerializer() + { + value jv; + + // serializer(value) + { + serializer sr(jv); + } + + // is_done() + { + serializer sr(jv); + BEAST_EXPECT(! sr.is_done()); + } + + // next() + { + serializer sr(jv); + char buf[1024]; + auto n = sr.next( + buf, sizeof(buf)); + BEAST_EXPECT(sr.is_done()); + BEAST_EXPECT(string_view( + buf, n) == "null"); + } + } + void testRoundTrips() { @@ -129,41 +163,7 @@ public: if(e.result != 'y') continue; - round_trip(e.text); -#if 0 - error_code ec; - std::string s1, s2; - { - auto jv = from_string( - e.text, ec); - if(! BEAST_EXPECTS( - ! ec, ec.message())) - continue; - s1 = to_string(jv); - } - { - auto jv = - from_string(s1, ec); - if(! BEAST_EXPECTS( - ! ec, ec.message())) - { - log << - " " << e.text << "\n" << - " " << s1 << "\n" << - std::endl << std::endl; - continue; - } - s2 = to_string(jv); - } - if(! BEAST_EXPECT(s1 == s2)) - if(s1 != s2) - { - log << - " " << s1 << "\n" << - " " << s2 << "\n" << - std::endl << std::endl; - } -#endif + round_trip(e.name, e.text); } } @@ -171,7 +171,7 @@ public: good(string_view s) { error_code ec; - auto jv = from_string(s, ec); + auto jv = parse(s, ec); return !ec; } @@ -179,11 +179,13 @@ public: void tv(char const (&s)[N]) { - round_trip(string_view(s, N - 1)); + round_trip( + "", + string_view(s, N - 1)); } void - run() + doTestStrings() { tv(R"("")"); tv(R"("x")"); @@ -237,19 +239,34 @@ public: tv(R"(false)"); tv(R"(null)"); + } -#if 0 + void + doTestVectors() + { parse_vectors const pv; for(auto const e : pv) { if( e.result == 'y' || good(e.text)) { - log << e.name << std::endl; - round_trip(e.text); + round_trip(e.name, e.text); } } -#endif + } + + void + run() + { + parse_vectors const pv; + auto jv = parse(pv.begin()->text); + auto s = to_string(jv); + error_code ec; + auto jv2 = parse(s, ec); + BEAST_EXPECTS(! ec, ec.message()); + testSerializer(); + doTestStrings(); + doTestVectors(); } }; diff --git a/test/value.cpp b/test/value.cpp index d9cdd809..999bf6c6 100644 --- a/test/value.cpp +++ b/test/value.cpp @@ -703,6 +703,7 @@ public: } // kind::number +#if 0 { // VFALCO I'm not sure these should be numbers BEAST_EXPECT(value(tt{}).is_number()); @@ -713,6 +714,7 @@ public: { value jv; BEAST_EXPECT((jv = tt{}).is_number()); } { value jv; BEAST_EXPECT((jv = tt{}).is_number()); } } +#endif // kind::number {