json/include/nlohmann/detail/input/json_sax.hpp

729 lines
21 KiB
C++
Raw Normal View History

// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
2022-08-02 05:27:58 +08:00
// | | |__ | | | | | | version 3.11.1
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
2018-02-27 03:08:12 +08:00
#pragma once
#include <cstddef>
2019-03-15 21:55:13 +08:00
#include <string> // string
#include <utility> // move
#include <vector> // vector
2018-02-27 03:08:12 +08:00
2018-03-12 05:47:25 +08:00
#include <nlohmann/detail/exceptions.hpp>
2019-01-13 22:31:22 +08:00
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/string_concat.hpp>
2018-03-12 05:47:25 +08:00
NLOHMANN_JSON_NAMESPACE_BEGIN
2018-02-27 03:08:12 +08:00
/*!
@brief SAX interface
2018-08-17 03:53:47 +08:00
This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
Each function is called in different situations while the input is parsed. The
boolean return value informs the parser whether to continue processing the
input.
2018-02-27 03:08:12 +08:00
*/
template<typename BasicJsonType>
struct json_sax
{
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;
2018-03-14 14:18:42 +08:00
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
2018-02-27 03:08:12 +08:00
/*!
@brief a null value was read
@return whether parsing should proceed
*/
virtual bool null() = 0;
/*!
@brief a boolean value was read
@param[in] val boolean value
@return whether parsing should proceed
*/
virtual bool boolean(bool val) = 0;
/*!
@brief an integer number was read
@param[in] val integer value
@return whether parsing should proceed
*/
virtual bool number_integer(number_integer_t val) = 0;
/*!
@brief an unsigned integer number was read
@param[in] val unsigned integer value
@return whether parsing should proceed
*/
virtual bool number_unsigned(number_unsigned_t val) = 0;
/*!
@brief a floating-point number was read
2018-02-27 03:08:12 +08:00
@param[in] val floating-point value
@param[in] s raw token value
@return whether parsing should proceed
*/
2018-03-14 14:18:42 +08:00
virtual bool number_float(number_float_t val, const string_t& s) = 0;
2018-02-27 03:08:12 +08:00
/*!
@brief a string value was read
2018-02-27 03:08:12 +08:00
@param[in] val string value
@return whether parsing should proceed
@note It is safe to move the passed string value.
2018-02-27 03:08:12 +08:00
*/
2018-03-22 03:12:06 +08:00
virtual bool string(string_t& val) = 0;
2018-02-27 03:08:12 +08:00
/*!
@brief a binary value was read
@param[in] val binary value
@return whether parsing should proceed
@note It is safe to move the passed binary value.
*/
virtual bool binary(binary_t& val) = 0;
2018-02-27 03:08:12 +08:00
/*!
@brief the beginning of an object was read
@param[in] elements number of object elements or -1 if unknown
2018-02-27 03:08:12 +08:00
@return whether parsing should proceed
@note binary formats may report the number of elements
*/
virtual bool start_object(std::size_t elements) = 0;
2018-02-27 03:08:12 +08:00
/*!
@brief an object key was read
@param[in] val object key
@return whether parsing should proceed
2018-08-17 03:53:47 +08:00
@note It is safe to move the passed string.
2018-02-27 03:08:12 +08:00
*/
2018-03-22 03:12:06 +08:00
virtual bool key(string_t& val) = 0;
2018-02-27 03:08:12 +08:00
/*!
@brief the end of an object was read
@return whether parsing should proceed
*/
virtual bool end_object() = 0;
/*!
@brief the beginning of an array was read
@param[in] elements number of array elements or -1 if unknown
2018-02-27 03:08:12 +08:00
@return whether parsing should proceed
@note binary formats may report the number of elements
*/
virtual bool start_array(std::size_t elements) = 0;
2018-02-27 03:08:12 +08:00
/*!
@brief the end of an array was read
@return whether parsing should proceed
*/
virtual bool end_array() = 0;
/*!
@brief a parse error occurred
@param[in] position the position in the input where the error occurs
@param[in] last_token the last read token
2018-10-08 03:30:58 +08:00
@param[in] ex an exception object describing the error
2018-03-21 05:39:08 +08:00
@return whether parsing should proceed (must return false)
2018-02-27 03:08:12 +08:00
*/
virtual bool parse_error(std::size_t position,
const std::string& last_token,
2018-03-12 05:47:25 +08:00
const detail::exception& ex) = 0;
2018-02-27 03:08:12 +08:00
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
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;
2018-02-27 03:08:12 +08:00
virtual ~json_sax() = default;
};
2018-03-06 04:06:00 +08:00
namespace detail
{
2018-05-28 00:07:53 +08:00
/*!
@brief SAX implementation to create a JSON value from SAX events
This class implements the @ref json_sax interface and processes the SAX events
to create a JSON value which makes it basically a DOM parser. The structure or
hierarchy of the JSON value is managed by the stack `ref_stack` which contains
a pointer to the respective array or object for each recursion depth.
After successful parsing, the value that is passed by reference to the
constructor contains the parsed value.
@tparam BasicJsonType the JSON type
*/
2018-03-06 04:06:00 +08:00
template<typename BasicJsonType>
class json_sax_dom_parser
2018-03-06 04:06:00 +08:00
{
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;
2018-03-14 14:18:42 +08:00
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
2018-03-06 04:06:00 +08:00
2018-05-28 00:07:53 +08:00
/*!
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@param[in,out] r reference to a JSON value that is manipulated while
2018-05-28 00:07:53 +08:00
parsing
@param[in] allow_exceptions_ whether parse errors yield exceptions
*/
2018-08-17 03:53:47 +08:00
explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
2018-03-07 01:17:07 +08:00
: root(r), allow_exceptions(allow_exceptions_)
{}
2019-03-17 19:01:49 +08:00
// make class move-only
json_sax_dom_parser(const json_sax_dom_parser&) = delete;
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
2019-03-17 19:01:49 +08:00
json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
2019-03-17 19:01:49 +08:00
~json_sax_dom_parser() = default;
bool null()
2018-03-06 04:06:00 +08:00
{
handle_value(nullptr);
return true;
}
bool boolean(bool val)
2018-03-06 04:06:00 +08:00
{
handle_value(val);
return true;
}
bool number_integer(number_integer_t val)
2018-03-06 04:06:00 +08:00
{
handle_value(val);
return true;
}
bool number_unsigned(number_unsigned_t val)
2018-03-06 04:06:00 +08:00
{
handle_value(val);
return true;
}
bool number_float(number_float_t val, const string_t& /*unused*/)
2018-03-06 04:06:00 +08:00
{
handle_value(val);
return true;
}
bool string(string_t& val)
2018-03-06 04:06:00 +08:00
{
handle_value(val);
return true;
}
bool binary(binary_t& val)
{
2020-05-17 19:51:59 +08:00
handle_value(std::move(val));
return true;
}
bool start_object(std::size_t len)
2018-03-06 04:06:00 +08:00
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
}
2018-03-06 04:06:00 +08:00
return true;
}
bool key(string_t& val)
2018-03-06 04:06:00 +08:00
{
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_object());
2018-03-06 14:19:05 +08:00
// add null at given key and store the reference for later
object_element = &(ref_stack.back()->m_value.object->operator[](val));
2018-03-06 04:06:00 +08:00
return true;
}
bool end_object()
2018-03-06 04:06:00 +08:00
{
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_object());
2021-01-15 04:55:49 +08:00
ref_stack.back()->set_parents();
2018-03-06 04:06:00 +08:00
ref_stack.pop_back();
return true;
}
bool start_array(std::size_t len)
2018-03-06 04:06:00 +08:00
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
}
2018-03-06 04:06:00 +08:00
return true;
}
bool end_array()
2018-03-06 04:06:00 +08:00
{
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(ref_stack.back()->is_array());
2021-01-15 04:55:49 +08:00
ref_stack.back()->set_parents();
2018-03-06 04:06:00 +08:00
ref_stack.pop_back();
return true;
}
2020-07-16 20:45:39 +08:00
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
2020-07-16 20:45:39 +08:00
const Exception& ex)
2018-03-06 04:06:00 +08:00
{
2018-03-07 01:17:07 +08:00
errored = true;
static_cast<void>(ex);
2018-03-07 01:17:07 +08:00
if (allow_exceptions)
{
2020-07-16 20:45:39 +08:00
JSON_THROW(ex);
2018-03-07 01:17:07 +08:00
}
2018-03-06 04:06:00 +08:00
return false;
}
constexpr bool is_errored() const
2018-03-06 04:06:00 +08:00
{
2018-03-07 01:17:07 +08:00
return errored;
2018-03-06 04:06:00 +08:00
}
private:
/*!
@invariant If the ref stack is empty, then the passed value will be the new
root.
@invariant If the ref stack contains a value, then it is an array or an
object to which we can add elements
*/
template<typename Value>
2019-07-02 04:37:30 +08:00
JSON_HEDLEY_RETURNS_NON_NULL
2018-03-06 04:06:00 +08:00
BasicJsonType* handle_value(Value&& v)
{
if (ref_stack.empty())
{
root = BasicJsonType(std::forward<Value>(v));
return &root;
}
JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
return &(ref_stack.back()->m_value.array->back());
}
2019-03-18 20:53:48 +08:00
JSON_ASSERT(ref_stack.back()->is_object());
JSON_ASSERT(object_element);
2019-03-18 20:53:48 +08:00
*object_element = BasicJsonType(std::forward<Value>(v));
return object_element;
2018-03-06 04:06:00 +08:00
}
2018-03-07 01:17:07 +08:00
/// the parsed JSON value
BasicJsonType& root;
/// stack to model hierarchy of values
2019-03-17 19:01:49 +08:00
std::vector<BasicJsonType*> ref_stack {};
2018-03-07 01:17:07 +08:00
/// 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;
2018-03-06 04:06:00 +08:00
};
template<typename BasicJsonType>
class json_sax_dom_callback_parser
{
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;
using parser_callback_t = typename BasicJsonType::parser_callback_t;
using parse_event_t = typename BasicJsonType::parse_event_t;
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_)
{
keep_stack.push_back(true);
}
2019-03-17 19:01:49 +08:00
// make class move-only
json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
2019-03-17 19:01:49 +08:00
json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
2019-03-17 19:01:49 +08:00
~json_sax_dom_callback_parser() = default;
bool null()
{
handle_value(nullptr);
return true;
}
bool boolean(bool val)
{
handle_value(val);
return true;
}
bool number_integer(number_integer_t val)
{
handle_value(val);
return true;
}
bool number_unsigned(number_unsigned_t val)
{
handle_value(val);
return true;
}
bool number_float(number_float_t val, const string_t& /*unused*/)
{
handle_value(val);
return true;
}
bool string(string_t& val)
{
handle_value(val);
return true;
}
bool binary(binary_t& val)
{
2020-05-17 19:51:59 +08:00
handle_value(std::move(val));
return true;
}
bool start_object(std::size_t len)
{
// check callback for object start
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
keep_stack.push_back(keep);
auto val = handle_value(BasicJsonType::value_t::object, true);
ref_stack.push_back(val.second);
// check object limit
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
}
return true;
}
bool key(string_t& val)
{
2018-03-22 03:12:06 +08:00
BasicJsonType k = BasicJsonType(val);
// check callback for key
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
key_keep_stack.push_back(keep);
// add discarded value at given key and store the reference for later
if (keep && ref_stack.back())
{
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
}
return true;
}
bool end_object()
{
2021-01-11 05:40:50 +08:00
if (ref_stack.back())
{
2021-01-11 05:40:50 +08:00
if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{
// discard object
*ref_stack.back() = discarded;
}
else
{
2021-01-15 04:55:49 +08:00
ref_stack.back()->set_parents();
2021-01-11 05:40:50 +08:00
}
}
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
{
// remove discarded value
2019-03-18 20:53:48 +08:00
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
{
2019-03-18 20:53:48 +08:00
if (it->is_discarded())
{
2019-03-18 20:53:48 +08:00
ref_stack.back()->erase(it);
break;
}
}
}
return true;
}
bool start_array(std::size_t len)
{
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
keep_stack.push_back(keep);
auto val = handle_value(BasicJsonType::value_t::array, true);
ref_stack.push_back(val.second);
// check array limit
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
}
return true;
}
bool end_array()
{
bool keep = true;
if (ref_stack.back())
{
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
2021-01-11 05:40:50 +08:00
if (keep)
{
2021-01-15 04:55:49 +08:00
ref_stack.back()->set_parents();
2021-01-11 05:40:50 +08:00
}
else
{
// discard array
*ref_stack.back() = discarded;
}
}
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
// remove discarded value
if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
{
2019-03-18 20:53:48 +08:00
ref_stack.back()->m_value.array->pop_back();
}
return true;
}
2020-07-16 20:45:39 +08:00
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
2020-07-16 20:45:39 +08:00
const Exception& ex)
{
errored = true;
static_cast<void>(ex);
if (allow_exceptions)
{
2020-07-16 20:45:39 +08:00
JSON_THROW(ex);
}
return false;
}
constexpr bool is_errored() const
{
return errored;
}
private:
/*!
@param[in] v value to add to the JSON value we build during parsing
@param[in] skip_callback whether we should skip calling the callback
function; this is required after start_array() and
start_object() SAX events, because otherwise we would call the
callback function with an empty array or object, respectively.
@invariant If the ref stack is empty, then the passed value will be the new
root.
@invariant If the ref stack contains a value, then it is an array or an
object to which we can add elements
@return pair of boolean (whether value should be kept) and pointer (to the
passed value in the ref_stack hierarchy; nullptr if not kept)
*/
template<typename Value>
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
{
JSON_ASSERT(!keep_stack.empty());
// do not handle this value if we know it would be added to a discarded
// container
if (!keep_stack.back())
{
return {false, nullptr};
}
// create value
auto value = BasicJsonType(std::forward<Value>(v));
// check callback
const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
// do not handle this value if we just learnt it shall be discarded
if (!keep)
{
return {false, nullptr};
}
if (ref_stack.empty())
{
root = std::move(value);
return {true, &root};
}
// skip this value if we already decided to skip the parent
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
if (!ref_stack.back())
{
return {false, nullptr};
}
// we now only expect arrays and objects
JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
2019-03-18 20:53:48 +08:00
// array
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->emplace_back(std::move(value));
return {true, &(ref_stack.back()->m_value.array->back())};
}
2019-03-18 20:53:48 +08:00
// object
JSON_ASSERT(ref_stack.back()->is_object());
2019-03-18 20:53:48 +08:00
// check if we should store an element for the current key
JSON_ASSERT(!key_keep_stack.empty());
2019-03-18 20:53:48 +08:00
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
if (!store_element)
2019-03-18 20:53:48 +08:00
{
return {false, nullptr};
}
2019-03-18 20:53:48 +08:00
JSON_ASSERT(object_element);
2019-03-18 20:53:48 +08:00
*object_element = std::move(value);
return {true, object_element};
}
/// the parsed JSON value
BasicJsonType& root;
/// stack to model hierarchy of values
2019-03-17 19:01:49 +08:00
std::vector<BasicJsonType*> ref_stack {};
/// stack to manage which values to keep
2019-03-17 19:01:49 +08:00
std::vector<bool> keep_stack {};
/// stack to manage which object keys to keep
2019-03-17 19:01:49 +08:00
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
{
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;
2018-03-14 14:18:42 +08:00
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
bool null()
{
return true;
}
bool boolean(bool /*unused*/)
{
return true;
}
bool number_integer(number_integer_t /*unused*/)
{
return true;
}
bool number_unsigned(number_unsigned_t /*unused*/)
{
return true;
}
bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
{
return true;
}
bool string(string_t& /*unused*/)
{
return true;
}
bool binary(binary_t& /*unused*/)
{
return true;
}
bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
{
return true;
}
bool key(string_t& /*unused*/)
{
return true;
}
bool end_object()
{
return true;
}
bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
{
return true;
}
bool end_array()
{
return true;
}
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
{
return false;
}
};
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END