This commit is contained in:
Luca Passarella 2023-02-06 08:51:11 -08:00 committed by GitHub
commit ff29547a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 2322 additions and 1425 deletions

View File

@ -237,6 +237,23 @@ class out_of_range : public exception
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
};
/// @brief exception indicating other library errors
/// @sa https://json.nlohmann.me/api/basic_json/other_error/
class not_implemented : public exception
{
public:
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static not_implemented create(int id_, const std::string& what_arg, BasicJsonContext context)
{
std::string w = concat(exception::name("not_implemented", id_), exception::diagnostics(context), what_arg);
return {id_, w.c_str()};
}
private:
JSON_HEDLEY_NON_NULL(3)
not_implemented(int id_, const char* what_arg) : exception(id_, what_arg) {}
};
/// @brief exception indicating other library errors
/// @sa https://json.nlohmann.me/api/basic_json/other_error/
class other_error : public exception

View File

@ -1183,7 +1183,7 @@ class binary_reader
}
}
return sax->end_object();
return true;
}
/////////////
@ -1349,7 +1349,11 @@ class binary_reader
case 0x8D:
case 0x8E:
case 0x8F:
return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
{
const auto len = conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu);
return sax->start_object(len) && get_msgpack_object(len) && sax->end_object();
}
// fixarray
case 0x90:
@ -1368,7 +1372,16 @@ class binary_reader
case 0x9D:
case 0x9E:
case 0x9F:
return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
{
const auto len = conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu);
return JSON_HEDLEY_LIKELY(
sax->start_array(len)
&&
get_msgpack_array(len)
&&
sax->end_array()
);
}
// fixstr
case 0xA0:
@ -1499,25 +1512,58 @@ class binary_reader
case 0xDC: // array 16
{
std::uint16_t len{};
return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
return JSON_HEDLEY_LIKELY(
get_number(input_format_t::msgpack, len)
&&
sax->start_array(static_cast<std::size_t>(len))
&&
get_msgpack_array(static_cast<std::size_t>(len))
&&
sax->end_array()
);
}
case 0xDD: // array 32
{
std::uint32_t len{};
return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
return JSON_HEDLEY_LIKELY(
get_number(input_format_t::msgpack, len)
&&
sax->start_array(conditional_static_cast<std::size_t>(len))
&&
get_msgpack_array(conditional_static_cast<std::size_t>(len))
&&
sax->end_array()
);
}
case 0xDE: // map 16
{
std::uint16_t len{};
return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
return JSON_HEDLEY_LIKELY(
get_number(input_format_t::msgpack, len)
&&
sax->start_object(len)
&&
get_msgpack_object(static_cast<std::size_t>(len))
&&
sax->end_object()
);
}
case 0xDF: // map 32
{
std::uint32_t len{};
return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
return JSON_HEDLEY_LIKELY(
get_number(input_format_t::msgpack, len)
&&
sax->start_object(len)
&&
get_msgpack_object(conditional_static_cast<std::size_t>(len))
&&
sax->end_object()
);
}
// negative fixint
@ -1770,11 +1816,6 @@ class binary_reader
*/
bool get_msgpack_array(const std::size_t len)
{
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
{
return false;
}
for (std::size_t i = 0; i < len; ++i)
{
if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
@ -1783,7 +1824,7 @@ class binary_reader
}
}
return sax->end_array();
return true;
}
/*!
@ -1792,28 +1833,438 @@ class binary_reader
*/
bool get_msgpack_object(const std::size_t len)
{
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
{
return false;
}
string_t key;
string_t recycle_string;
for (std::size_t i = 0; i < len; ++i)
{
get();
if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
if (JSON_HEDLEY_UNLIKELY(
!(
get_msgpack_object_key(recycle_string, detail::is_sax_msgpack<SAX, BasicJsonType>())
&&
parse_msgpack_internal()
)
)
)
{
return false;
}
if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
{
return false;
}
key.clear();
recycle_string.clear();
}
return true;
}
return sax->end_object();
// /*!
// @param[in] len the length of the object
// @param[in] full_msgpack_support is full msgpack protocoll suppored by sax
// @return whether object creation completed
// */
bool get_msgpack_object_key(string_t& recycle_string, std::false_type)
{
get();
return JSON_HEDLEY_LIKELY(get_msgpack_string(recycle_string) && sax->key(recycle_string));
}
// /*!
// @param[in] len the length of the object
// @param[in] full_msgpack_support is full msgpack protocoll suppored by sax
// @return whether object creation completed
// */
bool get_msgpack_object_key(string_t& recycle_string, std::true_type)
{
switch (get())
{
// EOF
case std::char_traits<char_type>::eof():
{
return unexpect_eof(input_format_t::msgpack, "key");
}
// positive fixint
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
case 0x2E:
case 0x2F:
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x38:
case 0x39:
case 0x3A:
case 0x3B:
case 0x3C:
case 0x3D:
case 0x3E:
case 0x3F:
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47:
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
case 0x4C:
case 0x4D:
case 0x4E:
case 0x4F:
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x58:
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5E:
case 0x5F:
case 0x60:
case 0x61:
case 0x62:
case 0x63:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
case 0x68:
case 0x69:
case 0x6A:
case 0x6B:
case 0x6C:
case 0x6D:
case 0x6E:
case 0x6F:
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x78:
case 0x79:
case 0x7A:
case 0x7B:
case 0x7C:
case 0x7D:
case 0x7E:
case 0x7F:
return JSON_HEDLEY_LIKELY(sax->key_unsigned(static_cast<number_unsigned_t>(current) ) );
// fixmap
case 0x80:
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
case 0x88:
case 0x89:
case 0x8A:
case 0x8B:
case 0x8C:
case 0x8D:
case 0x8E:
case 0x8F:
{
const auto len = static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu);
return JSON_HEDLEY_LIKELY( sax->start_key_object(len) && get_msgpack_object() && sax->end_key_object() );
}
// fixarray
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97:
case 0x98:
case 0x99:
case 0x9A:
case 0x9B:
case 0x9C:
case 0x9D:
case 0x9E:
case 0x9F:
{
const auto len = static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu);
return sax->start_key_array(len) && get_msgpack_array(len) && sax->end_key_array();
}
// fixstr
case 0xA0:
case 0xA1:
case 0xA2:
case 0xA3:
case 0xA4:
case 0xA5:
case 0xA6:
case 0xA7:
case 0xA8:
case 0xA9:
case 0xAA:
case 0xAB:
case 0xAC:
case 0xAD:
case 0xAE:
case 0xAF:
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF:
case 0xD9: // str 8
case 0xDA: // str 16
case 0xDB: // str 32
{
return JSON_HEDLEY_LIKELY( get_msgpack_string(recycle_string) && sax->key(recycle_string) );
}
case 0xC0: // nil
return JSON_HEDLEY_LIKELY( sax->key_null() );
case 0xC2: // false
return JSON_HEDLEY_LIKELY( sax->key_boolean(false) );
case 0xC3: // true
return JSON_HEDLEY_LIKELY( sax->key_boolean(true) );
case 0xC4: // bin 8
case 0xC5: // bin 16
case 0xC6: // bin 32
case 0xC7: // ext 8
case 0xC8: // ext 16
case 0xC9: // ext 32
case 0xD4: // fixext 1
case 0xD5: // fixext 2
case 0xD6: // fixext 4
case 0xD7: // fixext 8
case 0xD8: // fixext 16
{
binary_t b;
return get_msgpack_binary(b) && sax->key_binary(b);
}
case 0xCA: // float 32
{
float number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_float(static_cast<number_float_t>(number), "") );
}
case 0xCB: // float 64
{
double number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_float(static_cast<number_float_t>(number), "") );
}
case 0xCC: // uint 8
{
std::uint8_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_unsigned(number) );
}
case 0xCD: // uint 16
{
std::uint16_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_unsigned(number) );
}
case 0xCE: // uint 32
{
std::uint32_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_unsigned(number) );
}
case 0xCF: // uint 64
{
std::uint64_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_unsigned(number) );
}
case 0xD0: // int 8
{
std::int8_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_integer(number) );
}
case 0xD1: // int 16
{
std::int16_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_integer(number) );
}
case 0xD2: // int 32
{
std::int32_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_integer(number) );
}
case 0xD3: // int 64
{
std::int64_t number{};
return JSON_HEDLEY_LIKELY( get_number(input_format_t::msgpack, number) && sax->key_integer(number) );
}
case 0xDC: // array 16
{
std::uint16_t len{};
return get_number(input_format_t::msgpack, len) && sax->start_key_array(static_cast<std::size_t>(len)) && get_msgpack_array(static_cast<std::size_t>(len)) && sax->end_key_array();
}
case 0xDD: // array 32
{
std::uint32_t len{};
return get_number(input_format_t::msgpack, len) && sax->start_key_array(static_cast<std::size_t>(len)) && get_msgpack_array(static_cast<std::size_t>(len)) && sax->end_key_array();
}
case 0xDE: // map 16
{
std::uint16_t len{};
return JSON_HEDLEY_LIKELY(
get_number(input_format_t::msgpack, len)
&&
sax->start_key_object(len)
&&
get_msgpack_object()
&&
sax->end_key_object()
);
}
case 0xDF: // map 32
{
std::uint32_t len{};
return JSON_HEDLEY_LIKELY(
get_number(input_format_t::msgpack, len)
&&
sax->start_key_object(len)
&&
get_msgpack_object()
&&
sax->end_key_object()
);
}
// negative fixint
case 0xE0:
case 0xE1:
case 0xE2:
case 0xE3:
case 0xE4:
case 0xE5:
case 0xE6:
case 0xE7:
case 0xE8:
case 0xE9:
case 0xEA:
case 0xEB:
case 0xEC:
case 0xED:
case 0xEE:
case 0xEF:
case 0xF0:
case 0xF1:
case 0xF2:
case 0xF3:
case 0xF4:
case 0xF5:
case 0xF6:
case 0xF7:
case 0xF8:
case 0xF9:
case 0xFA:
case 0xFB:
case 0xFC:
case 0xFD:
case 0xFE:
case 0xFF:
return JSON_HEDLEY_LIKELY( sax->key_integer( static_cast<std::int8_t>(current) ) );
default: // anything else
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
exception_message(input_format_t::msgpack, concat("unsupported byte: 0x", last_token), "key"), nullptr));
}
}
}
////////////

View File

@ -28,8 +28,9 @@ boolean return value informs the parser whether to continue processing the
input.
*/
template<typename BasicJsonType>
struct json_sax
class json_sax
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
@ -142,6 +143,87 @@ struct json_sax
virtual ~json_sax() = default;
};
template<typename BasicJsonType>
class msgpack_sax : public json_sax<BasicJsonType>
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
/*!
@brief an object key of null value was read
@return whether parsing should proceed
*/
virtual bool key_null() = 0;
/*!
@brief an object key of type bool was read
@return whether parsing should proceed
*/
virtual bool key_boolean(bool val) = 0;
/*!
@brief an object key of type integer number was read
@return whether parsing should proceed
*/
virtual bool key_integer(number_integer_t val) = 0;
/*!
@brief an object key of type unsigned was read
@return whether parsing should proceed
*/
virtual bool key_unsigned(number_unsigned_t val) = 0;
/*!
@brief an object key of type float was read
@return whether parsing should proceed
*/
virtual bool key_float(number_float_t val, const string_t& s) = 0;
/*!
@brief an object key of type binary was read
@param[in] val binary value
@return whether parsing should proceed
@note It is safe to move the passed binary value.
*/
virtual bool key_binary(binary_t& val) = 0;
/*!
@brief the beginning of a key of type array was read
@param[in] elements number of array elements or -1 if unknown
@return whether parsing should proceed
@note binary formats may report the number of elements
*/
virtual bool start_key_array(std::size_t elements) = 0;
/*!
@brief the end of a key of type array was read
@return whether parsing should proceed
*/
virtual bool end_key_array() = 0;
/*!
@brief the beginning of a key of type object was read
@param[in] elements number of object elements or -1 if unknown
@return whether parsing should proceed
@note binary formats may report the number of elements
*/
virtual bool start_key_object(std::size_t elements) = 0;
/*!
@brief the end of a key of type object was read
@return whether parsing should proceed
*/
virtual bool end_key_object() = 0;
};
namespace detail
{
@ -158,8 +240,59 @@ constructor contains the parsed value.
@tparam BasicJsonType the JSON type
*/
template<typename BasicJsonType>
class json_sax_dom_parser
class json_sax_exception_handler : public json_sax<BasicJsonType>
{
protected:
/// whether a syntax error occurred
bool errored = false;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
explicit json_sax_exception_handler(const bool allow_exceptions_)
: errored{false}, allow_exceptions{allow_exceptions_}
{}
template<class Exception>
bool handle_throw_exception(const Exception& ex)
{
errored = true;
static_cast<void>(ex);
if (allow_exceptions)
{
JSON_THROW(ex);
}
return false;
}
virtual bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& ex) override
{
return handle_throw_exception(ex);
}
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex)
{
return handle_throw_exception(ex);
}
constexpr bool is_errored() const
{
return errored;
}
};
template<typename BasicJsonType>
class json_sax_dom_parser : public json_sax_exception_handler<BasicJsonType>
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@ -174,7 +307,7 @@ class json_sax_dom_parser
@param[in] allow_exceptions_ whether parse errors yield exceptions
*/
explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
: root(r), allow_exceptions(allow_exceptions_)
: root(r), json_sax_exception_handler<BasicJsonType>(allow_exceptions_)
{}
// make class move-only
@ -184,49 +317,49 @@ class json_sax_dom_parser
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~json_sax_dom_parser() = default;
bool null()
bool null() override
{
handle_value(nullptr);
return true;
}
bool boolean(bool val)
bool boolean(bool val) override
{
handle_value(val);
return true;
}
bool number_integer(number_integer_t val)
bool number_integer(number_integer_t val) override
{
handle_value(val);
return true;
}
bool number_unsigned(number_unsigned_t val)
bool number_unsigned(number_unsigned_t val) override
{
handle_value(val);
return true;
}
bool number_float(number_float_t val, const string_t& /*unused*/)
bool number_float(number_float_t val, const string_t& /*unused*/) override
{
handle_value(val);
return true;
}
bool string(string_t& val)
bool string(string_t& val) override
{
handle_value(val);
return true;
}
bool binary(binary_t& val)
bool binary(binary_t& val) override
{
handle_value(std::move(val));
return true;
}
bool start_object(std::size_t len)
bool start_object(std::size_t len) override
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
@ -238,7 +371,7 @@ class json_sax_dom_parser
return true;
}
bool key(string_t& val)
bool key(string_t& val) override
{
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_object());
@ -248,7 +381,7 @@ class json_sax_dom_parser
return true;
}
bool end_object()
bool end_object() override
{
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_object());
@ -258,7 +391,7 @@ class json_sax_dom_parser
return true;
}
bool start_array(std::size_t len)
bool start_array(std::size_t len) override
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
@ -270,7 +403,7 @@ class json_sax_dom_parser
return true;
}
bool end_array()
bool end_array() override
{
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_array());
@ -280,23 +413,6 @@ class json_sax_dom_parser
return true;
}
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
const Exception& ex)
{
errored = true;
static_cast<void>(ex);
if (allow_exceptions)
{
JSON_THROW(ex);
}
return false;
}
constexpr bool is_errored() const
{
return errored;
}
private:
/*!
@ -335,14 +451,11 @@ class json_sax_dom_parser
std::vector<BasicJsonType*> ref_stack {};
/// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred
bool errored = false;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
};
template<typename BasicJsonType>
class json_sax_dom_callback_parser
class json_sax_dom_callback_parser : public json_sax_exception_handler<BasicJsonType>
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@ -356,7 +469,7 @@ class json_sax_dom_callback_parser
json_sax_dom_callback_parser(BasicJsonType& r,
const parser_callback_t cb,
const bool allow_exceptions_ = true)
: root(r), callback(cb), allow_exceptions(allow_exceptions_)
: root(r), callback(cb), json_sax_exception_handler<BasicJsonType>(allow_exceptions_)
{
keep_stack.push_back(true);
}
@ -368,49 +481,49 @@ class json_sax_dom_callback_parser
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~json_sax_dom_callback_parser() = default;
bool null()
bool null() override
{
handle_value(nullptr);
return true;
}
bool boolean(bool val)
bool boolean(bool val) override
{
handle_value(val);
return true;
}
bool number_integer(number_integer_t val)
bool number_integer(number_integer_t val) override
{
handle_value(val);
return true;
}
bool number_unsigned(number_unsigned_t val)
bool number_unsigned(number_unsigned_t val) override
{
handle_value(val);
return true;
}
bool number_float(number_float_t val, const string_t& /*unused*/)
bool number_float(number_float_t val, const string_t& /*unused*/) override
{
handle_value(val);
return true;
}
bool string(string_t& val)
bool string(string_t& val) override
{
handle_value(val);
return true;
}
bool binary(binary_t& val)
bool binary(binary_t& val) override
{
handle_value(std::move(val));
return true;
}
bool start_object(std::size_t len)
bool start_object(std::size_t len) override
{
// check callback for object start
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
@ -428,7 +541,7 @@ class json_sax_dom_callback_parser
return true;
}
bool key(string_t& val)
bool key(string_t& val) override
{
BasicJsonType k = BasicJsonType(val);
@ -445,7 +558,7 @@ class json_sax_dom_callback_parser
return true;
}
bool end_object()
bool end_object() override
{
if (ref_stack.back())
{
@ -481,7 +594,7 @@ class json_sax_dom_callback_parser
return true;
}
bool start_array(std::size_t len)
bool start_array(std::size_t len) override
{
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
keep_stack.push_back(keep);
@ -498,7 +611,7 @@ class json_sax_dom_callback_parser
return true;
}
bool end_array()
bool end_array() override
{
bool keep = true;
@ -530,23 +643,6 @@ class json_sax_dom_callback_parser
return true;
}
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
const Exception& ex)
{
errored = true;
static_cast<void>(ex);
if (allow_exceptions)
{
JSON_THROW(ex);
}
return false;
}
constexpr bool is_errored() const
{
return errored;
}
private:
/*!
@ -638,18 +734,14 @@ class json_sax_dom_callback_parser
std::vector<bool> key_keep_stack {};
/// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred
bool errored = false;
/// callback function
const parser_callback_t callback = nullptr;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
/// a discarded value for the callback
BasicJsonType discarded = BasicJsonType::value_t::discarded;
};
template<typename BasicJsonType>
class json_sax_acceptor
class json_sax_acceptor : public msgpack_sax<BasicJsonType>
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@ -658,67 +750,117 @@ class json_sax_acceptor
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
bool null()
bool null() override
{
return true;
}
bool boolean(bool /*unused*/)
bool boolean(bool /*unused*/) override
{
return true;
}
bool number_integer(number_integer_t /*unused*/)
bool number_integer(number_integer_t /*unused*/) override
{
return true;
}
bool number_unsigned(number_unsigned_t /*unused*/)
bool number_unsigned(number_unsigned_t /*unused*/) override
{
return true;
}
bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) override
{
return true;
}
bool string(string_t& /*unused*/)
bool string(string_t& /*unused*/) override
{
return true;
}
bool binary(binary_t& /*unused*/)
bool binary(binary_t& /*unused*/) override
{
return true;
}
bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) override
{
return true;
}
bool key(string_t& /*unused*/)
bool end_array() override
{
return true;
}
bool end_object()
bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) override
{
return true;
}
bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
bool end_object() override
{
return true;
}
bool end_array()
bool key(string_t& /*unused*/) override
{
return true;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
bool key_null() override
{
return true;
}
bool key_boolean(bool /*unused*/) override
{
return true;
}
bool key_integer(number_integer_t /*unused*/) override
{
return true;
}
bool key_unsigned(number_unsigned_t /*unused*/) override
{
return true;
}
bool key_float(number_float_t /*unused*/, const string_t& /*unused*/) override
{
return true;
}
bool key_binary(binary_t& /*val*/) override
{
return true;
}
bool start_key_array(std::size_t /*elements*/) override
{
return true;
}
bool end_key_array() override
{
return true;
}
bool start_key_object(std::size_t /*elements*/) override
{
return true;
}
bool end_key_object() override
{
return true;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) override
{
return false;
}

View File

@ -11,6 +11,7 @@
#include <cstdint> // size_t
#include <utility> // declval
#include <string> // string
#include <type_traits>
#include <nlohmann/detail/abi_macros.hpp>
#include <nlohmann/detail/meta/detected.hpp>
@ -23,84 +24,150 @@ namespace detail
template<typename T>
using null_function_t = decltype(std::declval<T&>().null());
template<typename T>
using key_null_function_t = decltype(std::declval<T&>().key_null());
template<typename T>
using boolean_function_t =
decltype(std::declval<T&>().boolean(std::declval<bool>()));
template<typename T>
using key_boolean_function_t =
decltype(std::declval<T&>().key_boolean(std::declval<bool>()));
template<typename T, typename Integer>
using number_integer_function_t =
decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
template<typename T, typename Integer>
using key_number_integer_function_t =
decltype(std::declval<T&>().key_number_integer(std::declval<Integer>()));
template<typename T, typename Unsigned>
using number_unsigned_function_t =
decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
template<typename T, typename Unsigned>
using key_number_unsigned_function_t =
decltype(std::declval<T&>().key_number_unsigned(std::declval<Unsigned>()));
template<typename T, typename Float, typename String>
using number_float_function_t = decltype(std::declval<T&>().number_float(
std::declval<Float>(), std::declval<const String&>()));
template<typename T, typename Float, typename String>
using key_number_float_function_t = decltype(std::declval<T&>().key_number_float(
std::declval<Float>(), std::declval<const String&>()));
template<typename T, typename String>
using string_function_t =
decltype(std::declval<T&>().string(std::declval<String&>()));
template<typename T, typename Binary>
using binary_function_t =
decltype(std::declval<T&>().binary(std::declval<Binary&>()));
template<typename T>
using start_object_function_t =
decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
template<typename T, typename String>
using key_function_t =
decltype(std::declval<T&>().key(std::declval<String&>()));
template<typename T>
using end_object_function_t = decltype(std::declval<T&>().end_object());
template<typename T, typename Binary>
using binary_function_t =
decltype(std::declval<T&>().binary(std::declval<Binary&>()));
template<typename T, typename Binary>
using key_binary_function_t =
decltype(std::declval<T&>().key_binary(std::declval<Binary&>()));
template<typename T>
using start_array_function_t =
decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
template<typename T>
using start_key_array_function_t =
decltype(std::declval<T&>().start_key_array(std::declval<std::size_t>()));
template<typename T>
using end_array_function_t = decltype(std::declval<T&>().end_array());
template<typename T>
using end_key_array_function_t = decltype(std::declval<T&>().end_key_array());
template<typename T>
using start_object_function_t =
decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
template<typename T>
using start_key_object_function_t =
decltype(std::declval<T&>().start_key_object(std::declval<std::size_t>()));
template<typename T>
using end_object_function_t = decltype(std::declval<T&>().end_object());
template<typename T>
using end_key_object_function_t = decltype(std::declval<T&>().end_key_object());
template<typename T, typename Exception>
using parse_error_function_t = decltype(std::declval<T&>().parse_error(
std::declval<std::size_t>(), std::declval<const std::string&>(),
std::declval<const Exception&>()));
template<typename SAX, typename BasicJsonType>
struct is_sax
template<typename SAX, typename BasicJsonType, typename IsTrue = conjunction<
is_detected_exact<bool, null_function_t, SAX>,
is_detected_exact<bool, boolean_function_t, SAX>,
is_detected_exact<bool, number_integer_function_t, SAX, typename BasicJsonType::number_integer_t>,
is_detected_exact<bool, number_unsigned_function_t, SAX, typename BasicJsonType::number_unsigned_t>,
is_detected_exact<bool, number_float_function_t, SAX, typename BasicJsonType::number_float_t, typename BasicJsonType::string_t>,
is_detected_exact<bool, string_function_t, SAX, typename BasicJsonType::string_t>,
is_detected_exact<bool, binary_function_t, SAX, typename BasicJsonType::binary_t>,
is_detected_exact<bool, key_function_t, SAX, typename BasicJsonType::string_t>,
is_detected_exact<bool, start_array_function_t, SAX>,
is_detected_exact<bool, end_array_function_t, SAX>,
is_detected_exact<bool, start_object_function_t, SAX>,
is_detected_exact<bool, end_object_function_t, SAX>,
is_detected_exact<bool, parse_error_function_t, SAX, typename BasicJsonType::exception>
>
>
struct is_sax : IsTrue
{
private:
static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>");
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
using exception_t = typename BasicJsonType::exception;
public:
static constexpr bool value =
is_detected_exact<bool, null_function_t, SAX>::value &&
is_detected_exact<bool, boolean_function_t, SAX>::value &&
is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
is_detected_exact<bool, start_object_function_t, SAX>::value &&
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
is_detected_exact<bool, end_object_function_t, SAX>::value &&
is_detected_exact<bool, start_array_function_t, SAX>::value &&
is_detected_exact<bool, end_array_function_t, SAX>::value &&
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
};
template<typename SAX, typename BasicJsonType, typename IsTrue = conjunction<
is_sax<SAX, BasicJsonType>,
is_detected_exact<bool, key_null_function_t, SAX>,
is_detected_exact<bool, key_boolean_function_t, SAX>,
is_detected_exact<bool, key_number_integer_function_t, SAX, typename BasicJsonType::number_integer_t>,
is_detected_exact<bool, key_number_unsigned_function_t, SAX, typename BasicJsonType::number_unsigned_t>,
is_detected_exact<bool, key_number_float_function_t, SAX, typename BasicJsonType::number_float_t, typename BasicJsonType::string_t>,
is_detected_exact<bool, key_binary_function_t, SAX, typename BasicJsonType::binary_t>,
is_detected_exact<bool, start_array_function_t, SAX>,
is_detected_exact<bool, end_array_function_t, SAX>,
is_detected_exact<bool, start_key_object_function_t, SAX>,
is_detected_exact<bool, end_key_object_function_t, SAX>
>
>
struct is_sax_msgpack : IsTrue
{
private:
static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>");
};
template<typename SAX, typename BasicJsonType>
struct is_sax_static_asserts
{

1
include/test_data.hpp Normal file
View File

@ -0,0 +1 @@
#define TEST_DATA_DIRECTORY "/Users/lucapassarella/Documents/projects/json/json_test_data"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,344 @@
#pragma once
#include <nlohmann/json.hpp>
using nlohmann::json;
class SaxEventLogger : public nlohmann::msgpack_sax<nlohmann::json>
{
public:
std::vector<std::string> events {};
bool errored = false;
bool null() override
{
events.emplace_back("null()");
return true;
}
bool boolean(bool val) override
{
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
return true;
}
bool number_integer(json::number_integer_t val) override
{
events.push_back("number_integer(" + std::to_string(val) + ")");
return true;
}
bool number_unsigned(json::number_unsigned_t val) override
{
events.push_back("number_unsigned(" + std::to_string(val) + ")");
return true;
}
bool number_float(json::number_float_t /*unused*/, const std::string& s) override
{
events.push_back("number_float(" + s + ")");
return true;
}
bool string(std::string& val) override
{
events.push_back("string(" + val + ")");
return true;
}
bool binary(json::binary_t& val) override
{
std::string binary_contents = "binary(";
std::string comma_space;
for (auto b : val)
{
binary_contents.append(comma_space);
binary_contents.append(std::to_string(static_cast<int>(b)));
comma_space = ", ";
}
binary_contents.append(")");
events.push_back(binary_contents);
return true;
}
bool start_array(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_array()");
}
else
{
events.push_back("start_array(" + std::to_string(elements) + ")");
}
return true;
}
bool end_array() override
{
events.emplace_back("end_array()");
return true;
}
bool start_object(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_object()");
}
else
{
events.push_back("start_object(" + std::to_string(elements) + ")");
}
return true;
}
bool end_object() override
{
events.emplace_back("end_object()");
return true;
}
bool key(std::string& val) override
{
events.push_back("key(" + val + ")");
return true;
}
virtual bool key_null() override
{
events.push_back("key_null()");
return true;
}
virtual bool key_boolean(bool val) override
{
events.push_back("key_bool(" + std::to_string(val) + ")");
return true;
}
virtual bool key_integer(json::number_integer_t val) override
{
events.push_back("key_integer(" + std::to_string(val) + ")");
return true;
}
virtual bool key_unsigned(json::number_unsigned_t val) override
{
events.push_back("key_unsigned(" + std::to_string(val) + ")");
return true;
}
virtual bool key_float(json::number_float_t val, const json::string_t& s) override
{
events.push_back("key_float(" + s + ")");
return true;
}
bool key_binary(binary_t& val) override
{
std::string binary_contents = "key_binary(";
std::string comma_space;
for (auto b : val)
{
binary_contents.append(comma_space);
binary_contents.append(std::to_string(static_cast<int>(b)));
comma_space = ", ";
}
binary_contents.append(")");
events.push_back(binary_contents);
return true;
}
bool start_key_array(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_key_array()");
}
else
{
events.push_back("start_key_array(" + std::to_string(elements) + ")");
}
return true;
}
bool end_key_array() override
{
events.emplace_back("end_key_array()");
return true;
}
bool start_key_object(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_key_object()");
}
else
{
events.push_back("start_key_object(" + std::to_string(elements) + ")");
}
return true;
}
bool end_key_object() override
{
events.emplace_back("end_key_object()");
return true;
}
bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/) override
{
errored = true;
events.push_back("parse_error(" + std::to_string(position) + ")");
return false;
}
};
class SaxCountdown : public nlohmann::msgpack_sax<nlohmann::json>
{
protected:
int events_left = 0;
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null() override
{
return events_left-- > 0;
}
bool boolean(bool /*val*/) override
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*val*/) override
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*val*/) override
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
{
return events_left-- > 0;
}
bool string(std::string& /*val*/) override
{
return events_left-- > 0;
}
bool binary(json::binary_t& /*val*/) override
{
return events_left-- > 0;
}
bool start_array(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_array() override
{
return events_left-- > 0;
}
bool start_object(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_object() override
{
return events_left-- > 0;
}
bool key(std::string& /*val*/) override
{
return events_left-- > 0;
}
bool key_null() override
{
return events_left-- > 0;
}
bool key_boolean(bool /*val*/) override
{
return events_left-- > 0;
}
bool key_integer(number_integer_t /*val*/) override
{
return events_left-- > 0;
}
bool key_unsigned(number_unsigned_t /*val*/) override
{
return events_left-- > 0;
}
bool key_float(number_float_t /*val*/, const string_t& /*val*/) override
{
return events_left-- > 0;
}
bool key_binary(binary_t& /*val*/) override
{
return events_left-- > 0;
}
bool start_key_array(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_key_array() override
{
return events_left-- > 0;
}
bool start_key_object(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_key_object() override
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
{
return false;
}
};
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
{
public:
explicit sax_no_exception(json& j)
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
{}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) override
{
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
return false;
}
static std::string* error_string;
};

View File

@ -645,83 +645,7 @@ TEST_CASE("BSON input/output_adapters")
}
}
namespace
{
class SaxCountdown
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null()
{
return events_left-- > 0;
}
bool boolean(bool /*unused*/)
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*unused*/)
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*unused*/)
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
{
return events_left-- > 0;
}
bool string(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool binary(std::vector<std::uint8_t>& /*unused*/)
{
return events_left-- > 0;
}
bool start_object(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool key(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool end_object()
{
return events_left-- > 0;
}
bool start_array(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool end_array()
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
{
return false;
}
private:
int events_left = 0;
};
} // namespace
#include "test_sax_helpers.hpp"
TEST_CASE("Incomplete BSON Input")
{

View File

@ -19,84 +19,7 @@ using nlohmann::json;
#include <set>
#include "make_test_data_available.hpp"
#include "test_utils.hpp"
namespace
{
class SaxCountdown
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null()
{
return events_left-- > 0;
}
bool boolean(bool /*unused*/)
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*unused*/)
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*unused*/)
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
{
return events_left-- > 0;
}
bool string(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool binary(std::vector<std::uint8_t>& /*unused*/)
{
return events_left-- > 0;
}
bool start_object(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool key(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool end_object()
{
return events_left-- > 0;
}
bool start_array(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool end_array()
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
{
return false;
}
private:
int events_left = 0;
};
} // namespace
#include "test_sax_helpers.hpp"
TEST_CASE("CBOR")
{

View File

@ -10,6 +10,7 @@
#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
#include "test_sax_helpers.hpp"
using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
@ -19,189 +20,6 @@ using nlohmann::json;
namespace
{
class SaxEventLogger
{
public:
bool null()
{
events.emplace_back("null()");
return true;
}
bool boolean(bool val)
{
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
return true;
}
bool number_integer(json::number_integer_t val)
{
events.push_back("number_integer(" + std::to_string(val) + ")");
return true;
}
bool number_unsigned(json::number_unsigned_t val)
{
events.push_back("number_unsigned(" + std::to_string(val) + ")");
return true;
}
bool number_float(json::number_float_t /*unused*/, const std::string& s)
{
events.push_back("number_float(" + s + ")");
return true;
}
bool string(std::string& val)
{
events.push_back("string(" + val + ")");
return true;
}
bool binary(json::binary_t& val)
{
std::string binary_contents = "binary(";
std::string comma_space;
for (auto b : val)
{
binary_contents.append(comma_space);
binary_contents.append(std::to_string(static_cast<int>(b)));
comma_space = ", ";
}
binary_contents.append(")");
events.push_back(binary_contents);
return true;
}
bool start_object(std::size_t elements)
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_object()");
}
else
{
events.push_back("start_object(" + std::to_string(elements) + ")");
}
return true;
}
bool key(std::string& val)
{
events.push_back("key(" + val + ")");
return true;
}
bool end_object()
{
events.emplace_back("end_object()");
return true;
}
bool start_array(std::size_t elements)
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_array()");
}
else
{
events.push_back("start_array(" + std::to_string(elements) + ")");
}
return true;
}
bool end_array()
{
events.emplace_back("end_array()");
return true;
}
bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/)
{
errored = true;
events.push_back("parse_error(" + std::to_string(position) + ")");
return false;
}
std::vector<std::string> events {};
bool errored = false;
};
class SaxCountdown : public nlohmann::json::json_sax_t
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null() override
{
return events_left-- > 0;
}
bool boolean(bool /*val*/) override
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*val*/) override
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*val*/) override
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
{
return events_left-- > 0;
}
bool string(std::string& /*val*/) override
{
return events_left-- > 0;
}
bool binary(json::binary_t& /*val*/) override
{
return events_left-- > 0;
}
bool start_object(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool key(std::string& /*val*/) override
{
return events_left-- > 0;
}
bool end_object() override
{
return events_left-- > 0;
}
bool start_array(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_array() override
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
{
return false;
}
private:
int events_left = 0;
};
json parser_helper(const std::string& s);
bool accept_helper(const std::string& s);

View File

@ -10,6 +10,7 @@
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
#include "test_sax_helpers.hpp"
using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
@ -22,111 +23,6 @@ using nlohmann::json;
namespace
{
struct SaxEventLogger : public nlohmann::json_sax<json>
{
bool null() override
{
events.emplace_back("null()");
return true;
}
bool boolean(bool val) override
{
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
return true;
}
bool number_integer(json::number_integer_t val) override
{
events.push_back("number_integer(" + std::to_string(val) + ")");
return true;
}
bool number_unsigned(json::number_unsigned_t val) override
{
events.push_back("number_unsigned(" + std::to_string(val) + ")");
return true;
}
bool number_float(json::number_float_t /*val*/, const std::string& s) override
{
events.push_back("number_float(" + s + ")");
return true;
}
bool string(std::string& val) override
{
events.push_back("string(" + val + ")");
return true;
}
bool binary(json::binary_t& val) override
{
std::string binary_contents = "binary(";
std::string comma_space;
for (auto b : val)
{
binary_contents.append(comma_space);
binary_contents.append(std::to_string(static_cast<int>(b)));
comma_space = ", ";
}
binary_contents.append(")");
events.push_back(binary_contents);
return true;
}
bool start_object(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_object()");
}
else
{
events.push_back("start_object(" + std::to_string(elements) + ")");
}
return true;
}
bool key(std::string& val) override
{
events.push_back("key(" + val + ")");
return true;
}
bool end_object() override
{
events.emplace_back("end_object()");
return true;
}
bool start_array(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_array()");
}
else
{
events.push_back("start_array(" + std::to_string(elements) + ")");
}
return true;
}
bool end_array() override
{
events.emplace_back("end_array()");
return true;
}
bool parse_error(std::size_t position, const std::string& /*last_token*/, const json::exception& /*ex*/) override
{
events.push_back("parse_error(" + std::to_string(position) + ")");
return false;
}
std::vector<std::string> events {};
};
struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger
{

View File

@ -25,7 +25,7 @@ class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
public:
explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser<json>(j, false) {}
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) override
{
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
return false;

View File

@ -21,84 +21,7 @@ using nlohmann::json;
#include <set>
#include "make_test_data_available.hpp"
#include "test_utils.hpp"
namespace
{
class SaxCountdown
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null()
{
return events_left-- > 0;
}
bool boolean(bool /*unused*/)
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*unused*/)
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*unused*/)
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
{
return events_left-- > 0;
}
bool string(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool binary(std::vector<std::uint8_t>& /*unused*/)
{
return events_left-- > 0;
}
bool start_object(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool key(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool end_object()
{
return events_left-- > 0;
}
bool start_array(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool end_array()
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
{
return false;
}
private:
int events_left = 0;
};
} // namespace
#include "test_sax_helpers.hpp"
TEST_CASE("MessagePack")
{
@ -1445,7 +1368,7 @@ TEST_CASE("MessagePack")
json _;
CHECK_THROWS_WITH_AS(_ = json::from_msgpack(std::vector<uint8_t>({0x87})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack string: unexpected end of input", json::parse_error&);
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack key: unexpected end of input", json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::from_msgpack(std::vector<uint8_t>({0xcc})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack number: unexpected end of input", json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::from_msgpack(std::vector<uint8_t>({0xcd})),
@ -1531,12 +1454,14 @@ TEST_CASE("MessagePack")
}
}
SECTION("invalid string in map")
{
json _;
CHECK_THROWS_WITH_AS(_ = json::from_msgpack(std::vector<uint8_t>({0x81, 0xff, 0x01})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing MessagePack string: expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0xFF", json::parse_error&);
CHECK(json::from_msgpack(std::vector<uint8_t>({0x81, 0xff, 0x01}), true, false).is_discarded());
}
// THIS TEST SHOULD FAIL NO MORE!
// INT AS KEY IN MSGPACK IS NOW SUPPORTED!
// SECTION("invalid string in map")
// {
// json _;
// CHECK_THROWS_WITH_AS(_ = json::from_msgpack(std::vector<uint8_t>({0x81, 0xff, 0x01})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing MessagePack string: expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0xFF", json::parse_error&);
// CHECK(json::from_msgpack(std::vector<uint8_t>({0x81, 0xff, 0x01}), true, false).is_discarded());
// }
SECTION("strict mode")
{

View File

@ -165,13 +165,11 @@ struct adl_serializer<NonDefaultConstructible>
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
{
public:
explicit sax_no_exception(json& j)
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
{}
explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser<json>(j, false) {}
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) override
{
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
return false;
}

View File

@ -16,84 +16,7 @@ using nlohmann::json;
#include <set>
#include "make_test_data_available.hpp"
#include "test_utils.hpp"
namespace
{
class SaxCountdown
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null()
{
return events_left-- > 0;
}
bool boolean(bool /*unused*/)
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*unused*/)
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*unused*/)
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
{
return events_left-- > 0;
}
bool string(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool binary(std::vector<std::uint8_t>& /*unused*/)
{
return events_left-- > 0;
}
bool start_object(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool key(std::string& /*unused*/)
{
return events_left-- > 0;
}
bool end_object()
{
return events_left-- > 0;
}
bool start_array(std::size_t /*unused*/)
{
return events_left-- > 0;
}
bool end_array()
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
{
return false;
}
private:
int events_left = 0;
};
} // namespace
#include "test_sax_helpers.hpp"
TEST_CASE("UBJSON")
{