nlohmann-json: 3.4.0 -> 3.5.0

https://github.com/nlohmann/json/releases/tag/v3.5.0
This commit is contained in:
Will Dietz 2018-12-21 22:38:06 -06:00
parent e78511743e
commit 3f8b78a84d

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ __| | __| | | | JSON for Modern C++
| | |__ | | | | | | version 3.4.0 | | |__ | | | | | | version 3.5.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@ -31,7 +31,7 @@ SOFTWARE.
#define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MAJOR 3
#define NLOHMANN_JSON_VERSION_MINOR 4 #define NLOHMANN_JSON_VERSION_MINOR 5
#define NLOHMANN_JSON_VERSION_PATCH 0 #define NLOHMANN_JSON_VERSION_PATCH 0
#include <algorithm> // all_of, find, for_each #include <algorithm> // all_of, find, for_each
@ -41,7 +41,7 @@ SOFTWARE.
#include <functional> // hash, less #include <functional> // hash, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iosfwd> // istream, ostream #include <iosfwd> // istream, ostream
#include <iterator> // iterator_traits, random_access_iterator_tag #include <iterator> // random_access_iterator_tag
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string, stoi, to_string #include <string> // string, stoi, to_string
#include <utility> // declval, forward, move, pair, swap #include <utility> // declval, forward, move, pair, swap
@ -324,12 +324,10 @@ constexpr T static_const<T>::value;
// #include <nlohmann/json_fwd.hpp> // #include <nlohmann/json_fwd.hpp>
// #include <nlohmann/detail/meta/cpp_future.hpp> // #include <nlohmann/detail/iterators/iterator_traits.hpp>
// #include <nlohmann/detail/meta/detected.hpp>
#include <type_traits> #include <iterator> // random_access_iterator_tag
// #include <nlohmann/detail/meta/void_t.hpp> // #include <nlohmann/detail/meta/void_t.hpp>
@ -346,6 +344,63 @@ template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann
// #include <nlohmann/detail/meta/cpp_future.hpp>
namespace nlohmann
{
namespace detail
{
template <typename It, typename = void>
struct iterator_types {};
template <typename It>
struct iterator_types <
It,
void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
typename It::reference, typename It::iterator_category >>
{
using difference_type = typename It::difference_type;
using value_type = typename It::value_type;
using pointer = typename It::pointer;
using reference = typename It::reference;
using iterator_category = typename It::iterator_category;
};
// This is required as some compilers implement std::iterator_traits in a way that
// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
template <typename T, typename = void>
struct iterator_traits
{
};
template <typename T>
struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
: iterator_types<T>
{
};
template <typename T>
struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
{
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = ptrdiff_t;
using pointer = T*;
using reference = T&;
};
}
}
// #include <nlohmann/detail/meta/cpp_future.hpp>
// #include <nlohmann/detail/meta/detected.hpp>
#include <type_traits>
// #include <nlohmann/detail/meta/void_t.hpp>
// http://en.cppreference.com/w/cpp/experimental/is_detected // http://en.cppreference.com/w/cpp/experimental/is_detected
namespace nlohmann namespace nlohmann
@ -522,10 +577,10 @@ template <typename T, typename = void>
struct is_iterator_traits : std::false_type {}; struct is_iterator_traits : std::false_type {};
template <typename T> template <typename T>
struct is_iterator_traits<std::iterator_traits<T>> struct is_iterator_traits<iterator_traits<T>>
{ {
private: private:
using traits = std::iterator_traits<T>; using traits = iterator_traits<T>;
public: public:
static constexpr auto value = static constexpr auto value =
@ -642,7 +697,7 @@ struct is_compatible_array_type_impl <
// Therefore it is detected as a CompatibleArrayType. // Therefore it is detected as a CompatibleArrayType.
// The real fix would be to have an Iterable concept. // The real fix would be to have an Iterable concept.
not is_iterator_traits< not is_iterator_traits<
std::iterator_traits<CompatibleArrayType>>::value >> iterator_traits<CompatibleArrayType>>::value >>
{ {
static constexpr bool value = static constexpr bool value =
std::is_constructible<BasicJsonType, std::is_constructible<BasicJsonType,
@ -679,7 +734,7 @@ struct is_constructible_array_type_impl <
// Therefore it is detected as a ConstructibleArrayType. // Therefore it is detected as a ConstructibleArrayType.
// The real fix would be to have an Iterable concept. // The real fix would be to have an Iterable concept.
not is_iterator_traits < not is_iterator_traits <
std::iterator_traits<ConstructibleArrayType >>::value and iterator_traits<ConstructibleArrayType >>::value and
(std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or
has_from_json<BasicJsonType, has_from_json<BasicJsonType,
@ -1594,26 +1649,24 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va
#include <cstddef> // size_t #include <cstddef> // size_t
#include <string> // string, to_string #include <string> // string, to_string
#include <iterator> // input_iterator_tag #include <iterator> // input_iterator_tag
#include <tuple> // tuple_size, get, tuple_element
// #include <nlohmann/detail/value_t.hpp> // #include <nlohmann/detail/value_t.hpp>
// #include <nlohmann/detail/meta/type_traits.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
{ {
/// proxy class for the items() function template <typename IteratorType> class iteration_proxy_value
template<typename IteratorType> class iteration_proxy
{
private:
/// helper class for iteration
class iteration_proxy_internal
{ {
public: public:
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using value_type = iteration_proxy_internal; using value_type = iteration_proxy_value;
using pointer = iteration_proxy_internal*; using pointer = value_type * ;
using reference = iteration_proxy_internal&; using reference = value_type & ;
using iterator_category = std::input_iterator_tag; using iterator_category = std::input_iterator_tag;
private: private:
@ -1629,16 +1682,16 @@ template<typename IteratorType> class iteration_proxy
const std::string empty_str = ""; const std::string empty_str = "";
public: public:
explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
/// dereference operator (needed for range-based for) /// dereference operator (needed for range-based for)
iteration_proxy_internal& operator*() iteration_proxy_value& operator*()
{ {
return *this; return *this;
} }
/// increment operator (needed for range-based for) /// increment operator (needed for range-based for)
iteration_proxy_internal& operator++() iteration_proxy_value& operator++()
{ {
++anchor; ++anchor;
++array_index; ++array_index;
@ -1647,13 +1700,13 @@ template<typename IteratorType> class iteration_proxy
} }
/// equality operator (needed for InputIterator) /// equality operator (needed for InputIterator)
bool operator==(const iteration_proxy_internal& o) const noexcept bool operator==(const iteration_proxy_value& o) const noexcept
{ {
return anchor == o.anchor; return anchor == o.anchor;
} }
/// inequality operator (needed for range-based for) /// inequality operator (needed for range-based for)
bool operator!=(const iteration_proxy_internal& o) const noexcept bool operator!=(const iteration_proxy_value& o) const noexcept
{ {
return anchor != o.anchor; return anchor != o.anchor;
} }
@ -1693,6 +1746,10 @@ template<typename IteratorType> class iteration_proxy
} }
}; };
/// proxy class for the items() function
template<typename IteratorType> class iteration_proxy
{
private:
/// the container to iterate /// the container to iterate
typename IteratorType::reference container; typename IteratorType::reference container;
@ -1702,20 +1759,55 @@ template<typename IteratorType> class iteration_proxy
: container(cont) {} : container(cont) {}
/// return iterator begin (needed for range-based for) /// return iterator begin (needed for range-based for)
iteration_proxy_internal begin() noexcept iteration_proxy_value<IteratorType> begin() noexcept
{ {
return iteration_proxy_internal(container.begin()); return iteration_proxy_value<IteratorType>(container.begin());
} }
/// return iterator end (needed for range-based for) /// return iterator end (needed for range-based for)
iteration_proxy_internal end() noexcept iteration_proxy_value<IteratorType> end() noexcept
{ {
return iteration_proxy_internal(container.end()); return iteration_proxy_value<IteratorType>(container.end());
} }
}; };
// Structured Bindings Support
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
// And see https://github.com/nlohmann/json/pull/1391
template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
{
return i.key();
}
// Structured Bindings Support
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
// And see https://github.com/nlohmann/json/pull/1391
template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
{
return i.value();
}
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann
// The Addition to the STD Namespace is required to add
// Structured Bindings Support to the iteration_proxy_value class
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
// And see https://github.com/nlohmann/json/pull/1391
namespace std
{
template <typename IteratorType>
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
: public std::integral_constant<std::size_t, 2> {};
template <std::size_t N, typename IteratorType>
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
{
public:
using type = decltype(
get<N>(std::declval <
::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
};
}
namespace nlohmann namespace nlohmann
{ {
@ -2009,7 +2101,7 @@ void to_json(BasicJsonType& j, const std::pair<Args...>& p)
// for https://github.com/nlohmann/json/pull/1134 // for https://github.com/nlohmann/json/pull/1134
template < typename BasicJsonType, typename T, template < typename BasicJsonType, typename T,
enable_if_t<std::is_same<T, typename iteration_proxy<typename BasicJsonType::iterator>::iteration_proxy_internal>::value, int> = 0> enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
void to_json(BasicJsonType& j, const T& b) void to_json(BasicJsonType& j, const T& b)
{ {
j = { {b.key(), b.value()} }; j = { {b.key(), b.value()} };
@ -2058,6 +2150,7 @@ constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
#include <string> // string, char_traits #include <string> // string, char_traits
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
#include <utility> // pair, declval #include <utility> // pair, declval
#include <cstdio> //FILE *
// #include <nlohmann/detail/macro_scope.hpp> // #include <nlohmann/detail/macro_scope.hpp>
@ -2094,6 +2187,27 @@ struct input_adapter_protocol
/// a type to simplify interfaces /// a type to simplify interfaces
using input_adapter_t = std::shared_ptr<input_adapter_protocol>; using input_adapter_t = std::shared_ptr<input_adapter_protocol>;
/*!
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.
*/
class file_input_adapter : public input_adapter_protocol
{
public:
explicit file_input_adapter(std::FILE* f) noexcept
: m_file(f)
{}
std::char_traits<char>::int_type get_character() noexcept override
{
return std::fgetc(m_file);
}
private:
/// the file pointer to read from
std::FILE* m_file;
};
/*! /*!
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
beginning of input. Does not support changing the underlying std::streambuf beginning of input. Does not support changing the underlying std::streambuf
@ -2109,8 +2223,8 @@ class input_stream_adapter : public input_adapter_protocol
~input_stream_adapter() override ~input_stream_adapter() override
{ {
// clear stream flags; we use underlying streambuf I/O, do not // clear stream flags; we use underlying streambuf I/O, do not
// maintain ifstream flags // maintain ifstream flags, except eof
is.clear(); is.clear(is.rdstate() & std::ios::eofbit);
} }
explicit input_stream_adapter(std::istream& i) explicit input_stream_adapter(std::istream& i)
@ -2128,7 +2242,13 @@ class input_stream_adapter : public input_adapter_protocol
// end up as the same value, eg. 0xFFFFFFFF. // end up as the same value, eg. 0xFFFFFFFF.
std::char_traits<char>::int_type get_character() override std::char_traits<char>::int_type get_character() override
{ {
return sb.sbumpc(); auto res = sb.sbumpc();
// set eof manually, as we don't use the istream interface.
if (res == EOF)
{
is.clear(is.rdstate() | std::ios::eofbit);
}
return res;
} }
private: private:
@ -2336,7 +2456,8 @@ class input_adapter
{ {
public: public:
// native support // native support
input_adapter(std::FILE* file)
: ia(std::make_shared<file_input_adapter>(file)) {}
/// input adapter for input stream /// input adapter for input stream
input_adapter(std::istream& i) input_adapter(std::istream& i)
: ia(std::make_shared<input_stream_adapter>(i)) {} : ia(std::make_shared<input_stream_adapter>(i)) {}
@ -2380,7 +2501,7 @@ class input_adapter
/// input adapter for iterator range with contiguous storage /// input adapter for iterator range with contiguous storage
template<class IteratorType, template<class IteratorType,
typename std::enable_if< typename std::enable_if<
std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
int>::type = 0> int>::type = 0>
input_adapter(IteratorType first, IteratorType last) input_adapter(IteratorType first, IteratorType last)
{ {
@ -2399,7 +2520,7 @@ class input_adapter
// assertion to check that each element is 1 byte long // assertion to check that each element is 1 byte long
static_assert( static_assert(
sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, sizeof(typename iterator_traits<IteratorType>::value_type) == 1,
"each element in the iterator range must have the size of 1 byte"); "each element in the iterator range must have the size of 1 byte");
const auto len = static_cast<size_t>(std::distance(first, last)); const auto len = static_cast<size_t>(std::distance(first, last));
@ -2423,7 +2544,7 @@ class input_adapter
/// input adapter for contiguous container /// input adapter for contiguous container
template<class ContiguousContainer, typename template<class ContiguousContainer, typename
std::enable_if<not std::is_pointer<ContiguousContainer>::value and std::enable_if<not std::is_pointer<ContiguousContainer>::value and
std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
int>::type = 0> int>::type = 0>
input_adapter(const ContiguousContainer& c) input_adapter(const ContiguousContainer& c)
: input_adapter(std::begin(c), std::end(c)) {} : input_adapter(std::begin(c), std::end(c)) {}
@ -3806,7 +3927,7 @@ scan_number_done:
{ {
// escape control characters // escape control characters
char cs[9]; char cs[9];
snprintf(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c)); (std::snprintf)(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c));
result += cs; result += cs;
} }
else else
@ -5486,24 +5607,21 @@ namespace detail
{ {
// forward declare, to be able to friend it later on // forward declare, to be able to friend it later on
template<typename IteratorType> class iteration_proxy; template<typename IteratorType> class iteration_proxy;
template<typename IteratorType> class iteration_proxy_value;
/*! /*!
@brief a template for a bidirectional iterator for the @ref basic_json class @brief a template for a bidirectional iterator for the @ref basic_json class
This class implements a both iterators (iterator and const_iterator) for the This class implements a both iterators (iterator and const_iterator) for the
@ref basic_json class. @ref basic_json class.
@note An iterator is called *initialized* when a pointer to a JSON value has @note An iterator is called *initialized* when a pointer to a JSON value has
been set (e.g., by a constructor or a copy assignment). If the iterator is been set (e.g., by a constructor or a copy assignment). If the iterator is
default-constructed, it is *uninitialized* and most methods are undefined. default-constructed, it is *uninitialized* and most methods are undefined.
**The library uses assertions to detect calls on uninitialized iterators.** **The library uses assertions to detect calls on uninitialized iterators.**
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- -
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
The iterator that can be moved can be moved in both directions (i.e. The iterator that can be moved can be moved in both directions (i.e.
incremented and decremented). incremented and decremented).
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional @since version 1.0.0, simplified in version 2.0.9, change to bidirectional
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
*/ */
@ -5514,6 +5632,7 @@ class iter_impl
friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>; friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
friend BasicJsonType; friend BasicJsonType;
friend iteration_proxy<iter_impl>; friend iteration_proxy<iter_impl>;
friend iteration_proxy_value<iter_impl>;
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
using array_t = typename BasicJsonType::array_t; using array_t = typename BasicJsonType::array_t;
@ -6081,7 +6200,6 @@ class iter_impl
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann
// #include <nlohmann/detail/iterators/iteration_proxy.hpp> // #include <nlohmann/detail/iterators/iteration_proxy.hpp>
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp> // #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
@ -6576,7 +6694,7 @@ class binary_reader
case 0x08: // boolean case 0x08: // boolean
{ {
return sax->boolean(static_cast<bool>(get())); return sax->boolean(get() != 0);
} }
case 0x0A: // null case 0x0A: // null
@ -6599,7 +6717,7 @@ class binary_reader
default: // anything else not supported (yet) default: // anything else not supported (yet)
{ {
char cr[3]; char cr[3];
snprintf(cr, sizeof(cr), "%.2hhX", static_cast<unsigned char>(element_type)); (std::snprintf)(cr, sizeof(cr), "%.2hhX", static_cast<unsigned char>(element_type));
return sax->parse_error(element_type_parse_position, std::string(cr), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr))); return sax->parse_error(element_type_parse_position, std::string(cr), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr)));
} }
} }
@ -6635,7 +6753,10 @@ class binary_reader
if (not is_array) if (not is_array)
{ {
sax->key(key); if (not sax->key(key))
{
return false;
}
} }
if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position))) if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))
@ -8253,7 +8374,7 @@ class binary_reader
std::string get_token_string() const std::string get_token_string() const
{ {
char cr[3]; char cr[3];
snprintf(cr, 3, "%.2hhX", static_cast<unsigned char>(current)); (std::snprintf)(cr, 3, "%.2hhX", static_cast<unsigned char>(current));
return std::string{cr}; return std::string{cr};
} }
@ -11134,13 +11255,13 @@ class serializer
{ {
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x", (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<uint16_t>(codepoint)); static_cast<uint16_t>(codepoint));
bytes += 6; bytes += 6;
} }
else else
{ {
std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)), static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),
static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF))); static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));
bytes += 12; bytes += 12;
@ -11178,7 +11299,7 @@ class serializer
case error_handler_t::strict: case error_handler_t::strict:
{ {
std::string sn(3, '\0'); std::string sn(3, '\0');
snprintf(&sn[0], sn.size(), "%.2X", byte); (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)); JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
} }
@ -11259,7 +11380,7 @@ class serializer
case error_handler_t::strict: case error_handler_t::strict:
{ {
std::string sn(3, '\0'); std::string sn(3, '\0');
snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back())); (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
} }
@ -11378,7 +11499,7 @@ class serializer
static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10; static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
// the actual conversion // the actual conversion
std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
// negative value indicates an error // negative value indicates an error
assert(len > 0); assert(len > 0);
@ -13208,7 +13329,7 @@ class basic_json
object = nullptr; // silence warning, see #821 object = nullptr; // silence warning, see #821
if (JSON_UNLIKELY(t == value_t::null)) if (JSON_UNLIKELY(t == value_t::null))
{ {
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.4.0")); // LCOV_EXCL_LINE JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.5.0")); // LCOV_EXCL_LINE
} }
break; break;
} }
@ -16599,9 +16720,20 @@ class basic_json
Range-based for loop with `items()` function: Range-based for loop with `items()` function:
@code{cpp} @code{cpp}
for (auto it : j_object.items()) for (auto& el : j_object.items())
{ {
std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; std::cout << "key: " << el.key() << ", value:" << el.value() << '\n';
}
@endcode
The `items()` function also allows to use
[structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)
(C++17):
@code{cpp}
for (auto& [key, val] : j_object.items())
{
std::cout << "key: " << key << ", value:" << val << '\n';
} }
@endcode @endcode
@ -16619,7 +16751,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@since version 3.1.0. @since version 3.1.0, structured bindings support since 3.5.0.
*/ */
iteration_proxy<iterator> items() noexcept iteration_proxy<iterator> items() noexcept
{ {
@ -20110,7 +20242,7 @@ class basic_json
Thereby, `Target` is the current object; that is, the patch is applied to Thereby, `Target` is the current object; that is, the patch is applied to
the current value. the current value.
@param[in] patch the patch to apply @param[in] apply_patch the patch to apply
@complexity Linear in the lengths of @a patch. @complexity Linear in the lengths of @a patch.
@ -20122,15 +20254,15 @@ class basic_json
@since version 3.0.0 @since version 3.0.0
*/ */
void merge_patch(const basic_json& patch) void merge_patch(const basic_json& apply_patch)
{ {
if (patch.is_object()) if (apply_patch.is_object())
{ {
if (not is_object()) if (not is_object())
{ {
*this = object(); *this = object();
} }
for (auto it = patch.begin(); it != patch.end(); ++it) for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
{ {
if (it.value().is_null()) if (it.value().is_null())
{ {
@ -20144,7 +20276,7 @@ class basic_json
} }
else else
{ {
*this = patch; *this = apply_patch;
} }
} }