2.3.5: json_sax_dom_error_state base for the DOM SAX parsers (#5891)

Holds errored, allow_exceptions, parse_error() and is_errored(). The scalar
handlers stay in each class (parse hot path).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-23 10:30:34 +02:00
1 parent c533a107a1
commit 0092111f4d
1 file changed
+50 -48
+50 -48
View File
@@ -315,6 +315,52 @@ struct diagnostic_positions
};
#endif
/*!
@brief error state shared by the DOM-building SAX parsers
Holds whether a parse error occurred and whether errors are thrown, and
implements the parse_error() and is_errored() members of the SAX interface for
json_sax_dom_parser and json_sax_dom_callback_parser.
*/
class json_sax_dom_error_state
{
public:
explicit json_sax_dom_error_state(const bool allow_exceptions_) noexcept
: allow_exceptions(allow_exceptions_)
{}
// make class move-only
json_sax_dom_error_state(const json_sax_dom_error_state&) = delete;
json_sax_dom_error_state(json_sax_dom_error_state&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
json_sax_dom_error_state& operator=(const json_sax_dom_error_state&) = delete;
json_sax_dom_error_state& operator=(json_sax_dom_error_state&&) = delete; // the const member prevents assignment
~json_sax_dom_error_state() = default;
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:
/// whether a syntax error occurred
bool errored = false;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
};
/*!
@brief SAX implementation to create a JSON value from SAX events
@@ -329,7 +375,7 @@ constructor contains the parsed value.
@tparam BasicJsonType the JSON type
*/
template<typename BasicJsonType, typename InputAdapterType>
class json_sax_dom_parser
class json_sax_dom_parser : public json_sax_dom_error_state
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@@ -345,7 +391,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, lexer_t* lexer_ = nullptr)
: root(r), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)
: json_sax_dom_error_state(allow_exceptions_), root(r), m_lexer_ref(lexer_)
{}
// make class move-only
@@ -474,24 +520,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:
/*!
@@ -545,16 +573,12 @@ 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;
/// the lexer reference to obtain the current position
lexer_t* m_lexer_ref = nullptr;
};
template<typename BasicJsonType, typename InputAdapterType>
class json_sax_dom_callback_parser
class json_sax_dom_callback_parser : public json_sax_dom_error_state
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
@@ -570,7 +594,7 @@ class json_sax_dom_callback_parser
parser_callback_t cb,
const bool allow_exceptions_ = true,
lexer_t* lexer_ = nullptr)
: root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)
: json_sax_dom_error_state(allow_exceptions_), root(r), callback(std::move(cb)), m_lexer_ref(lexer_)
{
keep_stack.push_back(true);
}
@@ -837,24 +861,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:
/// if there is a pending duplicate-key stash entry for this exact slot,
@@ -1096,12 +1102,8 @@ class json_sax_dom_callback_parser
/// value is later rejected by the callback, instead of erasing the
/// member entirely
std::vector<std::pair<BasicJsonType*, BasicJsonType>> duplicate_key_stash {};
/// 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;
/// the lexer reference to obtain the current position