diff --git a/third_party/include/nlohmann/json.hpp b/third_party/include/nlohmann/json.hpp index 34a8d32..87475ab 100644 --- a/third_party/include/nlohmann/json.hpp +++ b/third_party/include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.9.1 +| | |__ | | | | | | version 3.10.4 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -31,14 +31,16 @@ SOFTWARE. #define INCLUDE_NLOHMANN_JSON_HPP_ #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 9 -#define NLOHMANN_JSON_VERSION_PATCH 1 +#define NLOHMANN_JSON_VERSION_MINOR 10 +#define NLOHMANN_JSON_VERSION_PATCH 4 #include // all_of, find, for_each #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list -#include // istream, ostream +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO #include // random_access_iterator_tag #include // unique_ptr #include // accumulate @@ -165,7 +167,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept // #include -#include // pair +#include // declval, pair // #include @@ -2212,6 +2214,83 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ +// #include + + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; +} // namespace detail +} // namespace nlohmann + // This file contains all internal macro definitions // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them @@ -2248,8 +2327,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP // disable documentation warnings on clang #if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" #endif // allow to disable exceptions @@ -2501,6 +2581,45 @@ JSON_HEDLEY_DIAGNOSTIC_POP inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + #ifndef JSON_USE_IMPLICIT_CONVERSIONS #define JSON_USE_IMPLICIT_CONVERSIONS 1 #endif @@ -2511,6 +2630,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_EXPLICIT explicit #endif +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + namespace nlohmann { @@ -2695,6 +2818,14 @@ class exception : public std::exception break; } + case value_t::null: // LCOV_EXCL_LINE + case value_t::string: // LCOV_EXCL_LINE + case value_t::boolean: // LCOV_EXCL_LINE + case value_t::number_integer: // LCOV_EXCL_LINE + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE break; // LCOV_EXCL_LINE } @@ -3192,6 +3323,9 @@ template struct identity_tag {}; #include // declval #include // tuple +// #include + + // #include @@ -3199,19 +3333,6 @@ template struct identity_tag {}; // #include - -namespace nlohmann -{ -namespace detail -{ -template struct make_void -{ - using type = void; -}; -template using void_t = typename make_void::type; -} // namespace detail -} // namespace nlohmann - // #include @@ -3260,71 +3381,32 @@ struct iterator_traits::value>> } // namespace detail } // namespace nlohmann +// #include + + // #include + +namespace nlohmann +{ +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); +} // namespace nlohmann + +// #include + + +// #include + + +namespace nlohmann +{ +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); +} // namespace nlohmann + // #include // #include - -#include - -// #include - - -// https://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - nonesuch(nonesuch const&&) = delete; - void operator=(nonesuch const&) = delete; - void operator=(nonesuch&&) = delete; -}; - -template class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template class Op, class... Args> -struct detector>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op; -}; - -template class Op, class... Args> -using is_detected = typename detector::value_t; - -template class Op, class... Args> -using detected_t = typename detector::type; - -template class Op, class... Args> -using detected_or = detector; - -template class Op, class... Args> -using detected_or_t = typename detected_or::type; - -template class Op, class... Args> -using is_detected_exact = std::is_same>; - -template class Op, class... Args> -using is_detected_convertible = - std::is_convertible, To>; -} // namespace detail -} // namespace nlohmann - // #include #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ @@ -3474,9 +3556,6 @@ using reference_t = typename T::reference; template using iterator_category_t = typename T::iterator_category; -template -using iterator_t = typename T::iterator; - template using to_json_function = decltype(T::to_json(std::declval()...)); @@ -3552,6 +3631,9 @@ template struct conjunction : std::conditional, B1>::type {}; +// https://en.cppreference.com/w/cpp/types/negation +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. @@ -3609,6 +3691,31 @@ struct is_iterator_traits> is_detected::value; }; +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +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. @@ -3676,60 +3783,37 @@ struct is_constructible_object_type : is_constructible_object_type_impl {}; -template -struct is_compatible_string_type_impl : std::false_type {}; - template -struct is_compatible_string_type_impl < - BasicJsonType, CompatibleStringType, - enable_if_t::value >> +struct is_compatible_string_type { static constexpr auto value = is_constructible::value; }; template -struct is_compatible_string_type - : is_compatible_string_type_impl {}; - -template -struct is_constructible_string_type_impl : std::false_type {}; - -template -struct is_constructible_string_type_impl < - BasicJsonType, ConstructibleStringType, - enable_if_t::value >> +struct is_constructible_string_type { static constexpr auto value = is_constructible::value; }; -template -struct is_constructible_string_type - : is_constructible_string_type_impl {}; - template struct is_compatible_array_type_impl : std::false_type {}; template struct is_compatible_array_type_impl < BasicJsonType, CompatibleArrayType, - enable_if_t < is_detected::value&& + enable_if_t < is_detected::value&& -// This is needed because json_reverse_iterator has a ::iterator type... -// Therefore it is detected as a CompatibleArrayType. -// The real fix would be to have an Iterable concept. - !is_iterator_traits < - iterator_traits>::value >> + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> { static constexpr bool value = is_constructible::value; + range_value_t>::value; }; template @@ -3751,28 +3835,29 @@ struct is_constructible_array_type_impl < BasicJsonType, ConstructibleArrayType, enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& is_default_constructible::value&& (std::is_move_assignable::value || std::is_copy_assignable::value)&& -is_detected::value&& is_detected::value&& -is_complete_type < -detected_t>::value >> +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> { - static constexpr bool value = - // This is needed because json_reverse_iterator has a ::iterator type, - // furthermore, std::back_insert_iterator (and other iterators) have a - // base class `iterator`... Therefore it is detected as a - // ConstructibleArrayType. The real fix would be to have an Iterable - // concept. - !is_iterator_traits>::value && + using value_type = range_value_t; - (std::is_same::value || - has_from_json::value || - has_non_default_from_json < - BasicJsonType, typename ConstructibleArrayType::value_type >::value); + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; }; template @@ -3827,12 +3912,48 @@ struct is_constructible_tuple : std::false_type {}; template struct is_constructible_tuple> : conjunction...> {}; + +// a naive helper to check if a type is an ordered_map (exploits the fact that +// ordered_map inherits capacity() from std::vector) +template +struct is_ordered_map +{ + using one = char; + + struct two + { + char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + }; + + template static one test( decltype(&C::capacity) ) ; + template static two test(...); + + enum { value = sizeof(test(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) +}; + +// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) +template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > +T conditional_static_cast(U value) +{ + return static_cast(value); +} + +template::value, int> = 0> +T conditional_static_cast(U value) +{ + return value; +} + } // namespace detail } // namespace nlohmann // #include +#ifdef JSON_HAS_CPP_17 + #include +#endif + namespace nlohmann { namespace detail @@ -3872,6 +3993,13 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) break; } + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::binary: + case value_t::discarded: default: JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); } @@ -3976,7 +4104,7 @@ void from_json(const BasicJsonType& j, std::valarray& l) } template -auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -> decltype(j.template get(), void()) { for (std::size_t i = 0; i < N; ++i) @@ -4157,6 +4285,12 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) break; } + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::binary: + case value_t::discarded: default: JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); } @@ -4245,6 +4379,18 @@ void from_json(const BasicJsonType& j, std::unordered_map +void from_json(const BasicJsonType& j, std::filesystem::path& p) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + } + p = *j.template get_ptr(); +} +#endif + struct from_json_fn { template @@ -4278,6 +4424,8 @@ constexpr const auto& from_json = detail::static_const::va #include // valarray #include // vector +// #include + // #include @@ -4380,6 +4528,14 @@ template class iteration_proxy_value return anchor.key(); // use an empty key for all primitive types + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: return empty_str; } @@ -4470,6 +4626,10 @@ class tuple_element> // #include +#ifdef JSON_HAS_CPP_17 + #include +#endif + namespace nlohmann { namespace detail @@ -4478,6 +4638,13 @@ namespace detail // constructors // ////////////////// +/* + * Note all external_constructor<>::construct functions need to call + * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an + * allocated value (e.g., a string). See bug issue + * https://github.com/nlohmann/json/issues/2865 for more information. + */ + template struct external_constructor; template<> @@ -4486,6 +4653,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept { + j.m_value.destroy(j.m_type); j.m_type = value_t::boolean; j.m_value = b; j.assert_invariant(); @@ -4498,6 +4666,7 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) { + j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value = s; j.assert_invariant(); @@ -4506,6 +4675,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) { + j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value = std::move(s); j.assert_invariant(); @@ -4516,6 +4686,7 @@ struct external_constructor int > = 0 > static void construct(BasicJsonType& j, const CompatibleStringType& str) { + j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value.string = j.template create(str); j.assert_invariant(); @@ -4528,6 +4699,7 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) { + j.m_value.destroy(j.m_type); j.m_type = value_t::binary; j.m_value = typename BasicJsonType::binary_t(b); j.assert_invariant(); @@ -4536,8 +4708,9 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) { + j.m_value.destroy(j.m_type); j.m_type = value_t::binary; - j.m_value = typename BasicJsonType::binary_t(std::move(b));; + j.m_value = typename BasicJsonType::binary_t(std::move(b)); j.assert_invariant(); } }; @@ -4548,6 +4721,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { + j.m_value.destroy(j.m_type); j.m_type = value_t::number_float; j.m_value = val; j.assert_invariant(); @@ -4560,6 +4734,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept { + j.m_value.destroy(j.m_type); j.m_type = value_t::number_unsigned; j.m_value = val; j.assert_invariant(); @@ -4572,6 +4747,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept { + j.m_value.destroy(j.m_type); j.m_type = value_t::number_integer; j.m_value = val; j.assert_invariant(); @@ -4584,6 +4760,7 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) { + j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = arr; j.set_parents(); @@ -4593,6 +4770,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { + j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = std::move(arr); j.set_parents(); @@ -4606,6 +4784,8 @@ struct external_constructor { using std::begin; using std::end; + + j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value.array = j.template create(begin(arr), end(arr)); j.set_parents(); @@ -4615,6 +4795,7 @@ struct external_constructor template static void construct(BasicJsonType& j, const std::vector& arr) { + j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->reserve(arr.size()); @@ -4630,6 +4811,7 @@ struct external_constructor enable_if_t::value, int> = 0> static void construct(BasicJsonType& j, const std::valarray& arr) { + j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->resize(arr.size()); @@ -4648,6 +4830,7 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { + j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value = obj; j.set_parents(); @@ -4657,6 +4840,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { + j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value = std::move(obj); j.set_parents(); @@ -4670,6 +4854,7 @@ struct external_constructor using std::begin; using std::end; + j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value.object = j.template create(begin(obj), end(obj)); j.set_parents(); @@ -4817,6 +5002,14 @@ void to_json(BasicJsonType& j, const T& t) to_json_tuple_impl(j, t, make_index_sequence::value> {}); } +#ifdef JSON_HAS_CPP_17 +template +void to_json(BasicJsonType& j, const std::filesystem::path& p) +{ + j = p.string(); +} +#endif + struct to_json_fn { template @@ -4909,7 +5102,7 @@ struct adl_serializer // #include -#include // uint8_t +#include // uint8_t, uint64_t #include // tie #include // move @@ -4927,7 +5120,7 @@ order to override the binary type. @tparam BinaryType container to store bytes (`std::vector` by default) -@since version 3.8.0 +@since version 3.8.0; changed type of subtypes to std::uint64_t in 3.10.0. */ template class byte_container_with_subtype : public BinaryType @@ -4935,6 +5128,8 @@ class byte_container_with_subtype : public BinaryType public: /// the type of the underlying container using container_type = BinaryType; + /// the type of the subtype + using subtype_type = std::uint64_t; byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() @@ -4948,13 +5143,13 @@ class byte_container_with_subtype : public BinaryType : container_type(std::move(b)) {} - byte_container_with_subtype(const container_type& b, std::uint8_t subtype_) noexcept(noexcept(container_type(b))) + byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) : container_type(b) , m_subtype(subtype_) , m_has_subtype(true) {} - byte_container_with_subtype(container_type&& b, std::uint8_t subtype_) noexcept(noexcept(container_type(std::move(b)))) + byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) , m_subtype(subtype_) , m_has_subtype(true) @@ -4989,7 +5184,7 @@ class byte_container_with_subtype : public BinaryType @since version 3.8.0 */ - void set_subtype(std::uint8_t subtype_) noexcept + void set_subtype(subtype_type subtype_) noexcept { m_subtype = subtype_; m_has_subtype = true; @@ -4999,7 +5194,7 @@ class byte_container_with_subtype : public BinaryType @brief return the binary subtype Returns the numerical subtype of the value if it has a subtype. If it does - not have a subtype, this function will return size_t(-1) as a sentinel + not have a subtype, this function will return subtype_type(-1) as a sentinel value. @return the numerical subtype of the binary value @@ -5014,11 +5209,12 @@ class byte_container_with_subtype : public BinaryType @sa see @ref has_subtype() -- returns whether or not the binary value has a subtype - @since version 3.8.0 + @since version 3.8.0; fixed return value to properly return + subtype_type(-1) as documented in version 3.10.0 */ - constexpr std::uint8_t subtype() const noexcept + constexpr subtype_type subtype() const noexcept { - return m_subtype; + return m_has_subtype ? m_subtype : subtype_type(-1); } /*! @@ -5068,7 +5264,7 @@ class byte_container_with_subtype : public BinaryType } private: - std::uint8_t m_subtype = 0; + subtype_type m_subtype = 0; bool m_has_subtype = false; }; @@ -5089,6 +5285,8 @@ class byte_container_with_subtype : public BinaryType // #include +// #include + namespace nlohmann { @@ -5187,7 +5385,7 @@ std::size_t hash(const BasicJsonType& j) auto seed = combine(type, j.get_binary().size()); const auto h = std::hash {}(j.get_binary().has_subtype()); seed = combine(seed, h); - seed = combine(seed, j.get_binary().subtype()); + seed = combine(seed, static_cast(j.get_binary().subtype())); for (const auto byte : j.get_binary()) { seed = combine(seed, std::hash {}(byte)); @@ -5227,9 +5425,7 @@ std::size_t hash(const BasicJsonType& j) #include // array #include // size_t -#include //FILE * #include // strlen -#include // istream #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include // shared_ptr, make_shared, addressof #include // accumulate @@ -5237,6 +5433,11 @@ std::size_t hash(const BasicJsonType& j) #include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include // pair, declval +#ifndef JSON_NO_IO + #include // FILE * + #include // istream +#endif // JSON_NO_IO + // #include // #include @@ -5253,6 +5454,7 @@ enum class input_format_t { json, cbor, msgpack, ubjson, bson }; // input adapters // //////////////////// +#ifndef JSON_NO_IO /*! Input adapter for stdio file access. This adapter read only 1 byte and do not use any buffer. This adapter is a very low level adapter. @@ -5344,6 +5546,7 @@ class input_stream_adapter std::istream* is = nullptr; std::streambuf* sb = nullptr; }; +#endif // JSON_NO_IO // General-purpose iterator-based adapter. It might not be as fast as // theoretically possible for some containers, but it is extremely versatile. @@ -5630,6 +5833,7 @@ typename container_input_adapter_factory_impl::container_input_adapter_factory::create(container); } +#ifndef JSON_NO_IO // Special cases with fast paths inline file_input_adapter input_adapter(std::FILE* file) { @@ -5645,6 +5849,7 @@ inline input_stream_adapter input_adapter(std::istream&& stream) { return input_stream_adapter(stream); } +#endif // JSON_NO_IO using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); @@ -8200,6 +8405,8 @@ struct is_sax_static_asserts } // namespace detail } // namespace nlohmann +// #include + // #include @@ -8211,8 +8418,9 @@ namespace detail /// how to treat CBOR tags enum class cbor_tag_handler_t { - error, ///< throw a parse_error exception in case of a tag - ignore ///< ignore tags + error, ///< throw a parse_error exception in case of a tag + ignore, ///< ignore tags + store ///< store tags as binary type }; /*! @@ -8300,6 +8508,7 @@ class binary_reader result = parse_ubjson_internal(); break; + case input_format_t::json: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } @@ -8813,7 +9022,7 @@ class binary_reader case 0x9B: // array (eight-byte uint64_t for n follow) { std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + return get_number(input_format_t::cbor, len) && get_cbor_array(detail::conditional_static_cast(len), tag_handler); } case 0x9F: // array (indefinite length) @@ -8867,7 +9076,7 @@ class binary_reader case 0xBB: // map (eight-byte uint64_t for n follow) { std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + return get_number(input_format_t::cbor, len) && get_cbor_object(detail::conditional_static_cast(len), tag_handler); } case 0xBF: // map (indefinite length) @@ -8903,30 +9112,31 @@ class binary_reader case cbor_tag_handler_t::ignore: { + // ignore binary subtype switch (current) { case 0xD8: { - std::uint8_t len{}; - get_number(input_format_t::cbor, len); + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xD9: { - std::uint16_t len{}; - get_number(input_format_t::cbor, len); + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDA: { - std::uint32_t len{}; - get_number(input_format_t::cbor, len); + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDB: { - std::uint64_t len{}; - get_number(input_format_t::cbor, len); + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } default: @@ -8935,6 +9145,47 @@ class binary_reader return parse_cbor_internal(true, tag_handler); } + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + return parse_cbor_internal(true, tag_handler); + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE return false; // LCOV_EXCL_LINE @@ -9264,38 +9515,41 @@ class binary_reader return false; } - string_t key; - if (len != std::size_t(-1)) + if (len != 0) { - for (std::size_t i = 0; i < len; ++i) + string_t key; + if (len != std::size_t(-1)) { - get(); - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + for (std::size_t i = 0; i < len; ++i) { - return false; - } + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); } - key.clear(); } - } - else - { - while (get() != 0xFF) + else { - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + while (get() != 0xFF) { - return false; - } + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); } - key.clear(); } } @@ -10414,6 +10668,20 @@ class binary_reader return sax->number_unsigned(number_lexer.get_number_unsigned()); case token_type::value_float: return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + case token_type::uninitialized: + case token_type::literal_true: + case token_type::literal_false: + case token_type::literal_null: + case token_type::value_string: + case token_type::begin_array: + case token_type::begin_object: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::parse_error: + case token_type::end_of_input: + case token_type::literal_or_value: default: return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); } @@ -10616,6 +10884,7 @@ class binary_reader error_msg += "BSON"; break; + case input_format_t::json: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } @@ -10679,7 +10948,7 @@ namespace detail // parser // //////////// -enum class parse_event_t : uint8_t +enum class parse_event_t : std::uint8_t { /// the parser read `{` and started to process a JSON object object_start, @@ -10990,6 +11259,13 @@ class parser parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), BasicJsonType())); } + case token_type::uninitialized: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::end_of_input: + case token_type::literal_or_value: default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), @@ -11413,6 +11689,14 @@ class iter_impl break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { m_it.primitive_iterator = primitive_iterator_t(); @@ -11509,6 +11793,13 @@ class iter_impl break; } + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { m_it.primitive_iterator.set_begin(); @@ -11539,6 +11830,14 @@ class iter_impl break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { m_it.primitive_iterator.set_end(); @@ -11573,6 +11872,13 @@ class iter_impl case value_t::null: JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) @@ -11607,6 +11913,14 @@ class iter_impl return &*m_it.array_iterator; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) @@ -11652,6 +11966,14 @@ class iter_impl break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { ++m_it.primitive_iterator; @@ -11695,6 +12017,14 @@ class iter_impl break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { --m_it.primitive_iterator; @@ -11728,6 +12058,14 @@ class iter_impl case value_t::array: return (m_it.array_iterator == other.m_it.array_iterator); + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: return (m_it.primitive_iterator == other.m_it.primitive_iterator); } @@ -11765,6 +12103,14 @@ class iter_impl case value_t::array: return (m_it.array_iterator < other.m_it.array_iterator); + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: return (m_it.primitive_iterator < other.m_it.primitive_iterator); } @@ -11816,6 +12162,14 @@ class iter_impl break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { m_it.primitive_iterator += i; @@ -11884,6 +12238,14 @@ class iter_impl case value_t::array: return m_it.array_iterator - other.m_it.array_iterator; + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: return m_it.primitive_iterator - other.m_it.primitive_iterator; } @@ -11908,6 +12270,13 @@ class iter_impl case value_t::null: JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) @@ -12527,6 +12896,13 @@ class json_pointer an error situation, because primitive values may only occur as single value; that is, with an empty list of reference tokens. */ + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", j)); } @@ -12599,6 +12975,14 @@ class json_pointer break; } + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } @@ -12641,6 +13025,14 @@ class json_pointer break; } + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } @@ -12688,6 +13080,14 @@ class json_pointer break; } + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } @@ -12730,6 +13130,14 @@ class json_pointer break; } + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } @@ -12800,6 +13208,14 @@ class json_pointer break; } + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: { // we do not expect primitive values if there is still a @@ -12933,6 +13349,14 @@ class json_pointer break; } + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: default: { // add primitive value with its reference string @@ -13119,12 +13543,16 @@ class json_ref #include // copy #include // size_t -#include // streamsize #include // back_inserter #include // shared_ptr, make_shared -#include // basic_ostream #include // basic_string #include // vector + +#ifndef JSON_NO_IO + #include // streamsize + #include // basic_ostream +#endif // JSON_NO_IO + // #include @@ -13151,11 +13579,11 @@ template using output_adapter_t = std::shared_ptr>; /// output adapter for byte vectors -template +template> class output_vector_adapter : public output_adapter_protocol { public: - explicit output_vector_adapter(std::vector& vec) noexcept + explicit output_vector_adapter(std::vector& vec) noexcept : v(vec) {} @@ -13171,9 +13599,10 @@ class output_vector_adapter : public output_adapter_protocol } private: - std::vector& v; + std::vector& v; }; +#ifndef JSON_NO_IO /// output adapter for output streams template class output_stream_adapter : public output_adapter_protocol @@ -13197,6 +13626,7 @@ class output_stream_adapter : public output_adapter_protocol private: std::basic_ostream& stream; }; +#endif // JSON_NO_IO /// output adapter for basic_string template> @@ -13226,11 +13656,14 @@ template> class output_adapter { public: - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} + template> + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} +#ifndef JSON_NO_IO output_adapter(std::basic_ostream& s) : oa(std::make_shared>(s)) {} +#endif // JSON_NO_IO output_adapter(StringType& s) : oa(std::make_shared>(s)) {} @@ -13290,9 +13723,18 @@ class binary_writer break; } + case value_t::null: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { - JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j));; + JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j)); } } } @@ -13516,8 +13958,26 @@ class binary_writer { if (j.m_value.binary->has_subtype()) { - write_number(static_cast(0xd8)); - write_number(j.m_value.binary->subtype()); + if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd8)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd9)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xda)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xdb)); + write_number(static_cast(j.m_value.binary->subtype())); + } } // step 1: write control byte and the binary array size @@ -13597,6 +14057,7 @@ class binary_writer break; } + case value_t::discarded: default: break; } @@ -13918,6 +14379,7 @@ class binary_writer break; } + case value_t::discarded: default: break; } @@ -14122,6 +14584,7 @@ class binary_writer break; } + case value_t::discarded: default: break; } @@ -14142,6 +14605,7 @@ class binary_writer if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { JSON_THROW(out_of_range::create(409, "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")", j)); + static_cast(j); } return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; @@ -14330,7 +14794,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); + write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } @@ -14373,6 +14837,7 @@ class binary_writer return header_size + 0ul; // LCOV_EXCL_START + case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return 0ul; @@ -14419,6 +14884,7 @@ class binary_writer return write_bson_null(name); // LCOV_EXCL_START + case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return; @@ -14709,6 +15175,7 @@ class binary_writer case value_t::object: return '{'; + case value_t::discarded: default: // discarded values return 'N'; } @@ -14758,6 +15225,10 @@ class binary_writer void write_compact_float(const number_float_t n, detail::input_format_t format) { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && static_cast(n) <= static_cast((std::numeric_limits::max)()) && static_cast(static_cast(n)) == static_cast(n)) @@ -14774,6 +15245,9 @@ class binary_writer : get_msgpack_float_prefix(n)); write_number(n); } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif } public: @@ -15914,6 +16388,10 @@ char* to_chars(char* first, const char* last, FloatType value) *first++ = '-'; } +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif if (value == 0) // +-0 { *first++ = '0'; @@ -15922,6 +16400,9 @@ char* to_chars(char* first, const char* last, FloatType value) *first++ = '0'; return first; } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); @@ -16332,7 +16813,7 @@ class serializer for (std::size_t i = 0; i < s.size(); ++i) { - const auto byte = static_cast(s[i]); + const auto byte = static_cast(s[i]); switch (decode(state, codepoint, byte)) { @@ -16442,7 +16923,7 @@ class serializer { case error_handler_t::strict: { - std::string sn(3, '\0'); + std::string sn(9, '\0'); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) (std::snprintf)(&sn[0], sn.size(), "%.2X", byte); JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn, BasicJsonType())); @@ -16537,7 +17018,7 @@ class serializer { case error_handler_t::strict: { - std::string sn(3, '\0'); + std::string sn(9, '\0'); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast(s.back())); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType())); @@ -16617,6 +17098,7 @@ class serializer @tparam NumberType either @a number_integer_t or @a number_unsigned_t */ template < typename NumberType, detail::enable_if_t < + std::is_integral::value || std::is_same::value || std::is_same::value || std::is_same::value, @@ -16649,7 +17131,7 @@ class serializer // use a pointer to fill the buffer auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) - const bool is_negative = std::is_same::value && !(x >= 0); // see issue #755 + const bool is_negative = std::is_signed::value && !(x >= 0); // see issue #755 number_unsigned_t abs_value; unsigned int n_chars{}; @@ -16753,8 +17235,8 @@ class serializer // erase thousands separator if (thousands_sep != '\0') { - auto* const end = std::remove(number_buffer.begin(), - number_buffer.begin() + len, thousands_sep); + // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 + const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); std::fill(end, number_buffer.end(), '\0'); JSON_ASSERT((end - number_buffer.begin()) <= len); len = (end - number_buffer.begin()); @@ -16763,7 +17245,8 @@ class serializer // convert decimal point to '.' if (decimal_point != '\0' && decimal_point != '.') { - auto* const dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); if (dec_pos != number_buffer.end()) { *dec_pos = '.'; @@ -17920,8 +18403,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Notes on subtypes - CBOR - - Binary values are represented as byte strings. No subtypes are - supported and will be ignored when CBOR is written. + - Binary values are represented as byte strings. Subtypes are serialized + as tagged values. - MessagePack - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) @@ -18077,12 +18560,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::discarded: default: { object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1", basic_json())); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.4", basic_json())); // LCOV_EXCL_LINE } break; } @@ -18149,53 +18633,55 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec binary = create(std::move(value)); } - void destroy(value_t t) noexcept + void destroy(value_t t) { - // flatten the current json_value to a heap-allocated stack - std::vector stack; + if (t == value_t::array || t == value_t::object) + { + // flatten the current json_value to a heap-allocated stack + std::vector stack; - // move the top-level items to stack - if (t == value_t::array) - { - stack.reserve(array->size()); - std::move(array->begin(), array->end(), std::back_inserter(stack)); - } - else if (t == value_t::object) - { - stack.reserve(object->size()); - for (auto&& it : *object) + // move the top-level items to stack + if (t == value_t::array) { - stack.push_back(std::move(it.second)); + stack.reserve(array->size()); + std::move(array->begin(), array->end(), std::back_inserter(stack)); } - } - - while (!stack.empty()) - { - // move the last item to local variable to be processed - basic_json current_item(std::move(stack.back())); - stack.pop_back(); - - // if current_item is array/object, move - // its children to the stack to be processed later - if (current_item.is_array()) + else { - std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), - std::back_inserter(stack)); - - current_item.m_value.array->clear(); - } - else if (current_item.is_object()) - { - for (auto&& it : *current_item.m_value.object) + stack.reserve(object->size()); + for (auto&& it : *object) { stack.push_back(std::move(it.second)); } - - current_item.m_value.object->clear(); } - // it's now safe that current_item get destructed - // since it doesn't have any children + while (!stack.empty()) + { + // move the last item to local variable to be processed + basic_json current_item(std::move(stack.back())); + stack.pop_back(); + + // if current_item is array/object, move + // its children to the stack to be processed later + if (current_item.is_array()) + { + std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack)); + + current_item.m_value.array->clear(); + } + else if (current_item.is_object()) + { + for (auto&& it : *current_item.m_value.object) + { + stack.push_back(std::move(it.second)); + } + + current_item.m_value.object->clear(); + } + + // it's now safe that current_item get destructed + // since it doesn't have any children + } } switch (t) @@ -18232,6 +18718,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::discarded: default: { break; @@ -18303,6 +18795,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: break; } @@ -18322,12 +18822,40 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return it; } - reference set_parent(reference j) + reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1)) { #if JSON_DIAGNOSTICS + if (old_capacity != std::size_t(-1)) + { + // see https://github.com/nlohmann/json/issues/2838 + JSON_ASSERT(type() == value_t::array); + if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + return j; + } + } + + // ordered_json uses a vector internally, so pointers could have + // been invalidated; see https://github.com/nlohmann/json/issues/2962 +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(push ) +#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr +#endif + if (detail::is_ordered_map::value) + { + set_parents(); + return j; + } +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning( pop ) +#endif + j.m_parent = this; #else static_cast(j); + static_cast(old_capacity); #endif return j; } @@ -18500,7 +19028,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @ref number_float_t, and all convertible number types such as `int`, `size_t`, `int64_t`, `float` or `double` can be used. - **boolean**: @ref boolean_t / `bool` can be used. - - **binary**: @ref binary_t / `std::vector` may be used, + - **binary**: @ref binary_t / `std::vector` may be used, unfortunately because string literals cannot be distinguished from binary character arrays by the C++ type system, all types compatible with `const char*` will be directed to the string constructor instead. This is both @@ -18820,7 +19348,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) + static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; @@ -18838,9 +19366,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return res; } - /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) + /// @copydoc binary(const typename binary_t::container_type&, typename binary_t::subtype_type) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) + static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; @@ -19054,6 +19582,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::binary: + case value_t::discarded: default: break; } @@ -19110,6 +19643,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::discarded: default: JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + std::string(first.m_object->type_name()), *first.m_object)); } @@ -19209,6 +19744,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::discarded: default: break; } @@ -20033,7 +20570,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( JSONSerializer::from_json(std::declval(), std::declval()))) { - ValueType ret{}; + auto ret = ValueType(); JSONSerializer::from_json(*this, ret); return ret; } @@ -20362,17 +20899,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ template < typename ValueType, typename std::enable_if < - !std::is_pointer::value&& - !std::is_same>::value&& - !std::is_same::value&& - !detail::is_basic_json::value - && !std::is_same>::value + detail::conjunction < + detail::negation>, + detail::negation>>, + detail::negation>, + detail::negation>, + detail::negation>>, + #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) - && !std::is_same::value + detail::negation>, #endif - && detail::is_detected::value - , int >::type = 0 > - JSON_EXPLICIT operator ValueType() const + detail::is_detected_lazy + >::value, int >::type = 0 > + JSON_EXPLICIT operator ValueType() const { // delegate the call to get<>() const return get(); @@ -20657,15 +21196,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (idx >= m_value.array->size()) { #if JSON_DIAGNOSTICS - // remember array size before resizing - const auto previous_size = m_value.array->size(); + // remember array size & capacity before resizing + const auto old_size = m_value.array->size(); + const auto old_capacity = m_value.array->capacity(); #endif m_value.array->resize(idx + 1); #if JSON_DIAGNOSTICS - // set parent for values added above - set_parents(begin() + static_cast(previous_size), static_cast(idx + 1 - previous_size)); + if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + } + else + { + // set parent for values added above + set_parents(begin() + static_cast(old_size), static_cast(idx + 1 - old_size)); + } #endif + assert_invariant(); } return m_value.array->operator[](idx); @@ -21231,6 +21780,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::discarded: default: JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); } @@ -21347,6 +21898,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::discarded: default: JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); } @@ -22102,6 +22655,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return m_value.object->empty(); } + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { // all other types are nonempty @@ -22175,6 +22735,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return m_value.object->size(); } + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { // all other types have size 1 @@ -22240,6 +22807,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return m_value.object->max_size(); } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { // all other types have max_size() == size() @@ -22347,6 +22922,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::discarded: default: break; } @@ -22389,8 +22966,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // add element to array (move semantics) + const auto old_capacity = m_value.array->capacity(); m_value.array->push_back(std::move(val)); - set_parent(m_value.array->back()); + set_parent(m_value.array->back(), old_capacity); // if val is moved from, basic_json move constructor marks it null so we do not call the destructor } @@ -22425,8 +23003,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // add element to array + const auto old_capacity = m_value.array->capacity(); m_value.array->push_back(val); - set_parent(m_value.array->back()); + set_parent(m_value.array->back(), old_capacity); } /*! @@ -22580,12 +23159,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // add element to array (perfect forwarding) -#ifdef JSON_HAS_CPP_17 - return set_parent(m_value.array->emplace_back(std::forward(args)...)); -#else + const auto old_capacity = m_value.array->capacity(); m_value.array->emplace_back(std::forward(args)...); - return set_parent(m_value.array->back()); -#endif + return set_parent(m_value.array->back(), old_capacity); } /*! @@ -22661,6 +23237,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + set_parents(); return result; } @@ -22698,7 +23275,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // insert to array and return iterator - return set_parents(insert_iterator(pos, val), static_cast(1)); + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); @@ -22749,7 +23326,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // insert to array and return iterator - return set_parents(insert_iterator(pos, cnt, val), static_cast(cnt)); + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); @@ -22811,7 +23388,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // insert to array and return iterator - return set_parents(insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator), std::distance(first, last)); + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -22853,7 +23430,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // insert to array and return iterator - return set_parents(insert_iterator(pos, ilist.begin(), ilist.end()), static_cast(ilist.size())); + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @@ -22943,6 +23520,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = j.cbegin(); it != j.cend(); ++it) { m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_value.object->operator[](it.key()).m_parent = this; +#endif } } @@ -23003,6 +23583,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = first; it != last; ++it) { m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_value.object->operator[](it.key()).m_parent = this; +#endif } } @@ -23279,6 +23862,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif const auto lhs_type = lhs.type(); const auto rhs_type = rhs.type(); @@ -23313,6 +23900,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::binary: return *lhs.m_value.binary == *rhs.m_value.binary; + case value_t::discarded: default: return false; } @@ -23343,6 +23931,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } return false; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif } /*! @@ -23476,6 +24067,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::binary: return (*lhs.m_value.binary) < (*rhs.m_value.binary); + case value_t::discarded: default: return false; } @@ -23679,7 +24271,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @name serialization /// @{ - +#ifndef JSON_NO_IO /*! @brief serialize to stream @@ -23739,7 +24331,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { return o << j; } - +#endif // JSON_NO_IO /// @} @@ -23997,7 +24589,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); } - +#ifndef JSON_NO_IO /*! @brief deserialize from stream @deprecated This stream operator is deprecated and will be removed in @@ -24042,7 +24634,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec parser(detail::input_adapter(i)).parse(false, j); return i; } - +#endif // JSON_NO_IO /// @} /////////////////////////// @@ -24100,6 +24692,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return "binary"; case value_t::discarded: return "discarded"; + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: default: return "number"; } @@ -24185,6 +24780,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B + Binary values with subtype are mapped to tagged values (0xD8..0xDB) + depending on the subtype, followed by a byte string, see "binary" cells + in the table above. + @note The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value. @@ -24225,16 +24824,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.0.9; compact representation of floating-point numbers since version 3.8.0 */ - static std::vector to_cbor(const basic_json& j) + static std::vector to_cbor(const basic_json& j) { - std::vector result; + std::vector result; to_cbor(j, result); return result; } - static void to_cbor(const basic_json& j, detail::output_adapter o) + static void to_cbor(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_cbor(j); + binary_writer(o).write_cbor(j); } static void to_cbor(const basic_json& j, detail::output_adapter o) @@ -24320,16 +24919,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.0.9 */ - static std::vector to_msgpack(const basic_json& j) + static std::vector to_msgpack(const basic_json& j) { - std::vector result; + std::vector result; to_msgpack(j, result); return result; } - static void to_msgpack(const basic_json& j, detail::output_adapter o) + static void to_msgpack(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_msgpack(j); + binary_writer(o).write_msgpack(j); } static void to_msgpack(const basic_json& j, detail::output_adapter o) @@ -24423,19 +25022,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 3.1.0 */ - static std::vector to_ubjson(const basic_json& j, - const bool use_size = false, - const bool use_type = false) + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) { - std::vector result; + std::vector result; to_ubjson(j, result, use_size, use_type); return result; } - static void to_ubjson(const basic_json& j, detail::output_adapter o, + static void to_ubjson(const basic_json& j, detail::output_adapter o, const bool use_size = false, const bool use_type = false) { - binary_writer(o).write_ubjson(j, use_size, use_type); + binary_writer(o).write_ubjson(j, use_size, use_type); } static void to_ubjson(const basic_json& j, detail::output_adapter o, @@ -24501,9 +25100,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa see @ref to_cbor(const basic_json&) for the related CBOR format @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format */ - static std::vector to_bson(const basic_json& j) + static std::vector to_bson(const basic_json& j) { - std::vector result; + std::vector result; to_bson(j, result); return result; } @@ -24516,13 +25115,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @pre The input `j` shall be an object: `j.is_object() == true` @sa see @ref to_bson(const basic_json&) */ - static void to_bson(const basic_json& j, detail::output_adapter o) + static void to_bson(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_bson(j); + binary_writer(o).write_bson(j); } /*! - @copydoc to_bson(const basic_json&, detail::output_adapter) + @copydoc to_bson(const basic_json&, detail::output_adapter) */ static void to_bson(const basic_json& j, detail::output_adapter o) { @@ -25433,6 +26032,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } // 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 + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } @@ -25592,6 +26198,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case patch_operations::invalid: default: { // op must be "add", "remove", "replace", "move", "copy", or @@ -25748,6 +26355,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec break; } + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: default: { // both primitive type: replace value @@ -25960,9 +26575,9 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std // #include -// restore GCC/clang diagnostic settings +// restore clang diagnostic settings #if defined(__clang__) - #pragma GCC diagnostic pop + #pragma clang diagnostic pop #endif // clean up @@ -25979,6 +26594,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT +#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL // #include @@ -26134,4 +26750,4 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std -#endif // INCLUDE_NLOHMANN_JSON_HPP_ \ No newline at end of file +#endif // INCLUDE_NLOHMANN_JSON_HPP_