This commit is contained in:
Luca 2022-10-06 00:53:01 +02:00
parent edf4b3e82e
commit b49de73092
9 changed files with 1898 additions and 23248 deletions

1687
Makefile

File diff suppressed because it is too large Load Diff

BIN
doc/examples/accept__string Executable file

Binary file not shown.

View File

@ -226,6 +226,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

@ -1174,7 +1174,7 @@ class binary_reader
}
}
return sax->end_object();
return true;
}
/////////////
@ -1340,7 +1340,11 @@ class binary_reader
case 0x8D:
case 0x8E:
case 0x8F:
return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
{
const auto len = 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:
@ -1502,13 +1506,13 @@ class binary_reader
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 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(static_cast<std::size_t>(len));
return get_number(input_format_t::msgpack, len) && sax->start_object(len) && get_msgpack_object(static_cast<std::size_t>(len)) && sax->end_object();
}
// negative fixint
@ -1781,13 +1785,44 @@ class binary_reader
@param[in] len the length of the object
@return whether object creation completed
*/
bool get_msgpack_object(const std::size_t len)
bool get_msgpack_object(const std::size_t len){
return get_msgpack_object_impl(len, detail::is_sax_msgpack<SAX, BasicJsonType>());
}
/*!
@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_impl(const std::size_t len, std::false_type)
{
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
string_t key;
for (std::size_t i = 0; i < len; ++i)
{
return false;
get();
if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
{
return false;
}
if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
{
return false;
}
key.clear();
}
return true;
}
/*!
@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_impl(const std::size_t len, std::true_type)
{
for (std::size_t i = 0; i < len; ++i)
{
switch (get())
@ -1935,6 +1970,63 @@ class binary_reader
break;
}
// 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);
if ( JSON_HEDLEY_UNLIKELY(
! (
sax->start_key_object(len)
&&
get_msgpack_object()
&&
sax->end_key_object()
)
)
)
{
return false;
}
break;
}
// // 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:
// return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
// fixstr
case 0xA0:
case 0xA1:
@ -2107,6 +2199,50 @@ class binary_reader
break;
}
case 0xDE: // map 16
{
std::uint16_t len{};
if ( JSON_HEDLEY_UNLIKELY(
! (
get_number(input_format_t::msgpack, len)
&&
sax->start_key_object(len)
&&
get_msgpack_object()
&&
sax->end_key_object()
)
)
)
{
return false;
}
break;
}
case 0xDF: // map 32
{
std::uint32_t len{};
if ( JSON_HEDLEY_UNLIKELY(
! (
get_number(input_format_t::msgpack, len)
&&
sax->start_key_object(len)
&&
get_msgpack_object()
&&
sax->end_key_object()
)
)
)
{
return false;
}
break;
}
// negative fixint
case 0xE0:
case 0xE1:
@ -2163,7 +2299,7 @@ class binary_reader
}
return sax->end_object();
return true;
}
////////////

View File

@ -21,7 +21,7 @@ boolean return value informs the parser whether to continue processing the
input.
*/
template<typename BasicJsonType>
class sax_interface
class json_sax
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@ -97,36 +97,6 @@ class sax_interface
*/
virtual bool key(string_t& val) = 0;
/*!
@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 the end of an object was read
@return whether parsing should proceed
@ -158,16 +128,16 @@ class sax_interface
const std::string& last_token,
const detail::exception& ex) = 0;
sax_interface() = default;
sax_interface(const sax_interface&) = default;
sax_interface(sax_interface&&) noexcept = default;
sax_interface& operator=(const sax_interface&) = default;
sax_interface& operator=(sax_interface&&) noexcept = default;
virtual ~sax_interface() = default;
json_sax() = default;
json_sax(const json_sax&) = default;
json_sax(json_sax&&) noexcept = default;
json_sax& operator=(const json_sax&) = default;
json_sax& operator=(json_sax&&) noexcept = default;
virtual ~json_sax() = default;
};
template<typename BasicJsonType>
class json_sax : public sax_interface<BasicJsonType>
class msgpack_sax : public json_sax<BasicJsonType>
{
public:
@ -177,33 +147,77 @@ class json_sax : public sax_interface<BasicJsonType>
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
bool key_null() override
{
return false;
}
/*!
@brief an object key of null value was read
@return whether parsing should proceed
*/
virtual bool key_null() = 0;
bool key_boolean(bool val) override
{
return false;
}
/*!
@brief an object key of type bool was read
@return whether parsing should proceed
*/
virtual bool key_boolean(bool val) = 0;
bool key_integer(number_integer_t val) override
{
return false;
}
/*!
@brief an object key of type integer number was read
@return whether parsing should proceed
*/
virtual bool key_integer(number_integer_t val) = 0;
bool key_unsigned(number_unsigned_t val) override
{
return false;
}
/*!
@brief an object key of type unsigned was read
@return whether parsing should proceed
*/
virtual bool key_unsigned(number_unsigned_t val) = 0;
bool key_float(number_float_t val, const string_t& s) override
{
return false;
}
/*!
@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
{
/*!
@ -711,7 +725,7 @@ class json_sax_dom_callback_parser : public json_sax_exception_handler<BasicJson
};
template<typename BasicJsonType>
class json_sax_acceptor : public sax_interface<BasicJsonType>
class json_sax_acceptor : public msgpack_sax<BasicJsonType>
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@ -755,11 +769,26 @@ class json_sax_acceptor : public sax_interface<BasicJsonType>
return true;
}
bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) override
{
return true;
}
bool end_array() override
{
return true;
}
bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) override
{
return true;
}
bool end_object() override
{
return true;
}
bool key(string_t& /*unused*/) override
{
return true;
@ -790,17 +819,27 @@ class json_sax_acceptor : public sax_interface<BasicJsonType>
return true;
}
bool end_object() override
bool key_binary(binary_t& /*val*/) override
{
return true;
}
bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) override
bool start_key_array(std::size_t /*elements*/) override
{
return true;
}
bool end_array() override
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;
}

View File

@ -3,6 +3,7 @@
#include <cstdint> // size_t
#include <utility> // declval
#include <string> // string
#include <type_traits>
#include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
@ -14,22 +15,46 @@ 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&>()));
@ -61,37 +86,47 @@ 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, start_object_function_t, SAX>,
is_detected_exact<bool, key_function_t, SAX, typename BasicJsonType::string_t>,
is_detected_exact<bool, end_object_function_t, SAX>,
is_detected_exact<bool, start_array_function_t, SAX>,
is_detected_exact<bool, end_array_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>
>
>
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

@ -4,7 +4,7 @@
using nlohmann::json;
class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
class SaxEventLogger : public nlohmann::msgpack_sax<nlohmann::json>
{
public:
@ -35,19 +35,19 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true;
}
bool number_float(json::number_float_t /*unused*/, const std::string& s) override
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
bool string(std::string& val) override
{
events.push_back("string(" + val + ")");
return true;
}
bool binary(json::binary_t& val) override
bool binary(json::binary_t& val) override
{
std::string binary_contents = "binary(";
std::string comma_space;
@ -62,7 +62,26 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true;
}
bool start_object(std::size_t elements) override
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))
{
@ -75,19 +94,26 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true;
}
bool key(std::string& val) override
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
virtual bool key_null() override
{
events.push_back("key_null");
events.push_back("key_null()");
return true;
}
virtual bool key_boolean(bool val) override
virtual bool key_boolean(bool val) override
{
events.push_back("key_bool(" + std::to_string(val) + ")");
return true;
@ -111,28 +137,56 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true;
}
bool end_object() override
bool key_binary(binary_t& val) override
{
events.emplace_back("end_object()");
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_array(std::size_t elements) override
bool start_key_array(std::size_t elements) override
{
if (elements == static_cast<std::size_t>(-1))
{
events.emplace_back("start_array()");
events.emplace_back("start_key_array()");
}
else
{
events.push_back("start_array(" + std::to_string(elements) + ")");
events.push_back("start_key_array(" + std::to_string(elements) + ")");
}
return true;
}
bool end_array() override
bool end_key_array() override
{
events.emplace_back("end_array()");
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;
}
@ -146,7 +200,7 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
};
class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
class SaxCountdown : public nlohmann::msgpack_sax<nlohmann::json>
{
protected:
@ -190,12 +244,27 @@ class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
{
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;
@ -206,7 +275,7 @@ class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
return events_left-- > 0;
}
bool key_boolean(bool /*val*/) override
bool key_boolean(bool /*val*/) override
{
return events_left-- > 0;
}
@ -226,17 +295,27 @@ class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
return events_left-- > 0;
}
bool end_object() override
bool key_binary(binary_t& /*val*/) override
{
return events_left-- > 0;
}
bool start_array(std::size_t /*elements*/) override
bool start_key_array(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_array() override
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;
}