serializer work

This commit is contained in:
Vinnie Falco 2019-10-24 10:41:32 -07:00
parent b1e03f7326
commit dd8dd9929f
58 changed files with 831 additions and 448 deletions

View File

@ -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<std::string> 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());
}

View File

@ -16,6 +16,7 @@
#include <boost/json/basic_parser.hpp>
#include <boost/json/error.hpp>
#include <boost/json/fixed_storage.hpp>
#include <boost/json/ieee_decimal.hpp>
#include <boost/json/kind.hpp>
#include <boost/json/number.hpp>
#include <boost/json/object.hpp>

View File

@ -12,7 +12,7 @@
#include <boost/json/detail/config.hpp>
#include <boost/json/error.hpp>
#include <boost/json/number.hpp>
#include <boost/json/ieee_decimal.hpp>
#include <boost/json/detail/basic_parser.hpp>
#include <boost/json/detail/stack.hpp>
#include <boost/json/detail/string.hpp>

View File

@ -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(

View File

@ -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 {

View File

@ -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 <boost/json/detail/config.hpp>
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 <boost/json/impl/ieee_decimal.ipp>
#endif
#endif

View File

@ -1303,7 +1303,6 @@ write_eof(error_code& ec)
ec = {};
}
} // json
} // boost

View File

@ -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 <boost/json/detail/config.hpp>
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 <boost/json/impl/ieee_decimal.ipp>
#endif
#endif

View File

@ -11,7 +11,7 @@
#define BOOST_JSON_IMPL_NUMBER_IPP
#include <boost/json/number.hpp>
#include <boost/json/detail/number.hpp>
#include <boost/json/detail/math.hpp>
#include <algorithm>
#include <cmath>
#include <cstdint>
@ -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<number> 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<number> 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<unsigned long long>(
else if(dec.mantissa <= static_cast<unsigned long long>(
(std::numeric_limits<long long>::max)()) + 1)
{
assign_signed(static_cast<long long>(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<unsigned long long>(d);
if(v == d)
assign_unsigned(v);
assign_impl(v);
else
assign_double(d);
assign_impl(d);
}
else
{
auto v = static_cast<long long>(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:

View File

@ -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

View File

@ -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)
{

View File

@ -11,6 +11,7 @@
#define BOOST_JSON_NUMBER_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/ieee_decimal.hpp>
#include <boost/json/storage.hpp>
#include <boost/json/detail/string.hpp>
#include <boost/pilfer.hpp>
@ -21,12 +22,33 @@
namespace boost {
namespace json {
struct ieee_decimal
{
std::uint64_t mantissa;
short exponent;
bool sign;
};
namespace detail {
template<class T>
using remove_cv_t = typename
std::remove_cv<T>::type;
} // detail
/** Metafunction returning `true` if a `T` can be assigned to @ref number
*/
#ifdef GENERATING_DOCUMENTATION
template<class T>
using is_number = __see_below__;
#else
template<class T>
using is_number =
std::integral_constant<bool,
std::is_arithmetic<T>::value &&
! std::is_same<detail::remove_cv_t<T>,
bool>::value &&
! std::is_same<detail::remove_cv_t<T>,
char>::value &&
! std::is_same<detail::remove_cv_t<T>,
wchar_t>::value &&
! std::is_same<detail::remove_cv_t<T>,
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<class T
#ifndef GENERATING_DOCUMENTATION
,class = typename std::enable_if<
is_number<T>::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<class T>
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<class T>
void
assign_unsigned(
unsigned long long i) noexcept;
assign_impl(T t,
typename std::enable_if<
std::is_signed<T>::value &&
std::is_integral<T>::value
>::type* = 0) noexcept
{
kind_ = kind::type_int64;
int64_ = t;
}
inline
template<class T>
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<double>(t);
}
BOOST_JSON_DECL
friend
@ -261,7 +261,6 @@ private:
number const& lhs,
number const& rhs) noexcept;
inline
storage_ptr
release_storage() noexcept

View File

@ -14,6 +14,7 @@
#include <boost/json/basic_parser.hpp>
#include <boost/json/storage.hpp>
#include <boost/json/value.hpp>
#include <boost/json/storage.hpp>
#include <boost/json/detail/string.hpp>
#include <new>
#include <string>
@ -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

View File

@ -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<<(

View File

@ -26,6 +26,7 @@ the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined.
#include <boost/json/impl/array.ipp>
#include <boost/json/impl/basic_parser.ipp>
#include <boost/json/impl/error.ipp>
#include <boost/json/impl/ieee_decimal.ipp>
#include <boost/json/impl/number.ipp>
#include <boost/json/impl/object.ipp>
#include <boost/json/impl/parser.ipp>

View File

@ -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

View File

@ -31,6 +31,7 @@ local SOURCES =
assign_vector.cpp
basic_parser.cpp
error.cpp
ieee_decimal.cpp
json.cpp
kind.cpp
number.cpp

31
test/ieee_decimal.cpp Normal file
View File

@ -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 <boost/json/ieee_decimal.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <type_traits>
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

View File

@ -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 = ""

View File

@ -20,6 +20,23 @@ namespace json {
class number_test : public beast::unit_test::suite
{
public:
BOOST_JSON_STATIC_ASSERT(is_number<int>::value);
BOOST_JSON_STATIC_ASSERT(is_number<short>::value);
BOOST_JSON_STATIC_ASSERT(is_number<long>::value);
BOOST_JSON_STATIC_ASSERT(is_number<long long>::value);
BOOST_JSON_STATIC_ASSERT(is_number<unsigned int>::value);
BOOST_JSON_STATIC_ASSERT(is_number<unsigned short>::value);
BOOST_JSON_STATIC_ASSERT(is_number<unsigned long>::value);
BOOST_JSON_STATIC_ASSERT(is_number<unsigned long long>::value);
BOOST_JSON_STATIC_ASSERT(is_number<float>::value);
BOOST_JSON_STATIC_ASSERT(is_number<double>::value);
BOOST_JSON_STATIC_ASSERT(is_number<long double>::value);
BOOST_JSON_STATIC_ASSERT(! is_number<char>::value);
BOOST_JSON_STATIC_ASSERT(! is_number<wchar_t>::value);
BOOST_JSON_STATIC_ASSERT(! is_number<unsigned char>::value);
BOOST_JSON_STATIC_ASSERT(! is_number<bool>::value);
template<class I>
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);
}

View File

@ -11,20 +11,17 @@
#ifndef PARSE_VECTORS
#define PARSE_VECTORS
#include <boost/json/detail/string.hpp>
#include <boost/utility/string_view.hpp>
#include <cstdlib>
#include <type_traits>
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"" \"# -- --> */\": \" \",\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\": \"&#3"
"4; \\u0022 %22 0x22 034 &#x22;\",\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

View File

@ -0,0 +1 @@
["mismatch"}

View File

@ -0,0 +1 @@
["Unclosed array"

View File

@ -0,0 +1 @@
{unquoted_key: "keys must be quoted"}

View File

@ -0,0 +1 @@
["extra comma",]

View File

@ -0,0 +1 @@
["double extra comma",,]

View File

@ -0,0 +1 @@
[ , "<-- missing value"]

View File

@ -0,0 +1 @@
["Comma after the close"],

View File

@ -0,0 +1 @@
["Extra close"]]

View File

@ -0,0 +1 @@
{"Extra comma": true,}

View File

@ -0,0 +1 @@
{"Extra value after close": true} "misplaced quoted value"

View File

@ -0,0 +1 @@
{"Illegal expression": 1 + 2}

View File

@ -0,0 +1 @@
{"Illegal invocation": alert()}

View File

@ -0,0 +1 @@
{"Numbers cannot have leading zeroes": 013}

View File

@ -0,0 +1 @@
{"Numbers cannot be hex": 0x14}

View File

@ -0,0 +1 @@
["Illegal backslash escape: \x15"]

View File

@ -0,0 +1 @@
[\naked]

View File

@ -0,0 +1 @@
["Illegal backslash escape: \017"]

View File

@ -0,0 +1 @@
{"Missing colon" null}

View File

@ -0,0 +1 @@
{"Double colon":: null}

View File

@ -0,0 +1 @@
{"Comma instead of colon", null}

View File

@ -0,0 +1 @@
["Colon instead of comma": false]

View File

@ -0,0 +1 @@
["Bad value", truth]

View File

@ -0,0 +1 @@
['single quote']

View File

@ -0,0 +1 @@
[" tab character in string "]

View File

@ -0,0 +1 @@
["tab\ character\ in\ string\ "]

View File

@ -0,0 +1,2 @@
["line
break"]

View File

@ -0,0 +1,2 @@
["line\
break"]

View File

@ -0,0 +1 @@
[0e]

View File

@ -0,0 +1 @@
[0e+]

View File

@ -0,0 +1 @@
[0e+-1]

View File

@ -0,0 +1 @@
{"Comma instead if closing brace": true,

View File

@ -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": "&#34; \u0022 %22 0x22 034 &#x22;",
"\/\\\"\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"]

View File

@ -0,0 +1 @@
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]

View File

@ -0,0 +1,6 @@
{
"JSON Test Pattern pass3": {
"The outermost value": "must be an object or array.",
"In this test": "It is an object."
}
}

View File

@ -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();
}
};

View File

@ -14,7 +14,7 @@
#include <boost/beast/_experimental/unit_test/suite.hpp>
#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();
}
};

View File

@ -703,6 +703,7 @@ public:
}
// kind::number
#if 0
{
// VFALCO I'm not sure these should be numbers
BEAST_EXPECT(value(tt<char>{}).is_number());
@ -713,6 +714,7 @@ public:
{ value jv; BEAST_EXPECT((jv = tt<unsigned char>{}).is_number()); }
{ value jv; BEAST_EXPECT((jv = tt<wchar_t>{}).is_number()); }
}
#endif
// kind::number
{