diff --git a/README.md b/README.md index 19d8f722c3..5d354f1ed1 100644 --- a/README.md +++ b/README.md @@ -577,7 +577,7 @@ j[1] = 42; bool foo = j.at(2); // comparison -j == "[\"foo\", 42, true]"_json; // true +j == "[\"foo\", 42, true, 1.78]"_json; // true // other stuff j.size(); // 3 entries @@ -1528,6 +1528,7 @@ I deeply appreciate the help of the following people. - [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. - [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support. - [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`. +- [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. @@ -1637,4 +1638,6 @@ In case you have downloaded the library rather than checked out the code via Git Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. +Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information. + As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html) then. diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index c632ff2bea..49ed0f913e 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -490,51 +490,49 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) return 10; } // LCOV_EXCL_STOP - else if (n >= 100000000) + if (n >= 100000000) { pow10 = 100000000; return 9; } - else if (n >= 10000000) + if (n >= 10000000) { pow10 = 10000000; return 8; } - else if (n >= 1000000) + if (n >= 1000000) { pow10 = 1000000; return 7; } - else if (n >= 100000) + if (n >= 100000) { pow10 = 100000; return 6; } - else if (n >= 10000) + if (n >= 10000) { pow10 = 10000; return 5; } - else if (n >= 1000) + if (n >= 1000) { pow10 = 1000; return 4; } - else if (n >= 100) + if (n >= 100) { pow10 = 100; return 3; } - else if (n >= 10) + if (n >= 10) { pow10 = 10; return 2; } - else - { - pow10 = 1; - return 1; - } + + pow10 = 1; + return 1; } inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index a78a6ec96c..c437564fd0 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -135,10 +135,8 @@ class iterator_input_adapter std::advance(current, 1); return result; } - else - { - return std::char_traits::eof(); - } + + return std::char_traits::eof(); } private: diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 3d04f95443..6ebc095bfb 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -386,8 +386,9 @@ class parser m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), BasicJsonType())); } - else // object - { + + // states.back() is false -> object + // comma -> next value if (get_token() == token_type::value_separator) { @@ -397,12 +398,12 @@ class parser return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); - } + } - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } // parse separator (:) if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) @@ -410,35 +411,34 @@ class parser return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); - } - - // parse values - get_token(); - continue; } - // closing } - if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) - { - return false; - } + // parse values + get_token(); + continue; + } - // We are done with this object. Before we can parse a - // new value, we need to evaluate the new state first. - // By setting skip_to_state_evaluation to false, we - // are effectively jumping to the beginning of this if. - JSON_ASSERT(!states.empty()); - states.pop_back(); - skip_to_state_evaluation = true; - continue; + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; } + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), BasicJsonType())); - } } } diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp index 74b4eb347f..1b47faeb3e 100644 --- a/include/nlohmann/detail/iterators/iteration_proxy.hpp +++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -39,7 +39,7 @@ template class iteration_proxy_value /// a string representation of the array index mutable string_type array_index_str = "0"; /// an empty string (to return a reference for primitive values) - const string_type empty_str = ""; + const string_type empty_str{}; public: explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e11cbd34cd..30dd96f43e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -73,93 +73,35 @@ SOFTWARE. #include // runtime_error #include // to_string -// #include +// #include -#include // array #include // size_t -#include // uint8_t -#include // string namespace nlohmann { namespace detail { -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - binary, ///< binary array (ordered collection of bytes) - discarded ///< discarded by the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string < binary -- furthermore, each type is not smaller than itself -- discarded values are not comparable -- binary is represented as a b"" string in python and directly comparable to a - string; however, making a binary array directly comparable with a string would - be surprising behavior in a JSON file. - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept +/// struct to capture the start position of the current token +struct position_t { - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, - 6 /* binary */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; -} -} // namespace detail -} // namespace nlohmann + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; -// #include + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; +} // namespace detail +} // namespace nlohmann -#include // #include @@ -2438,97 +2380,6 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif -namespace nlohmann -{ -namespace detail -{ - -/*! -@brief replace all occurrences of a substring by another string - -@param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t -@param[in] f the substring to replace with @a t -@param[in] t the string to replace @a f - -@pre The search string @a f must not be empty. **This precondition is -enforced with an assertion.** - -@since version 2.0.0 -*/ -inline void replace_substring(std::string& s, const std::string& f, - const std::string& t) -{ - JSON_ASSERT(!f.empty()); - for (auto pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} -} - -/*! - * @brief string escaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to escape - * @return escaped string - * - * Note the order of escaping "~" to "~0" and "/" to "~1" is important. - */ -inline std::string escape(std::string s) -{ - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; -} - -/*! - * @brief string unescaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to unescape - * @return unescaped string - * - * Note the order of escaping "~1" to "/" and "~0" to "~" is important. - */ -static void unescape(std::string& s) -{ - replace_substring(s, "~1", "/"); - replace_substring(s, "~0", "~"); -} - -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // size_t - -namespace nlohmann -{ -namespace detail -{ -/// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; - - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } -}; - -} // namespace detail -} // namespace nlohmann - -// #include - - namespace nlohmann { namespace detail @@ -2587,61 +2438,6 @@ class exception : public std::exception return "[json.exception." + ename + "." + std::to_string(id_) + "] "; } - template - static std::string diagnostics(const BasicJsonType& leaf_element) - { -#if JSON_DIAGNOSTICS - std::vector tokens; - for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent) - { - switch (current->m_parent->type()) - { - case value_t::array: - { - for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) - { - if (¤t->m_parent->m_value.array->operator[](i) == current) - { - tokens.emplace_back(std::to_string(i)); - break; - } - } - break; - } - - case value_t::object: - { - for (const auto& element : *current->m_parent->m_value.object) - { - if (&element.second == current) - { - tokens.emplace_back(element.first.c_str()); - break; - } - } - break; - } - - default: // LCOV_EXCL_LINE - break; // LCOV_EXCL_LINE - } - } - - if (tokens.empty()) - { - return ""; - } - - return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + detail::escape(b); - }) + ") "; -#else - return ""; -#endif - } - private: /// an exception object as storage for error messages std::runtime_error m; @@ -2704,20 +2500,18 @@ class parse_error : public exception @param[in] what_arg the explanatory string @return parse_error object */ - template - static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context) + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + - position_string(pos) + ": " + exception::diagnostics(context) + what_arg; + position_string(pos) + ": " + what_arg; return parse_error(id_, pos.chars_read_total, w.c_str()); } - template - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context) + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + - ": " + exception::diagnostics(context) + what_arg; + ": " + what_arg; return parse_error(id_, byte_, w.c_str()); } @@ -2783,10 +2577,9 @@ caught.,invalid_iterator} class invalid_iterator : public exception { public: - template - static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context) + static invalid_iterator create(int id_, const std::string& what_arg) { - std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("invalid_iterator", id_) + what_arg; return invalid_iterator(id_, w.c_str()); } @@ -2838,10 +2631,9 @@ caught.,type_error} class type_error : public exception { public: - template - static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context) + static type_error create(int id_, const std::string& what_arg) { - std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("type_error", id_) + what_arg; return type_error(id_, w.c_str()); } @@ -2886,10 +2678,9 @@ caught.,out_of_range} class out_of_range : public exception { public: - template - static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context) + static out_of_range create(int id_, const std::string& what_arg) { - std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("out_of_range", id_) + what_arg; return out_of_range(id_, w.c_str()); } @@ -2925,10 +2716,9 @@ caught.,other_error} class other_error : public exception { public: - template - static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context) + static other_error create(int id_, const std::string& what_arg) { - std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("other_error", id_) + what_arg; return other_error(id_, w.c_str()); } @@ -3633,6 +3423,87 @@ struct is_constructible_tuple> : conjunction +#include // array +#include // size_t +#include // uint8_t +#include // string + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +} +} // namespace detail +} // namespace nlohmann + + namespace nlohmann { namespace detail @@ -3642,7 +3513,7 @@ void from_json(const BasicJsonType& j, typename std::nullptr_t& n) { if (JSON_HEDLEY_UNLIKELY(!j.is_null())) { - JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); } n = nullptr; } @@ -3673,7 +3544,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) } default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); } } @@ -3682,7 +3553,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) { if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); } b = *j.template get_ptr(); } @@ -3692,7 +3563,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); } s = *j.template get_ptr(); } @@ -3708,7 +3579,7 @@ void from_json(const BasicJsonType& j, ConstructibleStringType& s) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); } s = *j.template get_ptr(); @@ -3748,7 +3619,7 @@ void from_json(const BasicJsonType& j, std::forward_list& l) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } l.clear(); std::transform(j.rbegin(), j.rend(), @@ -3765,7 +3636,7 @@ void from_json(const BasicJsonType& j, std::valarray& l) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } l.resize(j.size()); std::transform(j.begin(), j.end(), std::begin(l), @@ -3856,7 +3727,8 @@ void()) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); } from_json_array_impl(j, arr, priority_tag<3> {}); @@ -3867,7 +3739,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) { if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); } bin = *j.template get_ptr(); @@ -3879,7 +3751,7 @@ void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) { if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); } ConstructibleObjectType ret; @@ -3933,7 +3805,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) } default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); } } @@ -3962,14 +3834,14 @@ void from_json(const BasicJsonType& j, std::map& { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } m.clear(); for (const auto& p : j) { if (JSON_HEDLEY_UNLIKELY(!p.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); } m.emplace(p.at(0).template get(), p.at(1).template get()); } @@ -3982,14 +3854,14 @@ void from_json(const BasicJsonType& j, std::unordered_map(), p.at(1).template get()); } @@ -4072,7 +3944,7 @@ template class iteration_proxy_value /// a string representation of the array index mutable string_type array_index_str = "0"; /// an empty string (to return a reference for primitive values) - const string_type empty_str = ""; + const string_type empty_str{}; public: explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} @@ -4335,7 +4207,6 @@ struct external_constructor { j.m_type = value_t::array; j.m_value = arr; - j.set_parents(); j.assert_invariant(); } @@ -4344,7 +4215,6 @@ struct external_constructor { j.m_type = value_t::array; j.m_value = std::move(arr); - j.set_parents(); j.assert_invariant(); } @@ -4357,7 +4227,6 @@ struct external_constructor using std::end; j.m_type = value_t::array; j.m_value.array = j.template create(begin(arr), end(arr)); - j.set_parents(); j.assert_invariant(); } @@ -4370,7 +4239,6 @@ struct external_constructor for (const bool x : arr) { j.m_value.array->push_back(x); - j.set_parent(j.m_value.array->back()); } j.assert_invariant(); } @@ -4386,7 +4254,6 @@ struct external_constructor { std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); } - j.set_parents(); j.assert_invariant(); } }; @@ -4399,7 +4266,6 @@ struct external_constructor { j.m_type = value_t::object; j.m_value = obj; - j.set_parents(); j.assert_invariant(); } @@ -4408,7 +4274,6 @@ struct external_constructor { j.m_type = value_t::object; j.m_value = std::move(obj); - j.set_parents(); j.assert_invariant(); } @@ -4421,7 +4286,6 @@ struct external_constructor j.m_type = value_t::object; j.m_value.object = j.template create(begin(obj), end(obj)); - j.set_parents(); j.assert_invariant(); } }; @@ -5083,10 +4947,8 @@ class iterator_input_adapter std::advance(current, 1); return result; } - else - { - return std::char_traits::eof(); - } + + return std::char_traits::eof(); } private: @@ -5647,7 +5509,8 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); + JSON_THROW(out_of_range::create(408, + "excessive object size: " + std::to_string(len))); } return true; @@ -5662,7 +5525,6 @@ class json_sax_dom_parser bool end_object() { - ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; } @@ -5673,7 +5535,8 @@ class json_sax_dom_parser if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); + JSON_THROW(out_of_range::create(408, + "excessive array size: " + std::to_string(len))); } return true; @@ -5681,7 +5544,6 @@ class json_sax_dom_parser bool end_array() { - ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; } @@ -5828,7 +5690,7 @@ class json_sax_dom_callback_parser // check object limit if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); + JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); } return true; @@ -5853,17 +5715,10 @@ class json_sax_dom_callback_parser bool end_object() { - if (ref_stack.back()) + if (ref_stack.back() && !callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) { - if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) - { - // discard object - *ref_stack.back() = discarded; - } - else - { - ref_stack.back()->set_parents(); - } + // discard object + *ref_stack.back() = discarded; } JSON_ASSERT(!ref_stack.empty()); @@ -5898,7 +5753,7 @@ class json_sax_dom_callback_parser // check array limit if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { - JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); + JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); } return true; @@ -5911,11 +5766,7 @@ class json_sax_dom_callback_parser if (ref_stack.back()) { keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); - if (keep) - { - ref_stack.back()->set_parents(); - } - else + if (!keep) { // discard array *ref_stack.back() = discarded; @@ -6013,7 +5864,7 @@ class json_sax_dom_callback_parser // array if (ref_stack.back()->is_array()) { - ref_stack.back()->m_value.array->emplace_back(std::move(value)); + ref_stack.back()->m_value.array->push_back(std::move(value)); return {true, &(ref_stack.back()->m_value.array->back())}; } @@ -8035,7 +7886,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current != std::char_traits::eof())) { return sax->parse_error(chars_read, get_token_string(), - parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"), BasicJsonType())); + parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"))); } } @@ -8111,7 +7962,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(len < 1)) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"))); } return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); @@ -8132,7 +7983,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(len < 0)) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } // All BSON binary values have a subtype @@ -8214,7 +8065,7 @@ class binary_reader { std::array cr{{}}; (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); - return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType())); + return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()))); } } } @@ -8614,7 +8465,7 @@ class binary_reader case cbor_tag_handler_t::error: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); } case cbor_tag_handler_t::ignore: @@ -8729,7 +8580,7 @@ class binary_reader default: // anything else (0xFF is handled inside the other types) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); } } } @@ -8824,7 +8675,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"))); } } } @@ -8923,7 +8774,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"))); } } } @@ -9390,7 +9241,7 @@ class binary_reader default: // anything else { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"))); } } } @@ -9472,7 +9323,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"))); } } } @@ -9722,7 +9573,7 @@ class binary_reader default: auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"))); } } @@ -9792,7 +9643,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"))); } } } @@ -9830,7 +9681,7 @@ class binary_reader return false; } auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"))); } return get_ubjson_size_value(result.first); @@ -9920,7 +9771,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current > 127)) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"))); } string_t s(1, static_cast(current)); return sax->string(s); @@ -9941,7 +9792,7 @@ class binary_reader default: // anything else { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"))); } } } @@ -10119,7 +9970,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) { - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); } switch (result_number) @@ -10131,7 +9982,7 @@ class binary_reader case token_type::value_float: return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); default: - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); } } @@ -10287,7 +10138,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current == std::char_traits::eof())) { return sax->parse_error(chars_read, "", - parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), BasicJsonType())); + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context))); } return true; } @@ -10460,6 +10311,7 @@ class parser { json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); sax_parse_internal(&sdp); + result.assert_invariant(); // in strict mode, input must be completely read if (strict && (get_token() != token_type::end_of_input)) @@ -10467,7 +10319,7 @@ class parser sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), - exception_message(token_type::end_of_input, "value"), BasicJsonType())); + exception_message(token_type::end_of_input, "value"))); } // in case of an error, return discarded value @@ -10488,13 +10340,15 @@ class parser { json_sax_dom_parser sdp(result, allow_exceptions); sax_parse_internal(&sdp); + result.assert_invariant(); // in strict mode, input must be completely read if (strict && (get_token() != token_type::end_of_input)) { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } // in case of an error, return discarded value @@ -10504,8 +10358,6 @@ class parser return; } } - - result.assert_invariant(); } /*! @@ -10532,7 +10384,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } return result; @@ -10578,7 +10431,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); } if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) { @@ -10590,7 +10444,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); } // remember we are now inside an object @@ -10633,7 +10488,7 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'", BasicJsonType())); + out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); } if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) @@ -10703,14 +10558,16 @@ class parser // using "uninitialized" to avoid "expected" message return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::uninitialized, "value"))); } default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::literal_or_value, "value"))); } } } @@ -10756,61 +10613,65 @@ class parser return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), BasicJsonType())); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_array, "array"))); } - else // object - { - // comma -> next value - if (get_token() == token_type::value_separator) - { - // parse key - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); - } - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } + // states.back() is false -> object - // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); - } + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); + } - // parse values - get_token(); - continue; + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; } - // closing } - if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) { - if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) - { - return false; - } + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); + } - // We are done with this object. Before we can parse a - // new value, we need to evaluate the new state first. - // By setting skip_to_state_evaluation to false, we - // are effectively jumping to the beginning of this if. - JSON_ASSERT(!states.empty()); - states.pop_back(); - skip_to_state_evaluation = true; - continue; + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; } - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), BasicJsonType())); + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_object, "object"))); } } @@ -11281,7 +11142,7 @@ class iter_impl } case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + JSON_THROW(invalid_iterator::create(214, "cannot get value")); default: { @@ -11290,7 +11151,7 @@ class iter_impl return *m_object; } - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + JSON_THROW(invalid_iterator::create(214, "cannot get value")); } } } @@ -11324,7 +11185,7 @@ class iter_impl return m_object; } - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + JSON_THROW(invalid_iterator::create(214, "cannot get value")); } } } @@ -11425,7 +11286,7 @@ class iter_impl // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } JSON_ASSERT(m_object != nullptr); @@ -11462,7 +11323,7 @@ class iter_impl // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } JSON_ASSERT(m_object != nullptr); @@ -11470,7 +11331,7 @@ class iter_impl switch (m_object->m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", *m_object)); + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); case value_t::array: return (m_it.array_iterator < other.m_it.array_iterator); @@ -11518,7 +11379,7 @@ class iter_impl switch (m_object->m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); case value_t::array: { @@ -11589,7 +11450,7 @@ class iter_impl switch (m_object->m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); case value_t::array: return m_it.array_iterator - other.m_it.array_iterator; @@ -11610,13 +11471,13 @@ class iter_impl switch (m_object->m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", *m_object)); + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); case value_t::array: return *std::next(m_it.array_iterator, n); case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + JSON_THROW(invalid_iterator::create(214, "cannot get value")); default: { @@ -11625,7 +11486,7 @@ class iter_impl return *m_object; } - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + JSON_THROW(invalid_iterator::create(214, "cannot get value")); } } } @@ -11643,7 +11504,7 @@ class iter_impl return m_it.object_iterator->first; } - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", *m_object)); + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); } /*! @@ -11804,8 +11665,6 @@ class json_reverse_iterator : public std::reverse_iterator // #include -// #include - // #include @@ -11864,7 +11723,7 @@ class json_pointer std::string{}, [](const std::string & a, const std::string & b) { - return a + "/" + detail::escape(b); + return a + "/" + escape(b); }); } @@ -12044,7 +11903,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(empty())) { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); } reference_tokens.pop_back(); @@ -12068,7 +11927,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(empty())) { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); } return reference_tokens.back(); @@ -12134,13 +11993,15 @@ class json_pointer // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) { - JSON_THROW(detail::parse_error::create(106, 0, "array index '" + s + "' must not begin with '0'", BasicJsonType())); + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + s + + "' must not begin with '0'")); } // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number", BasicJsonType())); + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); } std::size_t processed_chars = 0; @@ -12151,20 +12012,20 @@ class json_pointer } JSON_CATCH(std::out_of_range&) { - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); } // check if the string was completely read if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) { - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); } // only triggered on special platforms (like 32bit), see also // https://github.com/nlohmann/json/pull/2203 if (res >= static_cast((std::numeric_limits::max)())) { - JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type", BasicJsonType())); // LCOV_EXCL_LINE + JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE } return static_cast(res); @@ -12175,7 +12036,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(empty())) { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); } json_pointer result = *this; @@ -12238,7 +12099,7 @@ class json_pointer single value; that is, with an empty list of reference tokens. */ default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", j)); + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); } } @@ -12310,7 +12171,7 @@ class json_pointer } default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); } } @@ -12343,7 +12204,7 @@ class json_pointer // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range", *ptr)); + ") is out of range")); } // note: at performs range check @@ -12352,7 +12213,7 @@ class json_pointer } default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); } } @@ -12390,7 +12251,9 @@ class json_pointer if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr)); + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); } // use unchecked array access @@ -12399,7 +12262,7 @@ class json_pointer } default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); } } @@ -12432,7 +12295,7 @@ class json_pointer // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range", *ptr)); + ") is out of range")); } // note: at performs range check @@ -12441,7 +12304,7 @@ class json_pointer } default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); } } @@ -12545,7 +12408,9 @@ class json_pointer // check if nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { - JSON_THROW(detail::parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'", BasicJsonType())); + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); } // extract the reference tokens: @@ -12580,18 +12445,58 @@ class json_pointer (reference_token[pos + 1] != '0' && reference_token[pos + 1] != '1'))) { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", BasicJsonType())); + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); } } // finally, store the reference token - detail::unescape(reference_token); + unescape(reference_token); result.push_back(reference_token); } return result; } + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + JSON_PRIVATE_UNLESS_TESTED: + /// escape "~" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + private: /*! @param[in] reference_string the reference string to the current value @@ -12637,7 +12542,7 @@ class json_pointer // iterate object and use keys as reference string for (const auto& element : *value.m_value.object) { - flatten(reference_string + "/" + detail::escape(element.first), element.second, result); + flatten(reference_string + "/" + escape(element.first), element.second, result); } } break; @@ -12667,7 +12572,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!value.is_object())) { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", value)); + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); } BasicJsonType result; @@ -12677,7 +12582,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive", element.second)); + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); } // assign value to reference pointed to by JSON pointer; Note that if @@ -12993,7 +12898,7 @@ class binary_writer default: { - JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j));; + JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()))); } } } @@ -13837,12 +13742,13 @@ class binary_writer @return The size of a BSON document entry header, including the id marker and the entry name size (and its null-terminator). */ - static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) + static std::size_t calc_bson_entry_header_size(const string_t& name) { const auto it = name.find(static_cast(0)); if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { - JSON_THROW(out_of_range::create(409, "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")", j)); + JSON_THROW(out_of_range::create(409, + "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")")); } return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; @@ -13952,21 +13858,21 @@ class binary_writer @brief Writes a BSON element with key @a name and unsigned @a value */ void write_bson_unsigned(const string_t& name, - const BasicJsonType& j) + const std::uint64_t value) { - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + if (value <= static_cast((std::numeric_limits::max)())) { write_bson_entry_header(name, 0x10 /* int32 */); - write_number(static_cast(j.m_value.number_unsigned)); + write_number(static_cast(value)); } - else if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + else if (value <= static_cast((std::numeric_limits::max)())) { write_bson_entry_header(name, 0x12 /* int64 */); - write_number(static_cast(j.m_value.number_unsigned)); + write_number(static_cast(value)); } else { - JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(j.m_value.number_unsigned) + " cannot be represented by BSON as it does not fit int64", j)); + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64")); } } @@ -14043,7 +13949,7 @@ class binary_writer static std::size_t calc_bson_element_size(const string_t& name, const BasicJsonType& j) { - const auto header_size = calc_bson_entry_header_size(name, j); + const auto header_size = calc_bson_entry_header_size(name); switch (j.type()) { case value_t::object: @@ -14112,7 +14018,7 @@ class binary_writer return write_bson_integer(name, j.m_value.number_integer); case value_t::number_unsigned: - return write_bson_unsigned(name, j); + return write_bson_unsigned(name, j.m_value.number_unsigned); case value_t::string: return write_bson_string(name, *j.m_value.string); @@ -15040,51 +14946,49 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) return 10; } // LCOV_EXCL_STOP - else if (n >= 100000000) + if (n >= 100000000) { pow10 = 100000000; return 9; } - else if (n >= 10000000) + if (n >= 10000000) { pow10 = 10000000; return 8; } - else if (n >= 1000000) + if (n >= 1000000) { pow10 = 1000000; return 7; } - else if (n >= 100000) + if (n >= 100000) { pow10 = 100000; return 6; } - else if (n >= 10000) + if (n >= 10000) { pow10 = 10000; return 5; } - else if (n >= 1000) + if (n >= 1000) { pow10 = 1000; return 4; } - else if (n >= 100) + if (n >= 100) { pow10 = 100; return 3; } - else if (n >= 10) + if (n >= 10) { pow10 = 10; return 2; } - else - { - pow10 = 1; - return 1; - } + + pow10 = 1; + return 1; } inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, @@ -16146,7 +16050,7 @@ class serializer { std::string sn(3, '\0'); (std::snprintf)(&sn[0], sn.size(), "%.2X", byte); - JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn, BasicJsonType())); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn)); } case error_handler_t::ignore: @@ -16240,7 +16144,7 @@ class serializer { std::string sn(3, '\0'); (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast(s.back())); - JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); } case error_handler_t::ignore: @@ -16905,7 +16809,6 @@ class basic_json friend class ::nlohmann::detail::json_sax_dom_parser; template friend class ::nlohmann::detail::json_sax_dom_callback_parser; - friend class ::nlohmann::detail::exception; /// workaround type for MSVC using basic_json_t = NLOHMANN_BASIC_JSON_TPL; @@ -17777,7 +17680,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1", basic_json())); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1")); // LCOV_EXCL_LINE } break; } @@ -17944,83 +17847,13 @@ class basic_json invariant. Furthermore, it has to be called each time the type of a JSON value is changed, because the invariant expresses a relationship between @a m_type and @a m_value. - - Furthermore, the parent relation is checked for arrays and objects: If - @a check_parents true and the value is an array or object, then the - container's elements must have the current value as parent. - - @param[in] check_parents whether the parent relation should be checked. - The value is true by default and should only be set to false - during destruction of objects when the invariant does not - need to hold. */ - void assert_invariant(bool check_parents = true) const noexcept + void assert_invariant() const noexcept { JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); - -#if JSON_DIAGNOSTICS - JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) - { - return j.m_parent == this; - })); -#else - static_cast(check_parents); -#endif - } - - void set_parents() - { -#if JSON_DIAGNOSTICS - switch (m_type) - { - case value_t::array: - { - for (auto& element : *m_value.array) - { - element.m_parent = this; - } - break; - } - - case value_t::object: - { - for (auto& element : *m_value.object) - { - element.second.m_parent = this; - } - break; - } - - default: - break; - } -#endif - } - - iterator set_parents(iterator it, typename iterator::difference_type count) - { -#if JSON_DIAGNOSTICS - for (typename iterator::difference_type i = 0; i < count; ++i) - { - (it + i)->m_parent = this; - } -#else - static_cast(count); -#endif - return it; - } - - reference set_parent(reference j) - { -#if JSON_DIAGNOSTICS - j.m_parent = this; -#else - static_cast(j); -#endif - return j; } public: @@ -18237,7 +18070,6 @@ class basic_json std::forward(val)))) { JSONSerializer::to_json(*this, std::forward(val)); - set_parents(); assert_invariant(); } @@ -18316,7 +18148,6 @@ class basic_json default: // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE } - set_parents(); assert_invariant(); } @@ -18418,7 +18249,7 @@ class basic_json // if object is wanted but impossible, throw an exception if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) { - JSON_THROW(type_error::create(301, "cannot create object from initializer list", basic_json())); + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); } } @@ -18428,13 +18259,13 @@ class basic_json m_type = value_t::object; m_value = value_t::object; - for (auto& element_ref : init) + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) { auto element = element_ref.moved_or_copied(); m_value.object->emplace( std::move(*((*element.m_value.array)[0].m_value.string)), std::move((*element.m_value.array)[1])); - } + }); } else { @@ -18443,7 +18274,6 @@ class basic_json m_value.array = create(init.begin(), init.end()); } - set_parents(); assert_invariant(); } @@ -18653,7 +18483,6 @@ class basic_json : m_type(value_t::array) { m_value.array = create(cnt, val); - set_parents(); assert_invariant(); } @@ -18723,7 +18552,7 @@ class basic_json // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", basic_json())); + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); } // copy type from first iterator @@ -18741,7 +18570,7 @@ class basic_json if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", *first.m_object)); + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); } break; } @@ -18803,10 +18632,10 @@ class basic_json } default: - JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + std::string(first.m_object->type_name()), *first.m_object)); + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); } - set_parents(); assert_invariant(); } @@ -18905,7 +18734,6 @@ class basic_json break; } - set_parents(); assert_invariant(); } @@ -18940,13 +18768,12 @@ class basic_json m_value(std::move(other.m_value)) { // check that passed value is valid - other.assert_invariant(false); + other.assert_invariant(); // invalidate payload other.m_type = value_t::null; other.m_value = {}; - set_parents(); assert_invariant(); } @@ -18987,7 +18814,6 @@ class basic_json swap(m_type, other.m_type); swap(m_value, other.m_value); - set_parents(); assert_invariant(); return *this; } @@ -19009,7 +18835,7 @@ class basic_json */ ~basic_json() noexcept { - assert_invariant(false); + assert_invariant(); m_value.destroy(m_type); } @@ -19502,7 +19328,7 @@ class basic_json return m_value.boolean; } - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); } /// get a pointer to the value (object) @@ -19623,7 +19449,7 @@ class basic_json return *ptr; } - JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()), obj)); + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); } public: @@ -20051,7 +19877,7 @@ class basic_json { if (!is_binary()) { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); } return *get_ptr(); @@ -20062,7 +19888,7 @@ class basic_json { if (!is_binary()) { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); } return *get_ptr(); @@ -20112,17 +19938,17 @@ class basic_json { JSON_TRY { - return set_parent(m_value.array->at(idx)); + return m_value.array->at(idx); } JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } } else { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); } } @@ -20164,12 +19990,12 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } } else { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); } } @@ -20210,17 +20036,17 @@ class basic_json { JSON_TRY { - return set_parent(m_value.object->at(key)); + return m_value.object->at(key); } JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); } } else { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); } } @@ -20266,12 +20092,12 @@ class basic_json JSON_CATCH (std::out_of_range&) { // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); } } else { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); } } @@ -20316,22 +20142,15 @@ class basic_json // fill up array with null values if given idx is outside range if (idx >= m_value.array->size()) { -#if JSON_DIAGNOSTICS - // remember array size before resizing - const auto previous_size = m_value.array->size(); -#endif - m_value.array->resize(idx + 1); - -#if JSON_DIAGNOSTICS - // set parent for values added above - set_parents(begin() + static_cast(previous_size), static_cast(idx + 1 - previous_size)); -#endif + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); } return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -20361,7 +20180,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -20404,10 +20223,10 @@ class basic_json // operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - return set_parent(m_value.object->operator[](key)); + return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -20449,7 +20268,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -20494,10 +20313,10 @@ class basic_json // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - return set_parent(m_value.object->operator[](key)); + return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -20541,7 +20360,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -20613,7 +20432,7 @@ class basic_json return default_value; } - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); } /*! @@ -20686,7 +20505,7 @@ class basic_json } } - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); } /*! @@ -20840,7 +20659,7 @@ class basic_json // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } IteratorType result = end(); @@ -20856,7 +20675,7 @@ class basic_json { if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) { - JSON_THROW(invalid_iterator::create(205, "iterator out of range", *this)); + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); } if (is_string()) @@ -20892,7 +20711,7 @@ class basic_json } default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); } return result; @@ -20953,7 +20772,7 @@ class basic_json // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", *this)); + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); } IteratorType result = end(); @@ -20970,7 +20789,7 @@ class basic_json if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", *this)); + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); } if (is_string()) @@ -21008,7 +20827,7 @@ class basic_json } default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); } return result; @@ -21051,7 +20870,7 @@ class basic_json return m_value.object->erase(key); } - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); } /*! @@ -21085,14 +20904,14 @@ class basic_json { if (JSON_HEDLEY_UNLIKELY(idx >= size())) { - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else { - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); } } @@ -22037,7 +21856,7 @@ class basic_json // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); } // transform null object into an array @@ -22050,7 +21869,6 @@ class basic_json // add element to array (move semantics) m_value.array->push_back(std::move(val)); - set_parent(m_value.array->back()); // if val is moved from, basic_json move constructor marks it null so we do not call the destructor } @@ -22073,7 +21891,7 @@ class basic_json // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); } // transform null object into an array @@ -22086,7 +21904,6 @@ class basic_json // add element to array m_value.array->push_back(val); - set_parent(m_value.array->back()); } /*! @@ -22124,7 +21941,7 @@ class basic_json // push_back only works for null objects or objects if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); } // transform null object into an object @@ -22135,9 +21952,8 @@ class basic_json assert_invariant(); } - // add element to object - auto res = m_value.object->insert(val); - set_parent(res.first->second); + // add element to array + m_value.object->insert(val); } /*! @@ -22228,7 +22044,7 @@ class basic_json // emplace_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); } // transform null object into an array @@ -22241,10 +22057,10 @@ class basic_json // add element to array (perfect forwarding) #ifdef JSON_HAS_CPP_17 - return set_parent(m_value.array->emplace_back(std::forward(args)...)); + return m_value.array->emplace_back(std::forward(args)...); #else m_value.array->emplace_back(std::forward(args)...); - return set_parent(m_value.array->back()); + return m_value.array->back(); #endif } @@ -22281,7 +22097,7 @@ class basic_json // emplace only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { - JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); } // transform null object into an object @@ -22294,8 +22110,6 @@ class basic_json // add element to array (perfect forwarding) auto res = m_value.object->emplace(std::forward(args)...); - set_parent(res.first->second); - // create result iterator and set iterator to the result of emplace auto it = begin(); it.m_it.object_iterator = res.first; @@ -22354,14 +22168,14 @@ class basic_json // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } // insert to array and return iterator - return set_parents(insert_iterator(pos, val), static_cast(1)); + return insert_iterator(pos, val); } - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); } /*! @@ -22405,14 +22219,14 @@ class basic_json // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } // insert to array and return iterator - return set_parents(insert_iterator(pos, cnt, val), static_cast(cnt)); + return insert_iterator(pos, cnt, val); } - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); } /*! @@ -22450,28 +22264,28 @@ class basic_json // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); } if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", *this)); + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); } // insert to array and return iterator - return set_parents(insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator), std::distance(first, last)); + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -22503,17 +22317,17 @@ class basic_json // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } // insert to array and return iterator - return set_parents(insert_iterator(pos, ilist.begin(), ilist.end()), static_cast(ilist.size())); + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @@ -22544,19 +22358,19 @@ class basic_json // insert only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); } m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); @@ -22593,11 +22407,11 @@ class basic_json if (JSON_HEDLEY_UNLIKELY(!is_object())) { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); } if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this)); + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); } for (auto it = j.cbegin(); it != j.cend(); ++it) @@ -22644,20 +22458,20 @@ class basic_json if (JSON_HEDLEY_UNLIKELY(!is_object())) { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object() || !last.m_object->is_object())) { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); } for (auto it = first; it != last; ++it) @@ -22692,9 +22506,6 @@ class basic_json { std::swap(m_type, other.m_type); std::swap(m_value, other.m_value); - - set_parents(); - other.set_parents(); assert_invariant(); } @@ -22755,7 +22566,7 @@ class basic_json } else { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); } } @@ -22788,7 +22599,7 @@ class basic_json } else { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); } } @@ -22821,7 +22632,7 @@ class basic_json } else { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); } } @@ -22854,7 +22665,7 @@ class basic_json } else { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); } } @@ -22868,7 +22679,7 @@ class basic_json } else { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); } } @@ -23776,11 +23587,6 @@ class basic_json /// the value of the current element json_value m_value = {}; -#if JSON_DIAGNOSTICS - /// a pointer to a parent value (for debugging purposes) - basic_json* m_parent = nullptr; -#endif - ////////////////////////////////////////// // binary serialization/deserialization // ////////////////////////////////////////// @@ -25077,7 +24883,7 @@ class basic_json if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", parent)); + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } // default case: insert add offset @@ -25093,7 +24899,7 @@ class basic_json }; // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [this, &result](json_pointer & ptr) + const auto operation_remove = [&result](json_pointer & ptr) { // get reference to parent of JSON pointer ptr const auto last_path = ptr.back(); @@ -25111,7 +24917,7 @@ class basic_json } else { - JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found", *this)); + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); } } else if (parent.is_array()) @@ -25124,7 +24930,7 @@ class basic_json // type check: top level value must be an array if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", json_patch)); + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); } // iterate and apply the operations @@ -25144,13 +24950,13 @@ class basic_json // check if desired value is present if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'", val)); + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); } // check if result is of type string if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'", val)); + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); } // no error: return value @@ -25160,7 +24966,7 @@ class basic_json // type check: every element of the array must be an object if (JSON_HEDLEY_UNLIKELY(!val.is_object())) { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", val)); + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); } // collect mandatory members @@ -25238,7 +25044,7 @@ class basic_json // throw an exception if test fails if (JSON_HEDLEY_UNLIKELY(!success)) { - JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump(), val)); + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); } break; @@ -25248,7 +25054,7 @@ class basic_json { // op must be "add", "remove", "replace", "move", "copy", or // "test" - JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid", val)); + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); } } } @@ -25364,7 +25170,7 @@ class basic_json for (auto it = source.cbegin(); it != source.cend(); ++it) { // escape the key name to be used in a JSON patch - const auto key = detail::escape(it.key()); + const auto key = json_pointer::escape(it.key()); if (target.find(it.key()) != target.end()) { @@ -25388,7 +25194,7 @@ class basic_json if (source.find(it.key()) == source.end()) { // found a key that is not in this -> add it - const auto key = detail::escape(it.key()); + const auto key = json_pointer::escape(it.key()); result.push_back( { {"op", "add"}, {"path", path + "/" + key}, diff --git a/test/cmake_fetch_content/CMakeLists.txt b/test/cmake_fetch_content/CMakeLists.txt index f850b8bd78..7df00865e6 100644 --- a/test/cmake_fetch_content/CMakeLists.txt +++ b/test/cmake_fetch_content/CMakeLists.txt @@ -11,12 +11,10 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.11.0") ) set_tests_properties(cmake_fetch_content_configure PROPERTIES FIXTURES_SETUP cmake_fetch_content - LABELS git_required - LABELS not_reproducible + LABELS "git_required;not_reproducible" ) set_tests_properties(cmake_fetch_content_build PROPERTIES FIXTURES_REQUIRED cmake_fetch_content - LABELS git_required - LABELS not_reproducible + LABELS "git_required;not_reproducible" ) endif() diff --git a/third_party/gdb_pretty_printer/README.md b/third_party/gdb_pretty_printer/README.md new file mode 100644 index 0000000000..f5f61927b0 --- /dev/null +++ b/third_party/gdb_pretty_printer/README.md @@ -0,0 +1,77 @@ +# GDB Pretty Printer + +File [nlohmann-json.py](nlohmann-json.py) contains a pretty printer for GDB for JSON values of this library. It was originally published as [Gist](https://gist.github.com/ssbssa/60da5339c6e6036b2afce17de06050ea#file-nlohmann-json-py) by [Hannes Domani](https://github.com/ssbssa). + +## How to use + +- Add line + + ``` + source /path/to/nlohmann-json.py + ``` + + to `~/.gdbinit`. Note you must replace `/path/to` with whatever path you stored file `nlohmann-json.py`. +- In GDB, debug as usual. When you want to pretty-print a JSON value `var`, type + + ``` + p -pretty on -array on -- var + ``` + + The result should look like + + ``` + $1 = std::map with 5 elements = { + ["Baptiste"] = std::map with 1 element = { + ["first"] = "second" + }, + ["Emmanuel"] = std::vector of length 3, capacity 3 = { + 3, + "25", + 0.5 + }, + ["Jean"] = 0.7, + ["Zorg"] = std::map with 8 elements = { + ["array"] = std::vector of length 3, capacity 3 = { + 1, + 0, + 2 + }, + ["awesome_str"] = "bleh", + ["bool"] = true, + ["flex"] = 0.2, + ["float"] = 5.22, + ["int"] = 5, + ["nested"] = std::map with 1 element = { + ["bar"] = "barz" + }, + ["trap "] = "you fell" + }, + ["empty"] = nlohmann::detail::value_t::null + } + ``` + +Tested with GDB 9.2. See [#1952](https://github.com/nlohmann/json/issues/1952) for more information. Please post questions there. + +## Copyright + +MIT License + +Copyright (C) 2020 [Hannes Domani](https://github.com/ssbssa) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/gdb_pretty_printer/nlohmann-json.py b/third_party/gdb_pretty_printer/nlohmann-json.py new file mode 100644 index 0000000000..5bac45f617 --- /dev/null +++ b/third_party/gdb_pretty_printer/nlohmann-json.py @@ -0,0 +1,28 @@ +import gdb +import re + +class JsonValuePrinter: + "Print a json-value" + + def __init__(self, val): + self.val = val + + def to_string(self): + if self.val.type.strip_typedefs().code == gdb.TYPE_CODE_FLT: + return ("%.6f" % float(self.val)).rstrip("0") + return self.val + +def json_lookup_function(val): + if re.search("^nlohmann::basic_json<.*>$", val.type.strip_typedefs().name): + t = str(val['m_type']) + if t.startswith("nlohmann::detail::value_t::"): + try: + union_val = val['m_value'][t[27:]] + if union_val.type.code == gdb.TYPE_CODE_PTR: + return gdb.default_visualizer(union_val.dereference()) + else: + return JsonValuePrinter(union_val) + except: + return JsonValuePrinter(val['m_type']) + +gdb.pretty_printers.append(json_lookup_function)