diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/from_json.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/from_json.hpp index d647d7423..ebd4d393a 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/from_json.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/from_json.hpp @@ -13,9 +13,6 @@ #include // forward_list #include // inserter, front_inserter, end #include // map -#ifdef JSON_HAS_CPP_17 - #include // optional -#endif #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -32,6 +29,15 @@ #include #include +// include after macro_scope.hpp +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif + +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM + #include // u8string_view +#endif + NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { @@ -47,7 +53,6 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) } #ifdef JSON_HAS_CPP_17 -#ifndef JSON_USE_IMPLICIT_CONVERSIONS template void from_json(const BasicJsonType& j, std::optional& opt) { @@ -60,8 +65,6 @@ void from_json(const BasicJsonType& j, std::optional& opt) opt.emplace(j.template get()); } } - -#endif // JSON_USE_IMPLICIT_CONVERSIONS #endif // JSON_HAS_CPP_17 // overloads for basic_json template parameters @@ -395,7 +398,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) } // overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit +// (BooleanType, etc.); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? template < typename BasicJsonType, typename ArithmeticType, @@ -540,7 +543,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p) JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } const auto& s = *j.template get_ptr(); -#ifdef JSON_HAS_CPP_20 + // Checking for C++20 standard or later can be insufficient in case the + // library support for char8_t is either incomplete or was disabled + // altogether. Use the __cpp_lib_char8_t feature test instead. +#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L) p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); #else p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_chars.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_chars.hpp index 743104174..3c663cf65 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_chars.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_chars.hpp @@ -130,7 +130,7 @@ struct diyfp // f * 2^e // p_lo = p0_lo + (Q << 32) // // But in this particular case here, the full p_lo is not required. - // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Effectively, we only need to add the highest bit in p_lo to p_hi (and // Q_hi + 1 does not overflow). Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up @@ -220,7 +220,7 @@ boundaries compute_boundaries(FloatType value) // Compute the boundaries m- and m+ of the floating-point value // v = f * 2^e. // - // Determine v- and v+, the floating-point predecessor and successor if v, + // Determine v- and v+, the floating-point predecessor and successor of v, // respectively. // // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) @@ -375,7 +375,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e) // (A smaller distance gamma-alpha would require a larger table.) // NB: - // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + // Actually, this function returns c, such that -60 <= e_c + e + 64 <= -34. constexpr int kCachedPowersMinDecExp = -300; constexpr int kCachedPowersDecStep = 8; @@ -687,8 +687,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, decimal_exponent += n; - // We may now just stop. But instead look if the buffer could be - // decremented to bring V closer to w. + // We may now just stop. But instead, it looks as if the buffer + // could be decremented to bring V closer to w. // // pow10 = 10^n is now 1 ulp in the decimal representation V. // The rounding procedure works with diyfp's with an implicit @@ -1095,7 +1095,7 @@ char* to_chars(char* first, const char* last, FloatType value) // Compute v = buffer * 10^decimal_exponent. // The decimal digits are stored in the buffer, which needs to be interpreted // as an unsigned decimal integer. - // len is the length of the buffer, i.e. the number of decimal digits. + // len is the length of the buffer, i.e., the number of decimal digits. int len = 0; int decimal_exponent = 0; dtoa_impl::grisu2(first, len, decimal_exponent, value); diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_json.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_json.hpp index ead45665f..8b910dd16 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_json.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/conversions/to_json.hpp @@ -15,7 +15,8 @@ #include // copy #include // begin, end -#include // string +#include // allocator_traits +#include // basic_string, char_traits #include // tuple, get #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include // move, forward, declval, pair @@ -267,7 +268,7 @@ struct external_constructor #ifdef JSON_HAS_CPP_17 template::value, int> = 0> -void to_json(BasicJsonType& j, const std::optional& opt) +void to_json(BasicJsonType& j, const std::optional& opt) noexcept { if (opt.has_value()) { @@ -440,15 +441,21 @@ inline void to_json(BasicJsonType& j, const T& t) } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +#if defined(__cpp_lib_char8_t) +template +inline void to_json(BasicJsonType& j, const std::basic_string& s) +{ + using OtherAllocator = typename std::allocator_traits::template rebind_alloc; + j = std::basic_string, OtherAllocator>(s.begin(), s.end(), s.get_allocator()); +} +#endif + template inline void to_json(BasicJsonType& j, const std_fs::path& p) { -#ifdef JSON_HAS_CPP_20 - const std::u8string s = p.u8string(); - j = std::string(s.begin(), s.end()); -#else - j = p.u8string(); // returns std::string in C++17 -#endif + // Returns either a std::string or a std::u8string depending whether library + // support for char8_t is enabled. + j = p.u8string(); } #endif diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/exceptions.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/exceptions.hpp index 5ebfb6578..2740e4c2b 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/exceptions.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/exceptions.hpp @@ -30,7 +30,7 @@ // emitted in every translation unit. This issue cannot be fixed with a // header-only library as there is no implementation file to move these // functions to. As a result, we suppress this warning here to avoid client -// code to stumble over this. See https://github.com/nlohmann/json/issues/4087 +// code stumbling over this. See https://github.com/nlohmann/json/issues/4087 // for a discussion. #if defined(__clang__) #pragma clang diagnostic push diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/binary_reader.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/binary_reader.hpp index 2120cf9a4..3d62ff277 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/binary_reader.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/binary_reader.hpp @@ -53,7 +53,7 @@ enum class cbor_tag_handler_t @note from https://stackoverflow.com/a/1001328/266378 */ -static inline bool little_endianness(int num = 1) noexcept +inline bool little_endianness(int num = 1) noexcept { return *reinterpret_cast(&num) == 1; } @@ -334,7 +334,7 @@ class binary_reader return get_number(input_format_t::bson, value) && sax->number_unsigned(value); } - default: // anything else not supported (yet) + default: // anything else is not supported (yet) { std::array cr{{}}; static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) @@ -731,7 +731,7 @@ class binary_reader case 0xD2: case 0xD3: case 0xD4: - case 0xD8: // tagged item (1 bytes follow) + case 0xD8: // tagged item (1 byte follows) case 0xD9: // tagged item (2 bytes follow) case 0xDA: // tagged item (4 bytes follow) case 0xDB: // tagged item (8 bytes follow) @@ -783,7 +783,7 @@ class binary_reader case cbor_tag_handler_t::store: { binary_t b; - // use binary subtype and store in binary container + // use binary subtype and store in a binary container switch (current) { case 0xD8: @@ -852,7 +852,7 @@ class binary_reader const auto byte1 = static_cast(byte1_raw); const auto byte2 = static_cast(byte2_raw); - // code from RFC 7049, Appendix D, Figure 3: + // Code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often // still only have limited support for them. It is very @@ -2159,7 +2159,7 @@ class binary_reader { break; } - if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array { return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); } @@ -2192,8 +2192,16 @@ class binary_reader result = 1; for (auto i : dim) { + // Pre-multiplication overflow check: if i > 0 and result > SIZE_MAX/i, then result*i would overflow. + // This check must happen before multiplication since overflow detection after the fact is unreliable + // as modular arithmetic can produce any value, not just 0 or SIZE_MAX. + if (JSON_HEDLEY_UNLIKELY(i > 0 && result > (std::numeric_limits::max)() / i)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + } result *= i; - if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() + // Additional post-multiplication check to catch any edge cases the pre-check might miss + if (result == 0 || result == npos) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); } @@ -2409,7 +2417,7 @@ class binary_reader const auto byte1 = static_cast(byte1_raw); const auto byte2 = static_cast(byte2_raw); - // code from RFC 7049, Appendix D, Figure 3: + // Code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often // still only have limited support for them. It is very @@ -2697,7 +2705,7 @@ class binary_reader bool get_ubjson_high_precision_number() { - // get size of following number string + // get the size of the following number string std::size_t size{}; bool no_ndarray = true; auto res = get_ubjson_size_value(size, no_ndarray); @@ -2795,7 +2803,7 @@ class binary_reader chars_read += new_chars_read; if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T))) { - // in case of failure, advance position by 1 to report failing location + // in case of failure, advance position by 1 to report the failing location ++chars_read; sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); return false; @@ -2826,17 +2834,22 @@ class binary_reader { return; } - if constexpr(std::is_integral_v) + else if constexpr(std::is_integral_v) { number = std::byteswap(number); return; } -#endif - auto* ptr = reinterpret_cast(&number); - for (std::size_t i = 0; i < sz / 2; ++i) + else { - std::swap(ptr[i], ptr[sz - i - 1]); +#endif + auto* ptr = reinterpret_cast(&number); + for (std::size_t i = 0; i < sz / 2; ++i) + { + std::swap(ptr[i], ptr[sz - i - 1]); + } +#ifdef __cpp_lib_byteswap } +#endif } /* diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/input_adapters.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/input_adapters.hpp index 1affd619e..2c23a8e5d 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/input_adapters.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/input_adapters.hpp @@ -108,7 +108,7 @@ class input_stream_adapter : is(&i), sb(i.rdbuf()) {} - // delete because of pointer members + // deleted because of pointer members input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&&) = delete; @@ -122,7 +122,7 @@ class input_stream_adapter // std::istream/std::streambuf use std::char_traits::to_int_type, to // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, e.g. 0xFFFFFFFF. + // end up as the same value, e.g., 0xFFFFFFFF. std::char_traits::int_type get_character() { auto res = sb->sbumpc(); @@ -344,7 +344,7 @@ class wide_string_input_adapter typename std::char_traits::int_type get_character() noexcept { - // check if buffer needs to be filled + // check if the buffer needs to be filled if (utf8_bytes_index == utf8_bytes_filled) { fill_buffer(); diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/json_sax.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/json_sax.hpp index 0ff877893..0b06ad5ab 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/json_sax.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/json_sax.hpp @@ -260,7 +260,7 @@ class json_sax_dom_parser JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(ref_stack.back()->is_object()); - // add null at given key and store the reference for later + // add null at the given key and store the reference for later object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); return true; } @@ -576,11 +576,11 @@ class json_sax_dom_callback_parser { BasicJsonType k = BasicJsonType(val); - // check callback for key + // check callback for the key const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); key_keep_stack.push_back(keep); - // add discarded value at given key and store the reference for later + // add discarded value at the given key and store the reference for later if (keep && ref_stack.back()) { object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/lexer.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/lexer.hpp index 2b4e80a48..a40790e7e 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/lexer.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/lexer.hpp @@ -127,7 +127,7 @@ class lexer : public lexer_base , decimal_point_char(static_cast(get_decimal_point())) {} - // delete because of pointer members + // deleted because of pointer members lexer(const lexer&) = delete; lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) lexer& operator=(lexer&) = delete; @@ -262,10 +262,10 @@ class lexer : public lexer_base while (true) { - // get next character + // get the next character switch (get()) { - // end of file while parsing string + // end of file while parsing the string case char_traits::eof(): { error_message = "invalid string: missing closing quote"; @@ -351,7 +351,7 @@ class lexer : public lexer_base (static_cast(codepoint1) << 10u) // low surrogate occupies the least significant 15 bits + static_cast(codepoint2) - // there is still the 0xD800, 0xDC00 and 0x10000 noise + // there is still the 0xD800, 0xDC00, and 0x10000 noise // in the result, so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00u); @@ -377,7 +377,7 @@ class lexer : public lexer_base } } - // result of the above calculation yields a proper codepoint + // the result of the above calculation yields a proper codepoint JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); // translate codepoint into bytes @@ -828,7 +828,7 @@ class lexer : public lexer_base break; } - // remaining bytes (80..C1 and F5..FF) are ill-formed + // the remaining bytes (80..C1 and F5..FF) are ill-formed default: { error_message = "invalid string: ill-formed UTF-8 byte"; @@ -973,7 +973,7 @@ class lexer : public lexer_base reset(); // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read + // changed if minus sign, decimal point, or exponent is read token_type number_type = token_type::value_unsigned; // state (init): we just found out we need to scan a number @@ -1345,7 +1345,7 @@ scan_number_done: if (next_unget) { - // just reset the next_unget variable and work with current + // only reset the next_unget variable and work with current next_unget = false; } else @@ -1524,7 +1524,7 @@ scan_number_done: return token_type::parse_error; } - // read next character and ignore whitespace + // read the next character and ignore whitespace skip_whitespace(); // ignore comments diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/parser.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/parser.hpp index b5a5a525c..2f5cde24a 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/input/parser.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/input/parser.hpp @@ -71,10 +71,12 @@ class parser explicit parser(InputAdapterType&& adapter, parser_callback_t cb = nullptr, const bool allow_exceptions_ = true, - const bool skip_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas_ = false) : callback(std::move(cb)) - , m_lexer(std::move(adapter), skip_comments) + , m_lexer(std::move(adapter), ignore_comments) , allow_exceptions(allow_exceptions_) + , ignore_trailing_commas(ignore_trailing_commas_) { // read first token get_token(); @@ -106,7 +108,7 @@ class parser exception_message(token_type::end_of_input, "value"), nullptr)); } - // in case of an error, return discarded value + // in case of an error, return a discarded value if (sdp.is_errored()) { result = value_t::discarded; @@ -133,7 +135,7 @@ class parser parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); } - // in case of an error, return discarded value + // in case of an error, return a discarded value if (sdp.is_errored()) { result = value_t::discarded; @@ -336,7 +338,7 @@ class parser case token_type::parse_error: { - // using "uninitialized" to avoid "expected" message + // using "uninitialized" to avoid an "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"), nullptr)); @@ -384,11 +386,17 @@ class parser if (states.back()) // array { // comma -> next value + // or end of array (ignore_trailing_commas = true) if (get_token() == token_type::value_separator) { // parse a new value get_token(); - continue; + + // if ignore_trailing_commas and last_token is ], we can continue to "closing ]" + if (!(ignore_trailing_commas && last_token == token_type::end_array)) + { + continue; + } } // closing ] @@ -417,32 +425,39 @@ class parser // states.back() is false -> object // comma -> next value + // or end of object (ignore_trailing_commas = true) 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"), nullptr)); - } - - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } - - // 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"), nullptr)); - } - - // parse values get_token(); - continue; + + // if ignore_trailing_commas and last_token is }, we can continue to "closing }" + if (!(ignore_trailing_commas && last_token == token_type::end_object)) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(last_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"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // 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"), nullptr)); + } + + // parse values + get_token(); + continue; + } } // closing } @@ -513,6 +528,8 @@ class parser lexer_t m_lexer; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; + /// whether trailing commas in objects and arrays should be ignored (true) or signaled as errors (false) + const bool ignore_trailing_commas = false; }; } // namespace detail diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/iter_impl.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/iter_impl.hpp index 45864e8c3..c2fbbfa78 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/iter_impl.hpp @@ -23,7 +23,7 @@ NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -// forward declare, to be able to friend it later on +// forward declare to be able to friend it later on template class iteration_proxy; template class iteration_proxy_value; diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/primitive_iterator.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/primitive_iterator.hpp index 3a238349b..f1a735662 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/primitive_iterator.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/iterators/primitive_iterator.hpp @@ -21,9 +21,9 @@ namespace detail @brief an iterator for primitive JSON types This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes +string). Its only purpose is to allow the iterator/const_iterator classes to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, +a `difference_type` variable. Value begin_value (`0`) models the begin and end_value (`1`) models past the end. */ class primitive_iterator_t diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/json_pointer.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/json_pointer.hpp index 1f764979e..e1b3947ed 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/json_pointer.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/json_pointer.hpp @@ -285,7 +285,7 @@ class json_pointer { if (reference_token == "0") { - // start a new array if reference token is 0 + // start a new array if the reference token is 0 result = &result->operator[](0); } else @@ -314,7 +314,7 @@ class json_pointer The following code is only reached if there exists a reference token _and_ the current value is primitive. In this case, we have an error situation, because primitive values may only occur as - single value; that is, with an empty list of reference tokens. + a single value; that is, with an empty list of reference tokens. */ case detail::value_t::string: case detail::value_t::boolean: @@ -358,7 +358,7 @@ class json_pointer // convert null values to arrays or objects before continuing if (ptr->is_null()) { - // check if reference token is a number + // check if the reference token is a number const bool nums = std::all_of(reference_token.begin(), reference_token.end(), [](const unsigned char x) @@ -366,7 +366,7 @@ class json_pointer return std::isdigit(x); }); - // change value to array for numbers or "-" or to object otherwise + // change value to an array for numbers or "-" or to object otherwise *ptr = (nums || reference_token == "-") ? detail::value_t::array : detail::value_t::object; @@ -609,7 +609,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) { - // first char should be between '1' and '9' + // the first char should be between '1' and '9' return false; } for (std::size_t i = 1; i < reference_token.size(); i++) @@ -673,7 +673,7 @@ class json_pointer return result; } - // check if nonempty reference string begins with slash + // check if a nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); @@ -747,7 +747,7 @@ class json_pointer } else { - // iterate array and use index as reference string + // iterate array and use index as a reference string for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) { flatten(detail::concat(reference_string, '/', std::to_string(i)), @@ -785,7 +785,7 @@ class json_pointer case detail::value_t::discarded: default: { - // add primitive value with its reference string + // add a primitive value with its reference string result[reference_string] = value; break; } @@ -821,17 +821,17 @@ class json_pointer JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); } - // assign value to reference pointed to by JSON pointer; Note that if - // the JSON pointer is "" (i.e., points to the whole value), function - // get_and_create returns a reference to result itself. An assignment - // will then create a primitive value. + // Assign the value to the reference pointed to by JSON pointer. Note + // that if the JSON pointer is "" (i.e., points to the whole value), + // function get_and_create returns a reference to the result itself. + // An assignment will then create a primitive value. json_pointer(element.first).get_and_create(result) = element.second; } return result; } - // can't use conversion operator because of ambiguity + // can't use the conversion operator because of ambiguity json_pointer convert() const& { json_pointer result; @@ -926,7 +926,7 @@ class json_pointer }; #if !JSON_HAS_THREE_WAY_COMPARISON -// functions cannot be defined inside class due to ODR violations +// functions cannot be defined inside the class due to ODR violations template inline bool operator==(const json_pointer& lhs, const json_pointer& rhs) noexcept diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_scope.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_scope.hpp index d1c6b1be3..9117c7df9 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_scope.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_scope.hpp @@ -31,9 +31,15 @@ #endif // C++ language standard detection -// if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) +// if the user manually specified the used C++ version, this is skipped +#if !defined(JSON_HAS_CPP_26) && !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus > 202302L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202302L) + #define JSON_HAS_CPP_26 + #define JSON_HAS_CPP_23 + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) #define JSON_HAS_CPP_23 #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 @@ -128,7 +134,7 @@ #endif #ifndef JSON_HAS_RANGES - // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has a syntax error #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 #define JSON_HAS_RANGES 0 #elif defined(__cpp_lib_ranges) @@ -205,7 +211,7 @@ #define JSON_ASSERT(x) assert(x) #endif -// allow to access some private functions (needed by the test suite) +// allow accessing some private functions (needed by the test suite) #if defined(JSON_TESTS_PRIVATE) #define JSON_PRIVATE_UNLESS_TESTED public #else diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_unscope.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_unscope.hpp index 2edb1686d..236e89cac 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_unscope.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/macro_unscope.hpp @@ -35,6 +35,7 @@ #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 #undef JSON_HAS_CPP_23 + #undef JSON_HAS_CPP_26 #undef JSON_HAS_FILESYSTEM #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef JSON_HAS_THREE_WAY_COMPARISON diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/meta/type_traits.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/meta/type_traits.hpp index d834a0d56..06dcb63e1 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/meta/type_traits.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/meta/type_traits.hpp @@ -13,7 +13,9 @@ #include // tuple #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval - +#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L + #include // byte +#endif #include #include #include @@ -40,12 +42,12 @@ namespace detail // Note to maintainers: // -// Every trait in this file expects a non CV-qualified type. +// Every trait in this file expects a non-CV-qualified type. // The only exceptions are in the 'aliases for detected' section -// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// (i.e., those of the form: decltype(T::member_function(std::declval()))) // // In this case, T has to be properly CV-qualified to constraint the function arguments -// (e.g. to_json(BasicJsonType&, const T&)) +// (e.g., to_json(BasicJsonType&, const T&)) template struct is_basic_json : std::false_type {}; @@ -53,7 +55,7 @@ NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json : std::true_type {}; // used by exceptions create() member functions -// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// true_type for the pointer to possibly cv-qualified basic_json or std::nullptr_t // false_type otherwise template struct is_basic_json_context : @@ -239,6 +241,30 @@ struct char_traits : std::char_traits } }; +#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L +template<> +struct char_traits : std::char_traits +{ + using char_type = std::byte; + using int_type = uint64_t; + + static int_type to_int_type(char_type c) noexcept + { + return static_cast(std::to_integer(c)); + } + + static char_type to_char_type(int_type i) noexcept + { + return std::byte(static_cast(i)); + } + + static constexpr int_type eof() noexcept + { + return static_cast(std::char_traits::eof()); + } +}; +#endif + /////////////////// // is_ functions // /////////////////// @@ -255,7 +281,7 @@ template struct negation : std::integral_constant < bool, !B::value > { // Reimplementation of is_constructible and is_default_constructible, due to them being broken for // std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). -// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +// This causes compile errors in e.g., Clang 3.5 or GCC 4.9. template struct is_default_constructible : std::is_default_constructible {}; @@ -335,7 +361,7 @@ using range_value_t = value_type_t>>; // The following implementation of is_complete_type is taken from // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ -// and is written by Xiang Fan who agreed to using it in this library. +// and is written by Xiang Fan who agreed to use it in this library. template struct is_complete_type : std::false_type {}; @@ -572,7 +598,7 @@ decltype(std::declval()(std::declval(), std::declval())) template using detect_is_transparent = typename T::is_transparent; -// type trait to check if KeyType can be used as object key (without a BasicJsonType) +// type trait to check if KeyType can be used as an object key (without a BasicJsonType) // see is_usable_as_basic_json_key_type below template> @@ -586,7 +612,7 @@ using is_usable_as_key_type = typename std::conditional < std::true_type, std::false_type >::type; -// type trait to check if KeyType can be used as object key +// type trait to check if KeyType can be used as an object key // true if: // - KeyType is comparable with BasicJsonType::object_t::key_type // - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/output/binary_writer.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/output/binary_writer.hpp index 4457dccb9..8fb2100b5 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/output/binary_writer.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/output/binary_writer.hpp @@ -973,9 +973,9 @@ class binary_writer if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); - static_cast(j); } + static_cast(j); return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; } @@ -1552,7 +1552,7 @@ class binary_writer { return 'L'; } - // anything else is treated as high-precision number + // anything else is treated as a high-precision number return 'H'; // LCOV_EXCL_LINE } @@ -1590,7 +1590,7 @@ class binary_writer { return 'M'; } - // anything else is treated as high-precision number + // anything else is treated as a high-precision number return 'H'; // LCOV_EXCL_LINE } @@ -1756,11 +1756,11 @@ class binary_writer template void write_number(const NumberType n, const bool OutputIsLittleEndian = false) { - // step 1: write number to array of length NumberType + // step 1: write the number to an array of length NumberType std::array vec{}; std::memcpy(vec.data(), &n, sizeof(NumberType)); - // step 2: write array to output (with possible reordering) + // step 2: write the array to output (with possible reordering) if (is_little_endian != OutputIsLittleEndian) { // reverse byte order prior to conversion if necessary @@ -1813,8 +1813,21 @@ class binary_writer enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > static CharType to_char_type(std::uint8_t x) noexcept { + // The std::is_trivial trait is deprecated in C++26. The replacement is to use + // std::is_trivially_copyable and std::is_trivially_default_constructible. + // However, some older library implementations support std::is_trivial + // but not all the std::is_trivially_* traits. + // Since detecting full support across all libraries is difficult, + // we use std::is_trivial unless we are using a standard where it has been deprecated. + // For more details, see: https://github.com/nlohmann/json/pull/4775#issuecomment-2884361627 +#ifdef JSON_HAS_CPP_26 + static_assert(std::is_trivially_copyable::value, "CharType must be trivially copyable"); + static_assert(std::is_trivially_default_constructible::value, "CharType must be trivially default constructible"); +#else + static_assert(std::is_trivial::value, "CharType must be trivial"); +#endif + static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); - static_assert(std::is_trivially_default_constructible::value && std::is_trivially_copyable::value, "CharType must be trivial"); CharType result; std::memcpy(&result, &x, sizeof(x)); return result; diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/output/serializer.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/output/serializer.hpp index 3137f3c36..28ff20f5d 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/output/serializer.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/output/serializer.hpp @@ -75,7 +75,7 @@ class serializer , error_handler(error_handler_) {} - // delete because of pointer members + // deleted because of pointer members serializer(const serializer&) = delete; serializer& operator=(const serializer&) = delete; serializer(serializer&&) = delete; @@ -573,7 +573,7 @@ class serializer break; } - default: // decode found yet incomplete multi-byte code point + default: // decode found yet incomplete multibyte code point { if (!ensure_ascii) { @@ -762,7 +762,7 @@ class serializer // jump to the end to generate the string from backward, // so we later avoid reversing the result - buffer_ptr += n_chars; + buffer_ptr += static_cast(n_chars); // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu // See: https://www.youtube.com/watch?v=o4-CwDo2zpg @@ -827,7 +827,7 @@ class serializer void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) { - // get number of digits for a float -> text -> float round-trip + // get the number of digits for a float -> text -> float round-trip static constexpr auto d = std::numeric_limits::max_digits10; // the actual conversion @@ -836,10 +836,10 @@ class serializer // negative value indicates an error JSON_ASSERT(len > 0); - // check if buffer was large enough + // check if the buffer was large enough JSON_ASSERT(static_cast(len) < number_buffer.size()); - // erase thousands separator + // erase thousands separators if (thousands_sep != '\0') { // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 @@ -947,8 +947,8 @@ class serializer * Helper function for dump_integer * * This function takes a negative signed integer and returns its absolute - * value as unsigned integer. The plus/minus shuffling is necessary as we can - * not directly remove the sign of an arbitrary signed integer as the + * value as an unsigned integer. The plus/minus shuffling is necessary as we + * cannot directly remove the sign of an arbitrary signed integer as the * absolute values of INT_MIN and INT_MAX are usually not the same. See * #1708 for details. */ diff --git a/lib/third_party/nlohmann_json/include/nlohmann/detail/string_escape.hpp b/lib/third_party/nlohmann_json/include/nlohmann/detail/string_escape.hpp index 7f0231819..63715cde1 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/detail/string_escape.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/detail/string_escape.hpp @@ -32,10 +32,10 @@ inline void replace_substring(StringType& s, const StringType& f, const StringType& t) { JSON_ASSERT(!f.empty()); - for (auto pos = s.find(f); // find first occurrence of f + for (auto pos = s.find(f); // find the first occurrence of f pos != StringType::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 + pos = s.find(f, pos + t.size())) // find the next occurrence of f {} } @@ -62,7 +62,7 @@ inline StringType escape(StringType s) * Note the order of escaping "~1" to "/" and "~0" to "~" is important. */ template -static void unescape(StringType& s) +inline void unescape(StringType& s) { replace_substring(s, StringType{"~1"}, StringType{"/"}); replace_substring(s, StringType{"~0"}, StringType{"~"}); diff --git a/lib/third_party/nlohmann_json/include/nlohmann/json.hpp b/lib/third_party/nlohmann_json/include/nlohmann/json.hpp index ed51cd544..55ec39d24 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/json.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/json.hpp @@ -134,11 +134,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec InputAdapterType adapter, detail::parser_callback_tcb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false + const bool ignore_comments = false, + const bool ignore_trailing_commas = false ) { return ::nlohmann::detail::parser(std::move(adapter), - std::move(cb), allow_exceptions, ignore_comments); + std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas); } private: @@ -563,7 +564,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec (t == value_t::binary && binary == nullptr) ) { - //not initialized (e.g. due to exception in the ctor) + // not initialized (e.g., due to exception in the ctor) return; } if (t == value_t::array || t == value_t::object) @@ -588,7 +589,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec while (!stack.empty()) { - // move the last item to local variable to be processed + // move the last item to a local variable to be processed basic_json current_item(std::move(stack.back())); stack.pop_back(); @@ -610,7 +611,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec current_item.m_data.m_value.object->clear(); } - // it's now safe that current_item get destructed + // it's now safe that current_item gets destructed // since it doesn't have any children } } @@ -918,20 +919,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int; // (many string types can be constructed from 0 via its null-pointer guise, so we get a - // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows) + // broken call to op[key_type], the wrong semantics, and a 4804 warning on Windows) return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast(0)].is_string(); }); // adjust type if type deduction is not wanted if (!type_deduction) { - // if array is wanted, do not create an object though possible + // if an array is wanted, do not create an object though possible if (manual_type == value_t::array) { is_an_object = false; } - // if object is wanted but impossible, throw an exception + // if an 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", nullptr)); @@ -940,7 +941,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (is_an_object) { - // the initializer list is a list of pairs -> create object + // the initializer list is a list of pairs -> create an object m_data.m_type = value_t::object; m_data.m_value = value_t::object; @@ -954,7 +955,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } else { - // the initializer list describes an array -> create array + // the initializer list describes an array -> create an array m_data.m_type = value_t::array; m_data.m_value.array = create(init.begin(), init.end()); } @@ -1042,16 +1043,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_ASSERT(first.m_object != nullptr); JSON_ASSERT(last.m_object != nullptr); - // make sure iterator fits the current value + // make sure the 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", nullptr)); } - // copy type from first iterator + // copy type from the first iterator m_data.m_type = first.m_object->m_data.m_type; - // check if iterator range is complete for primitive values + // check if the iterator range is complete for primitive values switch (m_data.m_type) { case value_t::boolean: @@ -1231,7 +1232,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check #endif { - // check that passed value is valid + // check that the passed value is valid other.assert_invariant(false); // cppcheck-suppress[accessForwarded] // invalidate payload @@ -1257,7 +1258,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_nothrow_move_assignable::value ) { - // check that passed value is valid + // check that the passed value is valid other.assert_invariant(); using std::swap; @@ -1973,7 +1974,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } JSON_CATCH (std::out_of_range&) { - // create better exception explanation + // create a better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); } // cppcheck-suppress[missingReturn] } @@ -1996,7 +1997,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } JSON_CATCH (std::out_of_range&) { - // create better exception explanation + // create a better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); } // cppcheck-suppress[missingReturn] } @@ -2086,7 +2087,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ reference operator[](size_type idx) { - // implicitly convert null value to an empty array + // implicitly convert a null value to an empty array if (is_null()) { m_data.m_type = value_t::array; @@ -2097,7 +2098,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // operator[] only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { - // fill up array with null values if given idx is outside range + // fill up the array with null values if given idx is outside the range if (idx >= m_data.m_value.array->size()) { #if JSON_DIAGNOSTICS @@ -2145,7 +2146,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param) { - // implicitly convert null value to an empty object + // implicitly convert a null value to an empty object if (is_null()) { m_data.m_type = value_t::object; @@ -2198,7 +2199,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::is_usable_as_basic_json_key_type::value, int > = 0 > reference operator[](KeyType && key) { - // implicitly convert null value to an empty object + // implicitly convert a null value to an empty object if (is_null()) { m_data.m_type = value_t::object; @@ -2255,7 +2256,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(key); if (it != end()) { @@ -2280,7 +2281,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(key); if (it != end()) { @@ -2306,7 +2307,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(std::forward(key)); if (it != end()) { @@ -2333,7 +2334,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(std::forward(key)); if (it != end()) { @@ -2356,7 +2357,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if pointer resolves a value, return it or use default value + // If the pointer resolves to a value, return it. Otherwise, return + // 'default_value'. JSON_TRY { return ptr.get_checked(this).template get(); @@ -2381,7 +2383,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if pointer resolves a value, return it or use default value + // If the pointer resolves to a value, return it. Otherwise, return + // 'default_value'. JSON_TRY { return ptr.get_checked(this).template get(); @@ -2455,7 +2458,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_same::value, int > = 0 > IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param) { - // make sure iterator fits the current value + // make sure the 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)); @@ -2525,7 +2528,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_same::value, int > = 0 > IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param) { - // make sure iterator fits the current value + // make sure the 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)); @@ -3120,7 +3123,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); } - // transform null object into an array + // transform a null object into an array if (is_null()) { m_data.m_type = value_t::array; @@ -3128,7 +3131,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array (move semantics) + // add the element to the array (move semantics) const auto old_capacity = m_data.m_value.array->capacity(); m_data.m_value.array->push_back(std::move(val)); set_parent(m_data.m_value.array->back(), old_capacity); @@ -3153,7 +3156,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); } - // transform null object into an array + // transform a null object into an array if (is_null()) { m_data.m_type = value_t::array; @@ -3161,7 +3164,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array + // add the element to the array const auto old_capacity = m_data.m_value.array->capacity(); m_data.m_value.array->push_back(val); set_parent(m_data.m_value.array->back(), old_capacity); @@ -3185,7 +3188,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); } - // transform null object into an object + // transform a null object into an object if (is_null()) { m_data.m_type = value_t::object; @@ -3193,7 +3196,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to object + // add the element to the object auto res = m_data.m_value.object->insert(val); set_parent(res.first->second); } @@ -3241,7 +3244,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this)); } - // transform null object into an array + // transform a null object into an array if (is_null()) { m_data.m_type = value_t::array; @@ -3249,7 +3252,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array (perfect forwarding) + // add the element to the array (perfect forwarding) const auto old_capacity = m_data.m_value.array->capacity(); m_data.m_value.array->emplace_back(std::forward(args)...); return set_parent(m_data.m_value.array->back(), old_capacity); @@ -3266,7 +3269,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this)); } - // transform null object into an object + // transform a null object into an object if (is_null()) { m_data.m_type = value_t::object; @@ -3274,11 +3277,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array (perfect forwarding) + // add the element to the array (perfect forwarding) auto res = m_data.m_value.object->emplace(std::forward(args)...); set_parent(res.first->second); - // create result iterator and set iterator to the result of emplace + // create a result iterator and set iterator to the result of emplace auto it = begin(); it.m_it.object_iterator = res.first; @@ -3442,7 +3445,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/update/ void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param) { - // implicitly convert null value to an empty object + // implicitly convert a null value to an empty object if (is_null()) { m_data.m_type = value_t::object; @@ -4002,7 +4005,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { - // read width member and use it as indentation parameter if nonzero + // read width member and use it as the indentation parameter if nonzero const bool pretty_print = o.width() > 0; const auto indentation = pretty_print ? o.width() : 0; @@ -4043,10 +4046,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json parse(InputType&& i, parser_callback_t cb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { basic_json result; - parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] + parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] return result; } @@ -4058,10 +4062,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec IteratorType last, parser_callback_t cb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { basic_json result; - parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] + parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved] return result; } @@ -4070,10 +4075,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json parse(detail::span_input_adapter&& i, parser_callback_t cb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { basic_json result; - parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] + parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved] return result; } @@ -4081,26 +4087,29 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/accept/ template static bool accept(InputType&& i, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { - return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); + return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); } /// @brief check if the input is valid JSON /// @sa https://json.nlohmann.me/api/basic_json/accept/ template static bool accept(IteratorType first, IteratorType last, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { - return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); + return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) static bool accept(detail::span_input_adapter&& i, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { - return parser(i.get(), nullptr, false, ignore_comments).accept(true); + return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); } /// @brief generate SAX events @@ -4110,11 +4119,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool sax_parse(InputType&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { auto ia = detail::input_adapter(std::forward(i)); return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); } @@ -4125,11 +4135,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { auto ia = detail::input_adapter(std::move(first), std::move(last)); return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); } @@ -4144,12 +4155,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { auto ia = i.get(); return format == input_format_t::json // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); } @@ -4204,8 +4216,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: - default: return "number"; + default: + return "invalid"; } } @@ -4797,7 +4810,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.at(top_pointer); } - // get reference to parent of JSON pointer ptr + // get reference to the parent of the JSON pointer ptr const auto last_path = ptr.back(); ptr.pop_back(); // parent must exist when performing patch add per RFC6902 specs @@ -4835,7 +4848,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } - // if there exists a parent it cannot be primitive + // if there exists a parent, it cannot be primitive case value_t::string: // LCOV_EXCL_LINE case value_t::boolean: // LCOV_EXCL_LINE case value_t::number_integer: // LCOV_EXCL_LINE @@ -4851,7 +4864,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // wrapper for "remove" operation; remove value at ptr const auto operation_remove = [this, & result](json_pointer & ptr) { - // get reference to parent of JSON pointer ptr + // get reference to the parent of the JSON pointer ptr const auto last_path = ptr.back(); ptr.pop_back(); basic_json& parent = result.at(ptr); @@ -4897,14 +4910,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // context-sensitive error message const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable) - // check if desired value is present + // check if the desired value is present if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); } - // check if result is of type string + // check if the result is of type string if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) @@ -4993,7 +5006,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // ignore out of range errors: success remains false } - // throw an exception if test fails + // throw an exception if the test fails if (JSON_HEDLEY_UNLIKELY(!success)) { JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); @@ -5031,7 +5044,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // the patch basic_json result(value_t::array); - // if the values are the same, return empty patch + // if the values are the same, return an empty patch if (source == target) { return result; @@ -5145,7 +5158,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::discarded: default: { - // both primitive type: replace value + // both primitive types: replace value result.push_back( { {"op", "replace"}, {"path", path}, {"value", target} diff --git a/lib/third_party/nlohmann_json/include/nlohmann/ordered_map.hpp b/lib/third_party/nlohmann_json/include/nlohmann/ordered_map.hpp index d830c6d7e..2a293fc93 100644 --- a/lib/third_party/nlohmann_json/include/nlohmann/ordered_map.hpp +++ b/lib/third_party/nlohmann_json/include/nlohmann/ordered_map.hpp @@ -226,7 +226,7 @@ template , // Since we cannot move const Keys, we re-construct them in place. // We start at first and re-construct (viz. copy) the elements from - // the back of the vector. Example for first iteration: + // the back of the vector. Example for the first iteration: // ,--------. // v | destroy e and re-construct with h diff --git a/lib/third_party/nlohmann_json/single_include/nlohmann/json.hpp b/lib/third_party/nlohmann_json/single_include/nlohmann/json.hpp index 82d69f7c5..274c3afd4 100644 --- a/lib/third_party/nlohmann_json/single_include/nlohmann/json.hpp +++ b/lib/third_party/nlohmann_json/single_include/nlohmann/json.hpp @@ -173,9 +173,6 @@ #include // forward_list #include // inserter, front_inserter, end #include // map -#ifdef JSON_HAS_CPP_17 - #include // optional -#endif #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -2397,9 +2394,15 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif // C++ language standard detection -// if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) +// if the user manually specified the used C++ version, this is skipped +#if !defined(JSON_HAS_CPP_26) && !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus > 202302L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202302L) + #define JSON_HAS_CPP_26 + #define JSON_HAS_CPP_23 + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) #define JSON_HAS_CPP_23 #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 @@ -2494,7 +2497,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif #ifndef JSON_HAS_RANGES - // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has a syntax error #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 #define JSON_HAS_RANGES 0 #elif defined(__cpp_lib_ranges) @@ -2571,7 +2574,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_ASSERT(x) assert(x) #endif -// allow to access some private functions (needed by the test suite) +// allow accessing some private functions (needed by the test suite) #if defined(JSON_TESTS_PRIVATE) #define JSON_PRIVATE_UNLESS_TESTED public #else @@ -3099,10 +3102,10 @@ inline void replace_substring(StringType& s, const StringType& f, const StringType& t) { JSON_ASSERT(!f.empty()); - for (auto pos = s.find(f); // find first occurrence of f + for (auto pos = s.find(f); // find the first occurrence of f pos != StringType::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 + pos = s.find(f, pos + t.size())) // find the next occurrence of f {} } @@ -3129,7 +3132,7 @@ inline StringType escape(StringType s) * Note the order of escaping "~1" to "/" and "~0" to "~" is important. */ template -static void unescape(StringType& s) +inline void unescape(StringType& s) { replace_substring(s, StringType{"~1"}, StringType{"/"}); replace_substring(s, StringType{"~0"}, StringType{"~"}); @@ -3370,7 +3373,9 @@ NLOHMANN_JSON_NAMESPACE_END #include // tuple #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval - +#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L + #include // byte +#endif // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -3580,12 +3585,12 @@ namespace detail // Note to maintainers: // -// Every trait in this file expects a non CV-qualified type. +// Every trait in this file expects a non-CV-qualified type. // The only exceptions are in the 'aliases for detected' section -// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// (i.e., those of the form: decltype(T::member_function(std::declval()))) // // In this case, T has to be properly CV-qualified to constraint the function arguments -// (e.g. to_json(BasicJsonType&, const T&)) +// (e.g., to_json(BasicJsonType&, const T&)) template struct is_basic_json : std::false_type {}; @@ -3593,7 +3598,7 @@ NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json : std::true_type {}; // used by exceptions create() member functions -// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// true_type for the pointer to possibly cv-qualified basic_json or std::nullptr_t // false_type otherwise template struct is_basic_json_context : @@ -3779,6 +3784,30 @@ struct char_traits : std::char_traits } }; +#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L +template<> +struct char_traits : std::char_traits +{ + using char_type = std::byte; + using int_type = uint64_t; + + static int_type to_int_type(char_type c) noexcept + { + return static_cast(std::to_integer(c)); + } + + static char_type to_char_type(int_type i) noexcept + { + return std::byte(static_cast(i)); + } + + static constexpr int_type eof() noexcept + { + return static_cast(std::char_traits::eof()); + } +}; +#endif + /////////////////// // is_ functions // /////////////////// @@ -3795,7 +3824,7 @@ template struct negation : std::integral_constant < bool, !B::value > { // Reimplementation of is_constructible and is_default_constructible, due to them being broken for // std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). -// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +// This causes compile errors in e.g., Clang 3.5 or GCC 4.9. template struct is_default_constructible : std::is_default_constructible {}; @@ -3875,7 +3904,7 @@ using range_value_t = value_type_t>>; // The following implementation of is_complete_type is taken from // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ -// and is written by Xiang Fan who agreed to using it in this library. +// and is written by Xiang Fan who agreed to use it in this library. template struct is_complete_type : std::false_type {}; @@ -4112,7 +4141,7 @@ decltype(std::declval()(std::declval(), std::declval())) template using detect_is_transparent = typename T::is_transparent; -// type trait to check if KeyType can be used as object key (without a BasicJsonType) +// type trait to check if KeyType can be used as an object key (without a BasicJsonType) // see is_usable_as_basic_json_key_type below template> @@ -4126,7 +4155,7 @@ using is_usable_as_key_type = typename std::conditional < std::true_type, std::false_type >::type; -// type trait to check if KeyType can be used as object key +// type trait to check if KeyType can be used as an object key // true if: // - KeyType is comparable with BasicJsonType::object_t::key_type // - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type @@ -4490,7 +4519,7 @@ NLOHMANN_JSON_NAMESPACE_END // emitted in every translation unit. This issue cannot be fixed with a // header-only library as there is no implementation file to move these // functions to. As a result, we suppress this warning here to avoid client -// code to stumble over this. See https://github.com/nlohmann/json/issues/4087 +// code stumbling over this. See https://github.com/nlohmann/json/issues/4087 // for a discussion. #if defined(__clang__) #pragma clang diagnostic push @@ -4817,6 +4846,15 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// include after macro_scope.hpp +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif + +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM + #include // u8string_view +#endif + NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { @@ -4832,7 +4870,6 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) } #ifdef JSON_HAS_CPP_17 -#ifndef JSON_USE_IMPLICIT_CONVERSIONS template void from_json(const BasicJsonType& j, std::optional& opt) { @@ -4845,8 +4882,6 @@ void from_json(const BasicJsonType& j, std::optional& opt) opt.emplace(j.template get()); } } - -#endif // JSON_USE_IMPLICIT_CONVERSIONS #endif // JSON_HAS_CPP_17 // overloads for basic_json template parameters @@ -5180,7 +5215,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) } // overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit +// (BooleanType, etc.); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? template < typename BasicJsonType, typename ArithmeticType, @@ -5325,7 +5360,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p) JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } const auto& s = *j.template get_ptr(); -#ifdef JSON_HAS_CPP_20 + // Checking for C++20 standard or later can be insufficient in case the + // library support for char8_t is either incomplete or was disabled + // altogether. Use the __cpp_lib_char8_t feature test instead. +#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L) p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); #else p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 @@ -5380,7 +5418,8 @@ NLOHMANN_JSON_NAMESPACE_END #include // copy #include // begin, end -#include // string +#include // allocator_traits +#include // basic_string, char_traits #include // tuple, get #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include // move, forward, declval, pair @@ -5914,7 +5953,7 @@ struct external_constructor #ifdef JSON_HAS_CPP_17 template::value, int> = 0> -void to_json(BasicJsonType& j, const std::optional& opt) +void to_json(BasicJsonType& j, const std::optional& opt) noexcept { if (opt.has_value()) { @@ -6087,15 +6126,21 @@ inline void to_json(BasicJsonType& j, const T& t) } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +#if defined(__cpp_lib_char8_t) +template +inline void to_json(BasicJsonType& j, const std::basic_string& s) +{ + using OtherAllocator = typename std::allocator_traits::template rebind_alloc; + j = std::basic_string, OtherAllocator>(s.begin(), s.end(), s.get_allocator()); +} +#endif + template inline void to_json(BasicJsonType& j, const std_fs::path& p) { -#ifdef JSON_HAS_CPP_20 - const std::u8string s = p.u8string(); - j = std::string(s.begin(), s.end()); -#else - j = p.u8string(); // returns std::string in C++17 -#endif + // Returns either a std::string or a std::u8string depending whether library + // support for char8_t is enabled. + j = p.u8string(); } #endif @@ -6556,7 +6601,7 @@ class input_stream_adapter : is(&i), sb(i.rdbuf()) {} - // delete because of pointer members + // deleted because of pointer members input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&&) = delete; @@ -6570,7 +6615,7 @@ class input_stream_adapter // std::istream/std::streambuf use std::char_traits::to_int_type, to // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, e.g. 0xFFFFFFFF. + // end up as the same value, e.g., 0xFFFFFFFF. std::char_traits::int_type get_character() { auto res = sb->sbumpc(); @@ -6792,7 +6837,7 @@ class wide_string_input_adapter typename std::char_traits::int_type get_character() noexcept { - // check if buffer needs to be filled + // check if the buffer needs to be filled if (utf8_bytes_index == utf8_bytes_filled) { fill_buffer(); @@ -7149,7 +7194,7 @@ class lexer : public lexer_base , decimal_point_char(static_cast(get_decimal_point())) {} - // delete because of pointer members + // deleted because of pointer members lexer(const lexer&) = delete; lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) lexer& operator=(lexer&) = delete; @@ -7284,10 +7329,10 @@ class lexer : public lexer_base while (true) { - // get next character + // get the next character switch (get()) { - // end of file while parsing string + // end of file while parsing the string case char_traits::eof(): { error_message = "invalid string: missing closing quote"; @@ -7373,7 +7418,7 @@ class lexer : public lexer_base (static_cast(codepoint1) << 10u) // low surrogate occupies the least significant 15 bits + static_cast(codepoint2) - // there is still the 0xD800, 0xDC00 and 0x10000 noise + // there is still the 0xD800, 0xDC00, and 0x10000 noise // in the result, so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00u); @@ -7399,7 +7444,7 @@ class lexer : public lexer_base } } - // result of the above calculation yields a proper codepoint + // the result of the above calculation yields a proper codepoint JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); // translate codepoint into bytes @@ -7850,7 +7895,7 @@ class lexer : public lexer_base break; } - // remaining bytes (80..C1 and F5..FF) are ill-formed + // the remaining bytes (80..C1 and F5..FF) are ill-formed default: { error_message = "invalid string: ill-formed UTF-8 byte"; @@ -7995,7 +8040,7 @@ class lexer : public lexer_base reset(); // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read + // changed if minus sign, decimal point, or exponent is read token_type number_type = token_type::value_unsigned; // state (init): we just found out we need to scan a number @@ -8367,7 +8412,7 @@ scan_number_done: if (next_unget) { - // just reset the next_unget variable and work with current + // only reset the next_unget variable and work with current next_unget = false; } else @@ -8546,7 +8591,7 @@ scan_number_done: return token_type::parse_error; } - // read next character and ignore whitespace + // read the next character and ignore whitespace skip_whitespace(); // ignore comments @@ -8910,7 +8955,7 @@ class json_sax_dom_parser JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(ref_stack.back()->is_object()); - // add null at given key and store the reference for later + // add null at the given key and store the reference for later object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); return true; } @@ -9226,11 +9271,11 @@ class json_sax_dom_callback_parser { BasicJsonType k = BasicJsonType(val); - // check callback for key + // check callback for the key const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); key_keep_stack.push_back(keep); - // add discarded value at given key and store the reference for later + // add discarded value at the given key and store the reference for later if (keep && ref_stack.back()) { object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); @@ -9829,7 +9874,7 @@ enum class cbor_tag_handler_t @note from https://stackoverflow.com/a/1001328/266378 */ -static inline bool little_endianness(int num = 1) noexcept +inline bool little_endianness(int num = 1) noexcept { return *reinterpret_cast(&num) == 1; } @@ -10110,7 +10155,7 @@ class binary_reader return get_number(input_format_t::bson, value) && sax->number_unsigned(value); } - default: // anything else not supported (yet) + default: // anything else is not supported (yet) { std::array cr{{}}; static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) @@ -10507,7 +10552,7 @@ class binary_reader case 0xD2: case 0xD3: case 0xD4: - case 0xD8: // tagged item (1 bytes follow) + case 0xD8: // tagged item (1 byte follows) case 0xD9: // tagged item (2 bytes follow) case 0xDA: // tagged item (4 bytes follow) case 0xDB: // tagged item (8 bytes follow) @@ -10559,7 +10604,7 @@ class binary_reader case cbor_tag_handler_t::store: { binary_t b; - // use binary subtype and store in binary container + // use binary subtype and store in a binary container switch (current) { case 0xD8: @@ -10628,7 +10673,7 @@ class binary_reader const auto byte1 = static_cast(byte1_raw); const auto byte2 = static_cast(byte2_raw); - // code from RFC 7049, Appendix D, Figure 3: + // Code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often // still only have limited support for them. It is very @@ -11935,7 +11980,7 @@ class binary_reader { break; } - if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array { return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); } @@ -11968,8 +12013,16 @@ class binary_reader result = 1; for (auto i : dim) { + // Pre-multiplication overflow check: if i > 0 and result > SIZE_MAX/i, then result*i would overflow. + // This check must happen before multiplication since overflow detection after the fact is unreliable + // as modular arithmetic can produce any value, not just 0 or SIZE_MAX. + if (JSON_HEDLEY_UNLIKELY(i > 0 && result > (std::numeric_limits::max)() / i)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + } result *= i; - if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() + // Additional post-multiplication check to catch any edge cases the pre-check might miss + if (result == 0 || result == npos) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); } @@ -12185,7 +12238,7 @@ class binary_reader const auto byte1 = static_cast(byte1_raw); const auto byte2 = static_cast(byte2_raw); - // code from RFC 7049, Appendix D, Figure 3: + // Code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often // still only have limited support for them. It is very @@ -12473,7 +12526,7 @@ class binary_reader bool get_ubjson_high_precision_number() { - // get size of following number string + // get the size of the following number string std::size_t size{}; bool no_ndarray = true; auto res = get_ubjson_size_value(size, no_ndarray); @@ -12571,7 +12624,7 @@ class binary_reader chars_read += new_chars_read; if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T))) { - // in case of failure, advance position by 1 to report failing location + // in case of failure, advance position by 1 to report the failing location ++chars_read; sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); return false; @@ -12602,17 +12655,22 @@ class binary_reader { return; } - if constexpr(std::is_integral_v) + else if constexpr(std::is_integral_v) { number = std::byteswap(number); return; } -#endif - auto* ptr = reinterpret_cast(&number); - for (std::size_t i = 0; i < sz / 2; ++i) + else { - std::swap(ptr[i], ptr[sz - i - 1]); +#endif + auto* ptr = reinterpret_cast(&number); + for (std::size_t i = 0; i < sz / 2; ++i) + { + std::swap(ptr[i], ptr[sz - i - 1]); + } +#ifdef __cpp_lib_byteswap } +#endif } /* @@ -12929,10 +12987,12 @@ class parser explicit parser(InputAdapterType&& adapter, parser_callback_t cb = nullptr, const bool allow_exceptions_ = true, - const bool skip_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas_ = false) : callback(std::move(cb)) - , m_lexer(std::move(adapter), skip_comments) + , m_lexer(std::move(adapter), ignore_comments) , allow_exceptions(allow_exceptions_) + , ignore_trailing_commas(ignore_trailing_commas_) { // read first token get_token(); @@ -12964,7 +13024,7 @@ class parser exception_message(token_type::end_of_input, "value"), nullptr)); } - // in case of an error, return discarded value + // in case of an error, return a discarded value if (sdp.is_errored()) { result = value_t::discarded; @@ -12991,7 +13051,7 @@ class parser parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); } - // in case of an error, return discarded value + // in case of an error, return a discarded value if (sdp.is_errored()) { result = value_t::discarded; @@ -13194,7 +13254,7 @@ class parser case token_type::parse_error: { - // using "uninitialized" to avoid "expected" message + // using "uninitialized" to avoid an "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"), nullptr)); @@ -13242,11 +13302,17 @@ class parser if (states.back()) // array { // comma -> next value + // or end of array (ignore_trailing_commas = true) if (get_token() == token_type::value_separator) { // parse a new value get_token(); - continue; + + // if ignore_trailing_commas and last_token is ], we can continue to "closing ]" + if (!(ignore_trailing_commas && last_token == token_type::end_array)) + { + continue; + } } // closing ] @@ -13275,32 +13341,39 @@ class parser // states.back() is false -> object // comma -> next value + // or end of object (ignore_trailing_commas = true) 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"), nullptr)); - } - - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } - - // 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"), nullptr)); - } - - // parse values get_token(); - continue; + + // if ignore_trailing_commas and last_token is }, we can continue to "closing }" + if (!(ignore_trailing_commas && last_token == token_type::end_object)) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(last_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"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // 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"), nullptr)); + } + + // parse values + get_token(); + continue; + } } // closing } @@ -13371,6 +13444,8 @@ class parser lexer_t m_lexer; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; + /// whether trailing commas in objects and arrays should be ignored (true) or signaled as errors (false) + const bool ignore_trailing_commas = false; }; } // namespace detail @@ -13414,9 +13489,9 @@ namespace detail @brief an iterator for primitive JSON types This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes +string). Its only purpose is to allow the iterator/const_iterator classes to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, +a `difference_type` variable. Value begin_value (`0`) models the begin and end_value (`1`) models past the end. */ class primitive_iterator_t @@ -13581,7 +13656,7 @@ NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -// forward declare, to be able to friend it later on +// forward declare to be able to friend it later on template class iteration_proxy; template class iteration_proxy_value; @@ -14789,7 +14864,7 @@ class json_pointer { if (reference_token == "0") { - // start a new array if reference token is 0 + // start a new array if the reference token is 0 result = &result->operator[](0); } else @@ -14818,7 +14893,7 @@ class json_pointer The following code is only reached if there exists a reference token _and_ the current value is primitive. In this case, we have an error situation, because primitive values may only occur as - single value; that is, with an empty list of reference tokens. + a single value; that is, with an empty list of reference tokens. */ case detail::value_t::string: case detail::value_t::boolean: @@ -14862,7 +14937,7 @@ class json_pointer // convert null values to arrays or objects before continuing if (ptr->is_null()) { - // check if reference token is a number + // check if the reference token is a number const bool nums = std::all_of(reference_token.begin(), reference_token.end(), [](const unsigned char x) @@ -14870,7 +14945,7 @@ class json_pointer return std::isdigit(x); }); - // change value to array for numbers or "-" or to object otherwise + // change value to an array for numbers or "-" or to object otherwise *ptr = (nums || reference_token == "-") ? detail::value_t::array : detail::value_t::object; @@ -15113,7 +15188,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) { - // first char should be between '1' and '9' + // the first char should be between '1' and '9' return false; } for (std::size_t i = 1; i < reference_token.size(); i++) @@ -15177,7 +15252,7 @@ class json_pointer return result; } - // check if nonempty reference string begins with slash + // check if a nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); @@ -15251,7 +15326,7 @@ class json_pointer } else { - // iterate array and use index as reference string + // iterate array and use index as a reference string for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) { flatten(detail::concat(reference_string, '/', std::to_string(i)), @@ -15289,7 +15364,7 @@ class json_pointer case detail::value_t::discarded: default: { - // add primitive value with its reference string + // add a primitive value with its reference string result[reference_string] = value; break; } @@ -15325,17 +15400,17 @@ class json_pointer JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); } - // assign value to reference pointed to by JSON pointer; Note that if - // the JSON pointer is "" (i.e., points to the whole value), function - // get_and_create returns a reference to result itself. An assignment - // will then create a primitive value. + // Assign the value to the reference pointed to by JSON pointer. Note + // that if the JSON pointer is "" (i.e., points to the whole value), + // function get_and_create returns a reference to the result itself. + // An assignment will then create a primitive value. json_pointer(element.first).get_and_create(result) = element.second; } return result; } - // can't use conversion operator because of ambiguity + // can't use the conversion operator because of ambiguity json_pointer convert() const& { json_pointer result; @@ -15430,7 +15505,7 @@ class json_pointer }; #if !JSON_HAS_THREE_WAY_COMPARISON -// functions cannot be defined inside class due to ODR violations +// functions cannot be defined inside the class due to ODR violations template inline bool operator==(const json_pointer& lhs, const json_pointer& rhs) noexcept @@ -16713,9 +16788,9 @@ class binary_writer if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); - static_cast(j); } + static_cast(j); return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; } @@ -17292,7 +17367,7 @@ class binary_writer { return 'L'; } - // anything else is treated as high-precision number + // anything else is treated as a high-precision number return 'H'; // LCOV_EXCL_LINE } @@ -17330,7 +17405,7 @@ class binary_writer { return 'M'; } - // anything else is treated as high-precision number + // anything else is treated as a high-precision number return 'H'; // LCOV_EXCL_LINE } @@ -17496,11 +17571,11 @@ class binary_writer template void write_number(const NumberType n, const bool OutputIsLittleEndian = false) { - // step 1: write number to array of length NumberType + // step 1: write the number to an array of length NumberType std::array vec{}; std::memcpy(vec.data(), &n, sizeof(NumberType)); - // step 2: write array to output (with possible reordering) + // step 2: write the array to output (with possible reordering) if (is_little_endian != OutputIsLittleEndian) { // reverse byte order prior to conversion if necessary @@ -17553,8 +17628,21 @@ class binary_writer enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > static CharType to_char_type(std::uint8_t x) noexcept { - static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); + // The std::is_trivial trait is deprecated in C++26. The replacement is to use + // std::is_trivially_copyable and std::is_trivially_default_constructible. + // However, some older library implementations support std::is_trivial + // but not all the std::is_trivially_* traits. + // Since detecting full support across all libraries is difficult, + // we use std::is_trivial unless we are using a standard where it has been deprecated. + // For more details, see: https://github.com/nlohmann/json/pull/4775#issuecomment-2884361627 +#ifdef JSON_HAS_CPP_26 + static_assert(std::is_trivially_copyable::value, "CharType must be trivially copyable"); + static_assert(std::is_trivially_default_constructible::value, "CharType must be trivially default constructible"); +#else static_assert(std::is_trivial::value, "CharType must be trivial"); +#endif + + static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); CharType result; std::memcpy(&result, &x, sizeof(x)); return result; @@ -17750,7 +17838,7 @@ struct diyfp // f * 2^e // p_lo = p0_lo + (Q << 32) // // But in this particular case here, the full p_lo is not required. - // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Effectively, we only need to add the highest bit in p_lo to p_hi (and // Q_hi + 1 does not overflow). Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up @@ -17840,7 +17928,7 @@ boundaries compute_boundaries(FloatType value) // Compute the boundaries m- and m+ of the floating-point value // v = f * 2^e. // - // Determine v- and v+, the floating-point predecessor and successor if v, + // Determine v- and v+, the floating-point predecessor and successor of v, // respectively. // // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) @@ -17995,7 +18083,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e) // (A smaller distance gamma-alpha would require a larger table.) // NB: - // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + // Actually, this function returns c, such that -60 <= e_c + e + 64 <= -34. constexpr int kCachedPowersMinDecExp = -300; constexpr int kCachedPowersDecStep = 8; @@ -18307,8 +18395,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, decimal_exponent += n; - // We may now just stop. But instead look if the buffer could be - // decremented to bring V closer to w. + // We may now just stop. But instead, it looks as if the buffer + // could be decremented to bring V closer to w. // // pow10 = 10^n is now 1 ulp in the decimal representation V. // The rounding procedure works with diyfp's with an implicit @@ -18715,7 +18803,7 @@ char* to_chars(char* first, const char* last, FloatType value) // Compute v = buffer * 10^decimal_exponent. // The decimal digits are stored in the buffer, which needs to be interpreted // as an unsigned decimal integer. - // len is the length of the buffer, i.e. the number of decimal digits. + // len is the length of the buffer, i.e., the number of decimal digits. int len = 0; int decimal_exponent = 0; dtoa_impl::grisu2(first, len, decimal_exponent, value); @@ -18796,7 +18884,7 @@ class serializer , error_handler(error_handler_) {} - // delete because of pointer members + // deleted because of pointer members serializer(const serializer&) = delete; serializer& operator=(const serializer&) = delete; serializer(serializer&&) = delete; @@ -19294,7 +19382,7 @@ class serializer break; } - default: // decode found yet incomplete multi-byte code point + default: // decode found yet incomplete multibyte code point { if (!ensure_ascii) { @@ -19483,7 +19571,7 @@ class serializer // jump to the end to generate the string from backward, // so we later avoid reversing the result - buffer_ptr += n_chars; + buffer_ptr += static_cast(n_chars); // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu // See: https://www.youtube.com/watch?v=o4-CwDo2zpg @@ -19548,7 +19636,7 @@ class serializer void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) { - // get number of digits for a float -> text -> float round-trip + // get the number of digits for a float -> text -> float round-trip static constexpr auto d = std::numeric_limits::max_digits10; // the actual conversion @@ -19557,10 +19645,10 @@ class serializer // negative value indicates an error JSON_ASSERT(len > 0); - // check if buffer was large enough + // check if the buffer was large enough JSON_ASSERT(static_cast(len) < number_buffer.size()); - // erase thousands separator + // erase thousands separators if (thousands_sep != '\0') { // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 @@ -19668,8 +19756,8 @@ class serializer * Helper function for dump_integer * * This function takes a negative signed integer and returns its absolute - * value as unsigned integer. The plus/minus shuffling is necessary as we can - * not directly remove the sign of an arbitrary signed integer as the + * value as an unsigned integer. The plus/minus shuffling is necessary as we + * cannot directly remove the sign of an arbitrary signed integer as the * absolute values of INT_MIN and INT_MAX are usually not the same. See * #1708 for details. */ @@ -19943,7 +20031,7 @@ template , // Since we cannot move const Keys, we re-construct them in place. // We start at first and re-construct (viz. copy) the elements from - // the back of the vector. Example for first iteration: + // the back of the vector. Example for the first iteration: // ,--------. // v | destroy e and re-construct with h @@ -20148,11 +20236,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec InputAdapterType adapter, detail::parser_callback_tcb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false + const bool ignore_comments = false, + const bool ignore_trailing_commas = false ) { return ::nlohmann::detail::parser(std::move(adapter), - std::move(cb), allow_exceptions, ignore_comments); + std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas); } private: @@ -20577,7 +20666,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec (t == value_t::binary && binary == nullptr) ) { - //not initialized (e.g. due to exception in the ctor) + // not initialized (e.g., due to exception in the ctor) return; } if (t == value_t::array || t == value_t::object) @@ -20602,7 +20691,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec while (!stack.empty()) { - // move the last item to local variable to be processed + // move the last item to a local variable to be processed basic_json current_item(std::move(stack.back())); stack.pop_back(); @@ -20624,7 +20713,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec current_item.m_data.m_value.object->clear(); } - // it's now safe that current_item get destructed + // it's now safe that current_item gets destructed // since it doesn't have any children } } @@ -20932,20 +21021,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int; // (many string types can be constructed from 0 via its null-pointer guise, so we get a - // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows) + // broken call to op[key_type], the wrong semantics, and a 4804 warning on Windows) return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast(0)].is_string(); }); // adjust type if type deduction is not wanted if (!type_deduction) { - // if array is wanted, do not create an object though possible + // if an array is wanted, do not create an object though possible if (manual_type == value_t::array) { is_an_object = false; } - // if object is wanted but impossible, throw an exception + // if an 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", nullptr)); @@ -20954,7 +21043,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (is_an_object) { - // the initializer list is a list of pairs -> create object + // the initializer list is a list of pairs -> create an object m_data.m_type = value_t::object; m_data.m_value = value_t::object; @@ -20968,7 +21057,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } else { - // the initializer list describes an array -> create array + // the initializer list describes an array -> create an array m_data.m_type = value_t::array; m_data.m_value.array = create(init.begin(), init.end()); } @@ -21056,16 +21145,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_ASSERT(first.m_object != nullptr); JSON_ASSERT(last.m_object != nullptr); - // make sure iterator fits the current value + // make sure the 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", nullptr)); } - // copy type from first iterator + // copy type from the first iterator m_data.m_type = first.m_object->m_data.m_type; - // check if iterator range is complete for primitive values + // check if the iterator range is complete for primitive values switch (m_data.m_type) { case value_t::boolean: @@ -21245,7 +21334,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check #endif { - // check that passed value is valid + // check that the passed value is valid other.assert_invariant(false); // cppcheck-suppress[accessForwarded] // invalidate payload @@ -21271,7 +21360,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_nothrow_move_assignable::value ) { - // check that passed value is valid + // check that the passed value is valid other.assert_invariant(); using std::swap; @@ -21987,7 +22076,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } JSON_CATCH (std::out_of_range&) { - // create better exception explanation + // create a better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); } // cppcheck-suppress[missingReturn] } @@ -22010,7 +22099,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } JSON_CATCH (std::out_of_range&) { - // create better exception explanation + // create a better exception explanation JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); } // cppcheck-suppress[missingReturn] } @@ -22100,7 +22189,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ reference operator[](size_type idx) { - // implicitly convert null value to an empty array + // implicitly convert a null value to an empty array if (is_null()) { m_data.m_type = value_t::array; @@ -22111,7 +22200,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // operator[] only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { - // fill up array with null values if given idx is outside range + // fill up the array with null values if given idx is outside the range if (idx >= m_data.m_value.array->size()) { #if JSON_DIAGNOSTICS @@ -22159,7 +22248,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param) { - // implicitly convert null value to an empty object + // implicitly convert a null value to an empty object if (is_null()) { m_data.m_type = value_t::object; @@ -22212,7 +22301,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec detail::is_usable_as_basic_json_key_type::value, int > = 0 > reference operator[](KeyType && key) { - // implicitly convert null value to an empty object + // implicitly convert a null value to an empty object if (is_null()) { m_data.m_type = value_t::object; @@ -22269,7 +22358,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(key); if (it != end()) { @@ -22294,7 +22383,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(key); if (it != end()) { @@ -22320,7 +22409,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(std::forward(key)); if (it != end()) { @@ -22347,7 +22436,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if key is found, return value and given default value otherwise + // If 'key' is found, return its value. Otherwise, return `default_value'. const auto it = find(std::forward(key)); if (it != end()) { @@ -22370,7 +22459,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if pointer resolves a value, return it or use default value + // If the pointer resolves to a value, return it. Otherwise, return + // 'default_value'. JSON_TRY { return ptr.get_checked(this).template get(); @@ -22395,7 +22485,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // value only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - // if pointer resolves a value, return it or use default value + // If the pointer resolves to a value, return it. Otherwise, return + // 'default_value'. JSON_TRY { return ptr.get_checked(this).template get(); @@ -22469,7 +22560,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_same::value, int > = 0 > IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param) { - // make sure iterator fits the current value + // make sure the 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)); @@ -22539,7 +22630,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_same::value, int > = 0 > IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param) { - // make sure iterator fits the current value + // make sure the 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)); @@ -23134,7 +23225,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); } - // transform null object into an array + // transform a null object into an array if (is_null()) { m_data.m_type = value_t::array; @@ -23142,7 +23233,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array (move semantics) + // add the element to the array (move semantics) const auto old_capacity = m_data.m_value.array->capacity(); m_data.m_value.array->push_back(std::move(val)); set_parent(m_data.m_value.array->back(), old_capacity); @@ -23167,7 +23258,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); } - // transform null object into an array + // transform a null object into an array if (is_null()) { m_data.m_type = value_t::array; @@ -23175,7 +23266,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array + // add the element to the array const auto old_capacity = m_data.m_value.array->capacity(); m_data.m_value.array->push_back(val); set_parent(m_data.m_value.array->back(), old_capacity); @@ -23199,7 +23290,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); } - // transform null object into an object + // transform a null object into an object if (is_null()) { m_data.m_type = value_t::object; @@ -23207,7 +23298,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to object + // add the element to the object auto res = m_data.m_value.object->insert(val); set_parent(res.first->second); } @@ -23255,7 +23346,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this)); } - // transform null object into an array + // transform a null object into an array if (is_null()) { m_data.m_type = value_t::array; @@ -23263,7 +23354,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array (perfect forwarding) + // add the element to the array (perfect forwarding) const auto old_capacity = m_data.m_value.array->capacity(); m_data.m_value.array->emplace_back(std::forward(args)...); return set_parent(m_data.m_value.array->back(), old_capacity); @@ -23280,7 +23371,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this)); } - // transform null object into an object + // transform a null object into an object if (is_null()) { m_data.m_type = value_t::object; @@ -23288,11 +23379,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec assert_invariant(); } - // add element to array (perfect forwarding) + // add the element to the array (perfect forwarding) auto res = m_data.m_value.object->emplace(std::forward(args)...); set_parent(res.first->second); - // create result iterator and set iterator to the result of emplace + // create a result iterator and set iterator to the result of emplace auto it = begin(); it.m_it.object_iterator = res.first; @@ -23456,7 +23547,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/update/ void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param) { - // implicitly convert null value to an empty object + // implicitly convert a null value to an empty object if (is_null()) { m_data.m_type = value_t::object; @@ -24016,7 +24107,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { - // read width member and use it as indentation parameter if nonzero + // read width member and use it as the indentation parameter if nonzero const bool pretty_print = o.width() > 0; const auto indentation = pretty_print ? o.width() : 0; @@ -24057,10 +24148,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json parse(InputType&& i, parser_callback_t cb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { basic_json result; - parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] + parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] return result; } @@ -24072,10 +24164,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec IteratorType last, parser_callback_t cb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { basic_json result; - parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] + parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved] return result; } @@ -24084,10 +24177,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json parse(detail::span_input_adapter&& i, parser_callback_t cb = nullptr, const bool allow_exceptions = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { basic_json result; - parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] + parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved] return result; } @@ -24095,26 +24189,29 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/accept/ template static bool accept(InputType&& i, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { - return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); + return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); } /// @brief check if the input is valid JSON /// @sa https://json.nlohmann.me/api/basic_json/accept/ template static bool accept(IteratorType first, IteratorType last, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { - return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); + return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) static bool accept(detail::span_input_adapter&& i, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { - return parser(i.get(), nullptr, false, ignore_comments).accept(true); + return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); } /// @brief generate SAX events @@ -24124,11 +24221,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool sax_parse(InputType&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { auto ia = detail::input_adapter(std::forward(i)); return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); } @@ -24139,11 +24237,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { auto ia = detail::input_adapter(std::move(first), std::move(last)); return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); } @@ -24158,12 +24257,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, - const bool ignore_comments = false) + const bool ignore_comments = false, + const bool ignore_trailing_commas = false) { auto ia = i.get(); return format == input_format_t::json // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); } @@ -24218,8 +24318,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: - default: return "number"; + default: + return "invalid"; } } @@ -24811,7 +24912,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec result.at(top_pointer); } - // get reference to parent of JSON pointer ptr + // get reference to the parent of the JSON pointer ptr const auto last_path = ptr.back(); ptr.pop_back(); // parent must exist when performing patch add per RFC6902 specs @@ -24849,7 +24950,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } - // if there exists a parent it cannot be primitive + // if there exists a parent, it cannot be primitive case value_t::string: // LCOV_EXCL_LINE case value_t::boolean: // LCOV_EXCL_LINE case value_t::number_integer: // LCOV_EXCL_LINE @@ -24865,7 +24966,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // wrapper for "remove" operation; remove value at ptr const auto operation_remove = [this, & result](json_pointer & ptr) { - // get reference to parent of JSON pointer ptr + // get reference to the parent of the JSON pointer ptr const auto last_path = ptr.back(); ptr.pop_back(); basic_json& parent = result.at(ptr); @@ -24911,14 +25012,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // context-sensitive error message const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable) - // check if desired value is present + // check if the desired value is present if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); } - // check if result is of type string + // check if the result is of type string if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) @@ -25007,7 +25108,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // ignore out of range errors: success remains false } - // throw an exception if test fails + // throw an exception if the test fails if (JSON_HEDLEY_UNLIKELY(!success)) { JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); @@ -25045,7 +25146,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // the patch basic_json result(value_t::array); - // if the values are the same, return empty patch + // if the values are the same, return an empty patch if (source == target) { return result; @@ -25159,7 +25260,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::discarded: default: { - // both primitive type: replace value + // both primitive types: replace value result.push_back( { {"op", "replace"}, {"path", path}, {"value", target} @@ -25353,6 +25454,7 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 #undef JSON_HAS_CPP_23 + #undef JSON_HAS_CPP_26 #undef JSON_HAS_FILESYSTEM #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef JSON_HAS_THREE_WAY_COMPARISON