mirror of
https://github.com/nlohmann/json.git
synced 2025-07-29 23:01:16 +03:00
json start/end position implementation (#4517)
* Add implementation to retrieve start and end positions of json during parse * Add more unit tests and add start/stop parsing for arrays * Add raw value for all types * Add more tests and fix compiler warning * Amalgamate * Fix CLang GCC warnings * Fix error in build * Style using astyle 3.1 * Fix whitespace changes * revert * more whitespace reverts * Address PR comments * Fix failing issues * More whitespace reverts * Address remaining PR comments * Address comments * Switch to using custom base class instead of default basic_json * Adding a basic using for a json using the new base class. Also address PR comments and fix CI failures * Address decltype comments * Diagnostic positions macro (#4) Co-authored-by: Sush Shringarputale <sushring@linux.microsoft.com> * Fix missed include deletion * Add docs and address other PR comments (#5) * Add docs and address other PR comments --------- Co-authored-by: Sush Shringarputale <sushring@linux.microsoft.com> * Address new PR comments and fix CI tests for documentation * Update documentation based on feedback (#6) --------- Co-authored-by: Sush Shringarputale <sushring@linux.microsoft.com> * Address std::size_t and other comments * Fix new CI issues * Fix lcov * Improve lcov case with update to handle_diagnostic_positions call for discarded values * Fix indentation of LCOV_EXCL_STOP comments * fix amalgamation astyle issue --------- Co-authored-by: Sush Shringarputale <sushring@linux.microsoft.com>
This commit is contained in:
committed by
GitHub
parent
733c59588d
commit
58f5f25968
@ -40,6 +40,7 @@ endif()
|
||||
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${JSON_BuildTests_INIT})
|
||||
option(JSON_CI "Enable CI build targets." OFF)
|
||||
option(JSON_Diagnostics "Use extended diagnostic messages." OFF)
|
||||
option(JSON_Diagnostic_Positions "Enable diagnostic positions." OFF)
|
||||
option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON)
|
||||
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
|
||||
option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF)
|
||||
@ -96,6 +97,10 @@ if (JSON_Diagnostics)
|
||||
message(STATUS "Diagnostics enabled (JSON_DIAGNOSTICS=1)")
|
||||
endif()
|
||||
|
||||
if (JSON_Diagnostic_Positions)
|
||||
message(STATUS "Diagnostic positions enabled")
|
||||
endif()
|
||||
|
||||
if (NOT JSON_GlobalUDLs)
|
||||
message(STATUS "User-defined string literals are not put in the global namespace (JSON_USE_GLOBAL_UDLS=0)")
|
||||
endif()
|
||||
@ -123,6 +128,7 @@ target_compile_definitions(
|
||||
$<$<NOT:$<BOOL:${JSON_ImplicitConversions}>>:JSON_USE_IMPLICIT_CONVERSIONS=0>
|
||||
$<$<BOOL:${JSON_DisableEnumSerialization}>:JSON_DISABLE_ENUM_SERIALIZATION=1>
|
||||
$<$<BOOL:${JSON_Diagnostics}>:JSON_DIAGNOSTICS=1>
|
||||
$<$<BOOL:${JSON_Diagnostic_Positions}>:JSON_DIAGNOSTIC_POSITIONS=1>
|
||||
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
|
||||
)
|
||||
|
||||
|
51
docs/examples/diagnostic_positions.cpp
Normal file
51
docs/examples/diagnostic_positions.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include <iostream>
|
||||
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 1
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string json_string = R"(
|
||||
{
|
||||
"address": {
|
||||
"street": "Fake Street",
|
||||
"housenumber": 1
|
||||
}
|
||||
}
|
||||
)";
|
||||
json j = json::parse(json_string);
|
||||
|
||||
std::cout << "Root diagnostic positions: \n";
|
||||
std::cout << "\tstart_pos: " << j.start_pos() << '\n';
|
||||
std::cout << "\tend_pos:" << j.end_pos() << "\n";
|
||||
std::cout << "Original string: \n";
|
||||
std::cout << "{\n \"address\": {\n \"street\": \"Fake Street\",\n \"housenumber\": 1\n }\n }" << "\n";
|
||||
std::cout << "Parsed string: \n";
|
||||
std::cout << json_string.substr(j.start_pos(), j.end_pos() - j.start_pos()) << "\n\n";
|
||||
|
||||
std::cout << "address diagnostic positions: \n";
|
||||
std::cout << "\tstart_pos:" << j["address"].start_pos() << '\n';
|
||||
std::cout << "\tend_pos:" << j["address"].end_pos() << "\n\n";
|
||||
std::cout << "Original string: \n";
|
||||
std::cout << "{ \"street\": \"Fake Street\",\n \"housenumber\": 1\n }" << "\n";
|
||||
std::cout << "Parsed string: \n";
|
||||
std::cout << json_string.substr(j["address"].start_pos(), j["address"].end_pos() - j["address"].start_pos()) << "\n\n";
|
||||
|
||||
std::cout << "street diagnostic positions: \n";
|
||||
std::cout << "\tstart_pos:" << j["address"]["street"].start_pos() << '\n';
|
||||
std::cout << "\tend_pos:" << j["address"]["street"].end_pos() << "\n\n";
|
||||
std::cout << "Original string: \n";
|
||||
std::cout << "\"Fake Street\"" << "\n";
|
||||
std::cout << "Parsed string: \n";
|
||||
std::cout << json_string.substr(j["address"]["street"].start_pos(), j["address"]["street"].end_pos() - j["address"]["street"].start_pos()) << "\n\n";
|
||||
|
||||
std::cout << "housenumber diagnostic positions: \n";
|
||||
std::cout << "\tstart_pos:" << j["address"]["housenumber"].start_pos() << '\n';
|
||||
std::cout << "\tend_pos:" << j["address"]["housenumber"].end_pos() << "\n\n";
|
||||
std::cout << "Original string: \n";
|
||||
std::cout << "1" << "\n";
|
||||
std::cout << "Parsed string: \n";
|
||||
std::cout << json_string.substr(j["address"]["housenumber"].start_pos(), j["address"]["housenumber"].end_pos() - j["address"]["housenumber"].start_pos()) << "\n\n";
|
||||
}
|
50
docs/examples/diagnostic_positions.output
Normal file
50
docs/examples/diagnostic_positions.output
Normal file
@ -0,0 +1,50 @@
|
||||
Root diagnostic positions:
|
||||
start_pos: 5
|
||||
end_pos:109
|
||||
Original string:
|
||||
{
|
||||
"address": {
|
||||
"street": "Fake Street",
|
||||
"housenumber": 1
|
||||
}
|
||||
}
|
||||
Parsed string:
|
||||
{
|
||||
"address": {
|
||||
"street": "Fake Street",
|
||||
"housenumber": 1
|
||||
}
|
||||
}
|
||||
|
||||
address diagnostic positions:
|
||||
start_pos:26
|
||||
end_pos:103
|
||||
|
||||
Original string:
|
||||
{ "street": "Fake Street",
|
||||
"housenumber": 1
|
||||
}
|
||||
Parsed string:
|
||||
{
|
||||
"street": "Fake Street",
|
||||
"housenumber": 1
|
||||
}
|
||||
|
||||
street diagnostic positions:
|
||||
start_pos:50
|
||||
end_pos:63
|
||||
|
||||
Original string:
|
||||
"Fake Street"
|
||||
Parsed string:
|
||||
"Fake Street"
|
||||
|
||||
housenumber diagnostic positions:
|
||||
start_pos:92
|
||||
end_pos:93
|
||||
|
||||
Original string:
|
||||
1
|
||||
Parsed string:
|
||||
1
|
||||
|
61
docs/mkdocs/docs/api/macros/json_diagnostic_positions.md
Normal file
61
docs/mkdocs/docs/api/macros/json_diagnostic_positions.md
Normal file
@ -0,0 +1,61 @@
|
||||
# JSON_DIAGNOSTIC_POSITIONS
|
||||
|
||||
```cpp
|
||||
#define JSON_DIAGNOSTIC_POSITIONS /* value */
|
||||
```
|
||||
|
||||
This macro enables position diagnostics for generated JSON objects.
|
||||
|
||||
When enabled, two new properties: `start_pos()` and `end_pos()` are added to `nlohmann::basic_json` objects and fields. `start_pos()` returns the start
|
||||
position of that JSON object/field in the original string the object was parsed from. Likewise, `end_pos()` returns the end position of that JSON
|
||||
object/field in the original string the object was parsed from.
|
||||
|
||||
`start_pos()` returns the first character of a given element in the original JSON string, while `end_pos()` returns the character following the last
|
||||
character. For objects and arrays, the first and last characters correspond to the opening or closing braces/brackets, respectively. For fields, the first
|
||||
and last character represent the opening and closing quotes or the first and last character of the field's numerical or predefined value
|
||||
(true/false/null), respectively.
|
||||
|
||||
Given the above, `end_pos() - start_pos()` for an object or field provides the length of the string representation for that object or field, including the
|
||||
opening or closing braces, brackets, or quotes.
|
||||
|
||||
`start_pos()` and `end_pos()` are only set if the JSON object was parsed using `parse()`. For all other cases, `std::string::npos` will be returned.
|
||||
|
||||
Note that enabling this macro increases the size of every JSON value by two `std::size_t` fields and adds
|
||||
slight runtime overhead.
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is `0` (position diagnostics are switched off).
|
||||
|
||||
```cpp
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
```
|
||||
|
||||
When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! hint "CMake option"
|
||||
|
||||
Diagnostic messages can also be controlled with the CMake option
|
||||
[`JSON_Diagnostic_Positions`](../../integration/cmake.md#json_diagnostic_positions) (`OFF` by default)
|
||||
which defines `JSON_DIAGNOSTIC_POSITIONS` accordingly.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example 1: retrieving positions"
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/diagnostic_positions.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
--8<-- "examples/diagnostic_positions.output"
|
||||
```
|
||||
|
||||
The output shows the start/end positions of all the objects and fields in the JSON string.
|
||||
|
||||
## Version history
|
||||
|
@ -135,6 +135,9 @@ Enable CI build targets. The exact targets are used during the several CI steps
|
||||
|
||||
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.
|
||||
|
||||
### `JSON_Diagnostic_Positions`
|
||||
Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md). This option is off by default.
|
||||
|
||||
### `JSON_DisableEnumSerialization`
|
||||
|
||||
Disable default `enum` serialization by defining the macro
|
||||
|
@ -26,6 +26,10 @@
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DIAGNOSTIC_POSITIONS
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
@ -36,6 +40,12 @@
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
@ -47,14 +57,15 @@
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
|
@ -65,7 +65,7 @@ static inline bool little_endianness(int num = 1) noexcept
|
||||
/*!
|
||||
@brief deserialization of CBOR, MessagePack, and UBJSON values
|
||||
*/
|
||||
template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
|
||||
template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType, InputAdapterType>>
|
||||
class binary_reader
|
||||
{
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
|
@ -462,6 +462,9 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory<C
|
||||
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
|
||||
}
|
||||
|
||||
// specialization for std::string
|
||||
using string_input_adapter_type = decltype(input_adapter(std::declval<std::string>()));
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
// Special cases with fast paths
|
||||
inline file_input_adapter input_adapter(std::FILE* file)
|
||||
|
@ -10,13 +10,14 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string> // string
|
||||
#include <type_traits> // enable_if_t
|
||||
#include <utility> // move
|
||||
#include <vector> // vector
|
||||
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
#include <nlohmann/detail/input/lexer.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/*!
|
||||
@ -157,7 +158,7 @@ constructor contains the parsed value.
|
||||
|
||||
@tparam BasicJsonType the JSON type
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
template<typename BasicJsonType, typename InputAdapterType>
|
||||
class json_sax_dom_parser
|
||||
{
|
||||
public:
|
||||
@ -166,14 +167,15 @@ class json_sax_dom_parser
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using binary_t = typename BasicJsonType::binary_t;
|
||||
using lexer_t = lexer<BasicJsonType, InputAdapterType>;
|
||||
|
||||
/*!
|
||||
@param[in,out] r reference to a JSON value that is manipulated while
|
||||
parsing
|
||||
@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_)
|
||||
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_)
|
||||
{}
|
||||
|
||||
// make class move-only
|
||||
@ -229,6 +231,17 @@ class json_sax_dom_parser
|
||||
{
|
||||
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Manually set the start position of the object here.
|
||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer has read the first character of the object, so
|
||||
// subtract 1 from the position to get the correct start position.
|
||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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()));
|
||||
@ -252,6 +265,14 @@ class json_sax_dom_parser
|
||||
JSON_ASSERT(!ref_stack.empty());
|
||||
JSON_ASSERT(ref_stack.back()->is_object());
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer's position is past the closing brace, so set that as the end position.
|
||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||
}
|
||||
#endif
|
||||
|
||||
ref_stack.back()->set_parents();
|
||||
ref_stack.pop_back();
|
||||
return true;
|
||||
@ -261,6 +282,15 @@ class json_sax_dom_parser
|
||||
{
|
||||
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Manually set the start position of the array here.
|
||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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()));
|
||||
@ -274,6 +304,14 @@ class json_sax_dom_parser
|
||||
JSON_ASSERT(!ref_stack.empty());
|
||||
JSON_ASSERT(ref_stack.back()->is_array());
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer's position is past the closing bracket, so set that as the end position.
|
||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||
}
|
||||
#endif
|
||||
|
||||
ref_stack.back()->set_parents();
|
||||
ref_stack.pop_back();
|
||||
return true;
|
||||
@ -298,6 +336,75 @@ class json_sax_dom_parser
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
void handle_diagnostic_positions_for_json_value(BasicJsonType& v)
|
||||
{
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer has read past the current field value, so set the end position to the current position.
|
||||
// The start position will be set below based on the length of the string representation
|
||||
// of the value.
|
||||
v.end_position = m_lexer_ref->get_position();
|
||||
|
||||
switch (v.type())
|
||||
{
|
||||
case value_t::boolean:
|
||||
{
|
||||
// 4 and 5 are the string length of "true" and "false"
|
||||
v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5);
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::null:
|
||||
{
|
||||
// 4 is the string length of "null"
|
||||
v.start_position = v.end_position - 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// As we handle the start and end positions for values created during parsing,
|
||||
// we do not expect the following value type to be called. Regardless, set the positions
|
||||
// in case this is created manually or through a different constructor. Exclude from lcov
|
||||
// since the exact condition of this switch is esoteric.
|
||||
// LCOV_EXCL_START
|
||||
case value_t::discarded:
|
||||
{
|
||||
v.end_position = std::string::npos;
|
||||
v.start_position = v.end_position;
|
||||
break;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
case value_t::binary:
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
case value_t::number_float:
|
||||
{
|
||||
v.start_position = v.end_position - m_lexer_ref->get_string().size();
|
||||
break;
|
||||
}
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
{
|
||||
// object and array are handled in start_object() and start_array() handlers
|
||||
// skip setting the values here.
|
||||
break;
|
||||
}
|
||||
default: // LCOV_EXCL_LINE
|
||||
// Handle all possible types discretely, default handler should never be reached.
|
||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@invariant If the ref stack is empty, then the passed value will be the new
|
||||
root.
|
||||
@ -311,6 +418,11 @@ class json_sax_dom_parser
|
||||
if (ref_stack.empty())
|
||||
{
|
||||
root = BasicJsonType(std::forward<Value>(v));
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
handle_diagnostic_positions_for_json_value(root);
|
||||
#endif
|
||||
|
||||
return &root;
|
||||
}
|
||||
|
||||
@ -319,12 +431,22 @@ class json_sax_dom_parser
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back());
|
||||
#endif
|
||||
|
||||
return &(ref_stack.back()->m_data.m_value.array->back());
|
||||
}
|
||||
|
||||
JSON_ASSERT(ref_stack.back()->is_object());
|
||||
JSON_ASSERT(object_element);
|
||||
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
handle_diagnostic_positions_for_json_value(*object_element);
|
||||
#endif
|
||||
|
||||
return object_element;
|
||||
}
|
||||
|
||||
@ -338,9 +460,11 @@ class json_sax_dom_parser
|
||||
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>
|
||||
template<typename BasicJsonType, typename InputAdapterType>
|
||||
class json_sax_dom_callback_parser
|
||||
{
|
||||
public:
|
||||
@ -351,11 +475,13 @@ class json_sax_dom_callback_parser
|
||||
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;
|
||||
using lexer_t = lexer<BasicJsonType, InputAdapterType>;
|
||||
|
||||
json_sax_dom_callback_parser(BasicJsonType& r,
|
||||
parser_callback_t cb,
|
||||
const bool allow_exceptions_ = true)
|
||||
: root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_)
|
||||
const bool allow_exceptions_ = true,
|
||||
lexer_t* lexer_ = nullptr)
|
||||
: root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)
|
||||
{
|
||||
keep_stack.push_back(true);
|
||||
}
|
||||
@ -418,12 +544,26 @@ class json_sax_dom_callback_parser
|
||||
auto val = handle_value(BasicJsonType::value_t::object, true);
|
||||
ref_stack.push_back(val.second);
|
||||
|
||||
if (ref_stack.back())
|
||||
{
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Manually set the start position of the object here.
|
||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer has read the first character of the object, so
|
||||
// subtract 1 from the position to get the correct start position.
|
||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// check object limit
|
||||
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
|
||||
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()));
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -452,9 +592,23 @@ class json_sax_dom_callback_parser
|
||||
{
|
||||
// discard object
|
||||
*ref_stack.back() = discarded;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Set start/end positions for discarded object.
|
||||
handle_diagnostic_positions_for_json_value(*ref_stack.back());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer's position is past the closing brace, so set that as the end position.
|
||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||
}
|
||||
#endif
|
||||
|
||||
ref_stack.back()->set_parents();
|
||||
}
|
||||
}
|
||||
@ -488,11 +642,26 @@ class json_sax_dom_callback_parser
|
||||
auto val = handle_value(BasicJsonType::value_t::array, true);
|
||||
ref_stack.push_back(val.second);
|
||||
|
||||
if (ref_stack.back())
|
||||
{
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Manually set the start position of the array here.
|
||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer has read the first character of the array, so
|
||||
// subtract 1 from the position to get the correct start position.
|
||||
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// check array limit
|
||||
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -506,12 +675,26 @@ class json_sax_dom_callback_parser
|
||||
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
|
||||
if (keep)
|
||||
{
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer's position is past the closing bracket, so set that as the end position.
|
||||
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||
}
|
||||
#endif
|
||||
|
||||
ref_stack.back()->set_parents();
|
||||
}
|
||||
else
|
||||
{
|
||||
// discard array
|
||||
*ref_stack.back() = discarded;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// Set start/end positions for discarded array.
|
||||
handle_diagnostic_positions_for_json_value(*ref_stack.back());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -548,6 +731,71 @@ class json_sax_dom_callback_parser
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
void handle_diagnostic_positions_for_json_value(BasicJsonType& v)
|
||||
{
|
||||
if (m_lexer_ref)
|
||||
{
|
||||
// Lexer has read past the current field value, so set the end position to the current position.
|
||||
// The start position will be set below based on the length of the string representation
|
||||
// of the value.
|
||||
v.end_position = m_lexer_ref->get_position();
|
||||
|
||||
switch (v.type())
|
||||
{
|
||||
case value_t::boolean:
|
||||
{
|
||||
// 4 and 5 are the string length of "true" and "false"
|
||||
v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5);
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::null:
|
||||
{
|
||||
// 4 is the string length of "null"
|
||||
v.start_position = v.end_position - 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::discarded:
|
||||
{
|
||||
v.end_position = std::string::npos;
|
||||
v.start_position = v.end_position;
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::binary:
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
case value_t::number_float:
|
||||
{
|
||||
v.start_position = v.end_position - m_lexer_ref->get_string().size();
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
{
|
||||
// object and array are handled in start_object() and start_array() handlers
|
||||
// skip setting the values here.
|
||||
break;
|
||||
}
|
||||
default: // LCOV_EXCL_LINE
|
||||
// Handle all possible types discretely, default handler should never be reached.
|
||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@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
|
||||
@ -578,6 +826,10 @@ class json_sax_dom_callback_parser
|
||||
// create value
|
||||
auto value = BasicJsonType(std::forward<Value>(v));
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
handle_diagnostic_positions_for_json_value(value);
|
||||
#endif
|
||||
|
||||
// check callback
|
||||
const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
|
||||
|
||||
@ -645,6 +897,8 @@ class json_sax_dom_callback_parser
|
||||
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
|
||||
lexer_t* m_lexer_ref = nullptr;
|
||||
};
|
||||
|
||||
template<typename BasicJsonType>
|
||||
|
@ -94,7 +94,7 @@ class parser
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
|
||||
json_sax_dom_callback_parser<BasicJsonType, InputAdapterType> sdp(result, callback, allow_exceptions, &m_lexer);
|
||||
sax_parse_internal(&sdp);
|
||||
|
||||
// in strict mode, input must be completely read
|
||||
@ -122,7 +122,7 @@ class parser
|
||||
}
|
||||
else
|
||||
{
|
||||
json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
|
||||
json_sax_dom_parser<BasicJsonType, InputAdapterType> sdp(result, allow_exceptions, &m_lexer);
|
||||
sax_parse_internal(&sdp);
|
||||
|
||||
// in strict mode, input must be completely read
|
||||
|
@ -115,9 +115,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
friend class ::nlohmann::detail::binary_writer;
|
||||
template<typename BasicJsonType, typename InputType, typename SAX>
|
||||
friend class ::nlohmann::detail::binary_reader;
|
||||
template<typename BasicJsonType>
|
||||
template<typename BasicJsonType, typename InputAdapterType>
|
||||
friend class ::nlohmann::detail::json_sax_dom_parser;
|
||||
template<typename BasicJsonType>
|
||||
template<typename BasicJsonType, typename InputAdapterType>
|
||||
friend class ::nlohmann::detail::json_sax_dom_callback_parser;
|
||||
friend class ::nlohmann::detail::exception;
|
||||
|
||||
@ -848,6 +848,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
|
||||
basic_json(const BasicJsonType& val)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
: start_position(val.start_position),
|
||||
end_position(val.end_position)
|
||||
#endif
|
||||
{
|
||||
using other_boolean_t = typename BasicJsonType::boolean_t;
|
||||
using other_number_float_t = typename BasicJsonType::number_float_t;
|
||||
@ -894,6 +898,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||
}
|
||||
JSON_ASSERT(m_data.m_type == val.type());
|
||||
|
||||
set_parents();
|
||||
assert_invariant();
|
||||
}
|
||||
@ -1145,6 +1150,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
basic_json(const basic_json& other)
|
||||
: json_base_class_t(other)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
, start_position(other.start_position)
|
||||
, end_position(other.end_position)
|
||||
#endif
|
||||
{
|
||||
m_data.m_type = other.m_data.m_type;
|
||||
// check of passed value is valid
|
||||
@ -1215,6 +1224,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
basic_json(basic_json&& other) noexcept
|
||||
: json_base_class_t(std::forward<json_base_class_t>(other)),
|
||||
m_data(std::move(other.m_data)) // cppcheck-suppress[accessForwarded] TODO check
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
, start_position(other.start_position) // cppcheck-suppress[accessForwarded] TODO check
|
||||
, end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check
|
||||
#endif
|
||||
{
|
||||
// check that passed value is valid
|
||||
other.assert_invariant(false); // cppcheck-suppress[accessForwarded]
|
||||
@ -1223,6 +1236,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
other.m_data.m_type = value_t::null;
|
||||
other.m_data.m_value = {};
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
other.start_position = std::string::npos;
|
||||
other.end_position = std::string::npos;
|
||||
#endif
|
||||
|
||||
set_parents();
|
||||
assert_invariant();
|
||||
}
|
||||
@ -1243,6 +1261,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
using std::swap;
|
||||
swap(m_data.m_type, other.m_data.m_type);
|
||||
swap(m_data.m_value, other.m_data.m_value);
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
swap(start_position, other.start_position);
|
||||
swap(end_position, other.end_position);
|
||||
#endif
|
||||
|
||||
json_base_class_t::operator=(std::move(other));
|
||||
|
||||
set_parents();
|
||||
@ -4226,6 +4250,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
basic_json* m_parent = nullptr;
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// the start position of the value
|
||||
std::size_t start_position = std::string::npos;
|
||||
/// the end position of the value
|
||||
std::size_t end_position = std::string::npos;
|
||||
public:
|
||||
constexpr std::size_t start_pos() const noexcept
|
||||
{
|
||||
return start_position;
|
||||
}
|
||||
|
||||
constexpr std::size_t end_pos() const noexcept
|
||||
{
|
||||
return end_position;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////
|
||||
// binary serialization/deserialization //
|
||||
//////////////////////////////////////////
|
||||
@ -4367,8 +4408,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4383,8 +4424,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4408,8 +4449,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = i.get();
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
@ -4424,8 +4465,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4439,8 +4480,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4462,8 +4503,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = i.get();
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
@ -4478,8 +4519,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4493,8 +4534,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4516,8 +4557,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = i.get();
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
@ -4532,8 +4573,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4547,8 +4588,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4562,8 +4603,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4577,8 +4618,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
@ -4600,8 +4641,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
basic_json result;
|
||||
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
|
||||
auto ia = i.get();
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,10 @@
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DIAGNOSTIC_POSITIONS
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
@ -54,6 +58,12 @@
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
@ -65,14 +75,15 @@
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
|
@ -1631,7 +1631,7 @@ TEST_CASE("CBOR")
|
||||
};
|
||||
|
||||
json j;
|
||||
auto cbp = nlohmann::detail::json_sax_dom_callback_parser<json>(j, callback, true);
|
||||
auto cbp = nlohmann::detail::json_sax_dom_callback_parser<json, nlohmann::detail::string_input_adapter_type>(j, callback, true);
|
||||
CHECK(json::sax_parse(input, &cbp, json::input_format_t::cbor));
|
||||
CHECK(j.at("foo").is_binary());
|
||||
CHECK(binary_seen);
|
||||
|
@ -219,7 +219,7 @@ json parser_helper(const std::string& s)
|
||||
CHECK(j_nothrow == j);
|
||||
|
||||
json j_sax;
|
||||
nlohmann::detail::json_sax_dom_parser<json> sdp(j_sax);
|
||||
nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type> sdp(j_sax);
|
||||
json::sax_parse(s, &sdp);
|
||||
CHECK(j_sax == j);
|
||||
|
||||
|
1957
tests/src/unit-class_parser_diagnostic_positions.cpp
Normal file
1957
tests/src/unit-class_parser_diagnostic_positions.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -587,7 +587,7 @@ TEST_CASE("deserialization")
|
||||
auto first = str.begin();
|
||||
auto last = str.end();
|
||||
json j;
|
||||
json_sax_dom_parser<json> sax(j, true);
|
||||
json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type> sax(j, true);
|
||||
|
||||
CHECK(json::sax_parse(proxy(first), proxy(last), &sax,
|
||||
input_format_t::json, false));
|
||||
|
@ -19,10 +19,10 @@ using json = nlohmann::json;
|
||||
// for #2824
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type>
|
||||
{
|
||||
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, nlohmann::detail::string_input_adapter_type>(j, false) {}
|
||||
|
||||
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
|
||||
{
|
||||
|
@ -162,11 +162,11 @@ struct adl_serializer<NonDefaultConstructible>
|
||||
// for #2824
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type>
|
||||
{
|
||||
public:
|
||||
explicit sax_no_exception(json& j)
|
||||
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
|
||||
: nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type>(j, false)
|
||||
{}
|
||||
|
||||
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
|
||||
|
@ -1617,7 +1617,7 @@ TEST_CASE("UBJSON")
|
||||
CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&);
|
||||
|
||||
json j;
|
||||
nlohmann::detail::json_sax_dom_callback_parser<json> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
|
||||
nlohmann::detail::json_sax_dom_callback_parser<json, decltype(nlohmann::detail::input_adapter(v_ubjson))> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
|
||||
{
|
||||
return true;
|
||||
});
|
||||
@ -1631,7 +1631,7 @@ TEST_CASE("UBJSON")
|
||||
CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&);
|
||||
|
||||
json j;
|
||||
nlohmann::detail::json_sax_dom_callback_parser<json> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
|
||||
nlohmann::detail::json_sax_dom_callback_parser<json, decltype(nlohmann::detail::input_adapter(v_ubjson))> scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
|
||||
{
|
||||
return true;
|
||||
});
|
||||
|
Reference in New Issue
Block a user