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) {} 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 /// @brief exception indicating other library errors
/// @sa https://json.nlohmann.me/api/basic_json/other_error/ /// @sa https://json.nlohmann.me/api/basic_json/other_error/
class other_error : public exception 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 0x8D:
case 0x8E: case 0x8E:
case 0x8F: 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 // fixarray
case 0x90: case 0x90:
@ -1502,13 +1506,13 @@ class binary_reader
case 0xDE: // map 16 case 0xDE: // map 16
{ {
std::uint16_t len{}; 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 case 0xDF: // map 32
{ {
std::uint32_t len{}; 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 // negative fixint
@ -1781,13 +1785,44 @@ class binary_reader
@param[in] len the length of the object @param[in] len the length of the object
@return whether object creation completed @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) for (std::size_t i = 0; i < len; ++i)
{ {
switch (get()) switch (get())
@ -1935,6 +1970,63 @@ class binary_reader
break; 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 // fixstr
case 0xA0: case 0xA0:
case 0xA1: case 0xA1:
@ -2107,6 +2199,50 @@ class binary_reader
break; 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 // negative fixint
case 0xE0: case 0xE0:
case 0xE1: 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. input.
*/ */
template<typename BasicJsonType> template<typename BasicJsonType>
class sax_interface class json_sax
{ {
public: public:
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
@ -97,36 +97,6 @@ class sax_interface
*/ */
virtual bool key(string_t& val) = 0; 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 @brief the end of an object was read
@return whether parsing should proceed @return whether parsing should proceed
@ -158,16 +128,16 @@ class sax_interface
const std::string& last_token, const std::string& last_token,
const detail::exception& ex) = 0; const detail::exception& ex) = 0;
sax_interface() = default; json_sax() = default;
sax_interface(const sax_interface&) = default; json_sax(const json_sax&) = default;
sax_interface(sax_interface&&) noexcept = default; json_sax(json_sax&&) noexcept = default;
sax_interface& operator=(const sax_interface&) = default; json_sax& operator=(const json_sax&) = default;
sax_interface& operator=(sax_interface&&) noexcept = default; json_sax& operator=(json_sax&&) noexcept = default;
virtual ~sax_interface() = default; virtual ~json_sax() = default;
}; };
template<typename BasicJsonType> template<typename BasicJsonType>
class json_sax : public sax_interface<BasicJsonType> class msgpack_sax : public json_sax<BasicJsonType>
{ {
public: public:
@ -177,33 +147,77 @@ class json_sax : public sax_interface<BasicJsonType>
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
bool key_null() override /*!
{ @brief an object key of null value was read
return false; @return whether parsing should proceed
} */
virtual bool key_null() = 0;
bool key_boolean(bool val) override /*!
{ @brief an object key of type bool was read
return false; @return whether parsing should proceed
} */
virtual bool key_boolean(bool val) = 0;
bool key_integer(number_integer_t val) override /*!
{ @brief an object key of type integer number was read
return false; @return whether parsing should proceed
} */
virtual bool key_integer(number_integer_t val) = 0;
bool key_unsigned(number_unsigned_t val) override /*!
{ @brief an object key of type unsigned was read
return false; @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 /*!
{ @brief an object key of type float was read
return false; @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 namespace detail
{ {
/*! /*!
@ -711,7 +725,7 @@ class json_sax_dom_callback_parser : public json_sax_exception_handler<BasicJson
}; };
template<typename BasicJsonType> template<typename BasicJsonType>
class json_sax_acceptor : public sax_interface<BasicJsonType> class json_sax_acceptor : public msgpack_sax<BasicJsonType>
{ {
public: public:
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
@ -755,11 +769,26 @@ class json_sax_acceptor : public sax_interface<BasicJsonType>
return true; 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 bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) override
{ {
return true; return true;
} }
bool end_object() override
{
return true;
}
bool key(string_t& /*unused*/) override bool key(string_t& /*unused*/) override
{ {
return true; return true;
@ -790,17 +819,27 @@ class json_sax_acceptor : public sax_interface<BasicJsonType>
return true; return true;
} }
bool end_object() override bool key_binary(binary_t& /*val*/) override
{ {
return true; 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; 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; return true;
} }

View File

@ -3,6 +3,7 @@
#include <cstdint> // size_t #include <cstdint> // size_t
#include <utility> // declval #include <utility> // declval
#include <string> // string #include <string> // string
#include <type_traits>
#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
@ -14,22 +15,46 @@ namespace detail
template<typename T> template<typename T>
using null_function_t = decltype(std::declval<T&>().null()); 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> template<typename T>
using boolean_function_t = using boolean_function_t =
decltype(std::declval<T&>().boolean(std::declval<bool>())); 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> template<typename T, typename Integer>
using number_integer_function_t = using number_integer_function_t =
decltype(std::declval<T&>().number_integer(std::declval<Integer>())); 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> template<typename T, typename Unsigned>
using number_unsigned_function_t = using number_unsigned_function_t =
decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>())); 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> template<typename T, typename Float, typename String>
using number_float_function_t = decltype(std::declval<T&>().number_float( using number_float_function_t = decltype(std::declval<T&>().number_float(
std::declval<Float>(), std::declval<const String&>())); 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> template<typename T, typename String>
using string_function_t = using string_function_t =
decltype(std::declval<T&>().string(std::declval<String&>())); 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<std::size_t>(), std::declval<const std::string&>(),
std::declval<const Exception&>())); std::declval<const Exception&>()));
template<typename SAX, typename BasicJsonType> template<typename SAX, typename BasicJsonType, typename IsTrue = conjunction<
struct is_sax 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: private:
static_assert(is_basic_json<BasicJsonType>::value, static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>"); "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> template<typename SAX, typename BasicJsonType>
struct is_sax_static_asserts 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; using nlohmann::json;
class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json> class SaxEventLogger : public nlohmann::msgpack_sax<nlohmann::json>
{ {
public: public:
@ -35,19 +35,19 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true; 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 + ")"); events.push_back("number_float(" + s + ")");
return true; return true;
} }
bool string(std::string& val) override bool string(std::string& val) override
{ {
events.push_back("string(" + val + ")"); events.push_back("string(" + val + ")");
return true; return true;
} }
bool binary(json::binary_t& val) override bool binary(json::binary_t& val) override
{ {
std::string binary_contents = "binary("; std::string binary_contents = "binary(";
std::string comma_space; std::string comma_space;
@ -62,7 +62,26 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true; 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)) if (elements == static_cast<std::size_t>(-1))
{ {
@ -75,19 +94,26 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true; 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 + ")"); events.push_back("key(" + val + ")");
return true; return true;
} }
virtual bool key_null() override virtual bool key_null() override
{ {
events.push_back("key_null"); events.push_back("key_null()");
return true; 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) + ")"); events.push_back("key_bool(" + std::to_string(val) + ")");
return true; return true;
@ -111,28 +137,56 @@ class SaxEventLogger : public nlohmann::sax_interface<nlohmann::json>
return true; 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; 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)) if (elements == static_cast<std::size_t>(-1))
{ {
events.emplace_back("start_array()"); events.emplace_back("start_key_array()");
} }
else else
{ {
events.push_back("start_array(" + std::to_string(elements) + ")"); events.push_back("start_key_array(" + std::to_string(elements) + ")");
} }
return true; 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; 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: protected:
@ -190,12 +244,27 @@ class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
{ {
return events_left-- > 0; 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 bool start_object(std::size_t /*elements*/) override
{ {
return events_left-- > 0; return events_left-- > 0;
} }
bool end_object() override
{
return events_left-- > 0;
}
bool key(std::string& /*val*/) override bool key(std::string& /*val*/) override
{ {
return events_left-- > 0; return events_left-- > 0;
@ -206,7 +275,7 @@ class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
return events_left-- > 0; return events_left-- > 0;
} }
bool key_boolean(bool /*val*/) override bool key_boolean(bool /*val*/) override
{ {
return events_left-- > 0; return events_left-- > 0;
} }
@ -226,17 +295,27 @@ class SaxCountdown : public nlohmann::sax_interface<nlohmann::json>
return events_left-- > 0; return events_left-- > 0;
} }
bool end_object() override bool key_binary(binary_t& /*val*/) override
{ {
return events_left-- > 0; 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; 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; return events_left-- > 0;
} }