From 60a0644ba122caea754bd9c9b6a4dd2c2f389e06 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 11 Oct 2026 08:46:11 +0200 Subject: [PATCH] Regenerate the amalgamated headers Signed-off-by: Niels Lohmann --- single_include/nlohmann/json.hpp | 78 +- single_include/nlohmann/json_view.hpp | 1201 ++++++++++++++++++++++++- 2 files changed, 1254 insertions(+), 25 deletions(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2471c44a5..0df60058c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3283,6 +3283,39 @@ enum class value_t : std::uint8_t discarded ///< discarded by the parser callback function }; +/*! +@brief the name of a JSON type, as returned by basic_json::type_name() + +Used in exception messages; also by code that reports types without a +basic_json value at hand (such as the zero-copy view). +*/ +inline const char* value_type_name(const value_t t) noexcept +{ + switch (t) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::binary: + return "binary"; + case value_t::discarded: + return "discarded"; + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + return "number"; + default: + return "invalid"; + } +} + /*! @brief comparison operator for JSON types @@ -20545,6 +20578,11 @@ NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +struct json_pointer_access; +} // namespace detail + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document /// @sa https://json.nlohmann.me/api/json_pointer/ template @@ -20557,6 +20595,8 @@ class json_pointer template friend class json_pointer; + friend struct detail::json_pointer_access; + template struct string_t_helper { @@ -21815,6 +21855,20 @@ inline bool operator<(const json_pointer& lhs, } #endif +namespace detail +{ +/// the reference tokens of a json_pointer, for code that resolves pointers +/// without a basic_json value (such as the zero-copy view) +struct json_pointer_access +{ + template + static const std::vector::string_t>& reference_tokens(const json_pointer& ptr) noexcept + { + return ptr.reference_tokens; + } +}; +} // namespace detail + NLOHMANN_JSON_NAMESPACE_END // #include @@ -35082,29 +35136,7 @@ public: JSON_HEDLEY_RETURNS_NON_NULL const char* type_name() const noexcept { - switch (m_data.m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::binary: - return "binary"; - case value_t::discarded: - return "discarded"; - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - return "number"; - default: - return "invalid"; - } + return detail::value_type_name(m_data.m_type); } JSON_PRIVATE_UNLESS_TESTED: diff --git a/single_include/nlohmann/json_view.hpp b/single_include/nlohmann/json_view.hpp index 91455bf4b..de979270e 100644 --- a/single_include/nlohmann/json_view.hpp +++ b/single_include/nlohmann/json_view.hpp @@ -28,10 +28,14 @@ #include // nullptr_t, size_t // IWYU pragma: keep #include // memcpy, strlen #include // distance, input_iterator_tag, iterator_traits +#include // map #include // unique_ptr #include // string -#include // enable_if, integral_constant, is_base_of, is_integral, is_same, remove_cv, remove_extent +#include // tuple_element, tuple_size // IWYU pragma: keep +#include // decay, enable_if, integral_constant, is_arithmetic, is_base_of, is_integral, is_same, remove_cv, remove_extent +#include // unordered_map #include // forward, move +#include // vector #include // IWYU pragma: export @@ -126,7 +130,10 @@ #elif defined(_MSC_VER) #define NLOHMANN_VIEW_LIKELY(x) (x) #define NLOHMANN_VIEW_UNLIKELY(x) (x) - #define NLOHMANN_VIEW_ALWAYS_INLINE __forceinline + // plain inline: __forceinline makes MSVC report C4714 (not inlined) for + // function templates it cannot inline, which is an error under /WX; the + // forced inlining is only a performance hint + #define NLOHMANN_VIEW_ALWAYS_INLINE inline #define NLOHMANN_VIEW_NOINLINE __declspec(noinline) #else #define NLOHMANN_VIEW_LIKELY(x) (x) @@ -1696,6 +1703,12 @@ namespace view NLOHMANN_VIEW_THROW(invalid_iterator::create(id, msg, nullptr)); } +/// a parse error without a position (as those of json_pointer) +[[noreturn]] NLOHMANN_VIEW_NOINLINE inline void throw_parse_error(int id, const std::string& msg) +{ + NLOHMANN_VIEW_THROW(parse_error::create(id, 0, msg, nullptr)); +} + /*! @brief throw the exception BasicJsonType::parse would throw for this input @@ -1837,6 +1850,441 @@ std::string collect_adapter(Adapter ia) } // namespace detail NLOHMANN_JSON_NAMESPACE_END +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // ptrdiff_t, size_t +#include // forward_iterator_tag +#include // string, to_string +#include // enable_if + +// #include +// #include + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace view +{ + +/// the result of view_iterator::operator->: keeps the view alive for the +/// duration of the member access +template +class arrow_proxy +{ + public: + explicit arrow_proxy(const View& v) noexcept + : m_view(v) + {} + + const View* operator->() const noexcept + { + return &m_view; + } + + private: + View m_view; +}; + +/*! +@brief forward iterator over the elements of a basic_json_view + +Iterates over the elements of an array or the member values of an object, in +document order; key() gives the key of an object member. As for basic_json, a +primitive value iterates as a range of one element (itself), and null as an +empty range. +*/ +template +class view_iterator +{ + public: + using iterator_category = std::forward_iterator_tag; + using value_type = View; + using difference_type = std::ptrdiff_t; + using pointer = arrow_proxy; + using reference = View; + using string_view_t = typename View::string_view_t; + + view_iterator() noexcept = default; + + /// @param[in] pos the element, or the key of the member + /// @param[in] object whether pos is a key (its value is the next node) + view_iterator(const document_data* d, const node* pos, bool object) noexcept + : m_doc(d), m_pos(pos), m_value_offset(object ? 1 : 0) + {} + + NLOHMANN_VIEW_ALWAYS_INLINE View operator*() const noexcept + { + return View(m_doc, m_pos + m_value_offset); + } + + pointer operator->() const noexcept + { + return pointer(**this); + } + + NLOHMANN_VIEW_ALWAYS_INLINE view_iterator& operator++() noexcept + { + m_pos = document_data::after(m_pos + m_value_offset); + return *this; + } + + view_iterator operator++(int) noexcept + { + const view_iterator r = *this; + ++*this; + return r; + } + + friend bool operator==(const view_iterator& a, const view_iterator& b) noexcept + { + return a.m_pos == b.m_pos; + } + + friend bool operator!=(const view_iterator& a, const view_iterator& b) noexcept + { + return a.m_pos != b.m_pos; + } + + /// the key of the current object member; throws invalid_iterator.207 for + /// other iterators, like basic_json's iterators + string_view_t key() const + { + if (NLOHMANN_VIEW_UNLIKELY(m_value_offset == 0)) + { + throw_invalid_iterator(207, "cannot use key() for non-object iterators"); + } + return string_view_t(m_doc->str(*m_pos), m_pos->len); + } + + View value() const noexcept + { + return **this; + } + + /// whether the iterator runs over the members of an object + bool is_object_iterator() const noexcept + { + return m_value_offset != 0; + } + + private: + const document_data* m_doc = nullptr; + const node* m_pos = nullptr; + std::size_t m_value_offset = 0; ///< 1 for objects: the value follows its key +}; + +/*! +@brief a (key, value) item of basic_json_view::items() + +The key of an array element is its index, as for basic_json::items(). +Supports structured bindings: for (const auto [key, value] : view.items()) +*/ +template +class view_item +{ + public: + using string_view_t = typename View::string_view_t; + using iterator = view_iterator; + + view_item(const iterator& it, std::size_t index) + : m_it(it) + { + if (!it.is_object_iterator()) + { + m_index = std::to_string(index); + } + } + + /// the member key, or the element index for arrays + string_view_t key() const + { + if (m_it.is_object_iterator()) + { + return m_it.key(); + } + return string_view_t(m_index.data(), m_index.size()); + } + + View value() const noexcept + { + return *m_it; + } + + template::type = 0> + string_view_t get() const + { + return key(); + } + + template::type = 0> + View get() const noexcept + { + return value(); + } + + private: + iterator m_it; + std::string m_index{}; // NOLINT(readability-redundant-member-init) +}; + +/// the range returned by basic_json_view::items() +template +class view_items +{ + public: + using item = view_item; + + class iterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = item; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = item; + + explicit iterator(const view_iterator& it) noexcept + : m_it(it) + {} + + item operator*() const + { + return item(m_it, m_index); + } + + iterator& operator++() noexcept + { + ++m_it; + ++m_index; + return *this; + } + + iterator operator++(int) noexcept + { + const iterator r = *this; + ++*this; + return r; + } + + friend bool operator==(const iterator& a, const iterator& b) noexcept + { + return a.m_it == b.m_it; + } + + friend bool operator!=(const iterator& a, const iterator& b) noexcept + { + return a.m_it != b.m_it; + } + + private: + view_iterator m_it; + std::size_t m_index = 0; + }; + + explicit view_items(const View& v) noexcept + : m_view(v) + {} + + iterator begin() const noexcept + { + return iterator(m_view.begin()); + } + + iterator end() const noexcept + { + return iterator(m_view.end()); + } + + private: + View m_view; +}; + +} // namespace view +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t +#include // uint16_t, uint32_t, uint64_t +#include // memcmp, memcpy +#include // numeric_limits +#include // integral_constant, is_integral, is_same + +// #include +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace view +{ + +/// equality test for strings of one length n <= 16: two overlapping loads per +/// string (the first and the last 8, 4, or 2 bytes) replace a memcmp, and no +/// byte outside [s, s + n) is read +class short_key +{ + public: + short_key(const unsigned char* k, std::size_t n) noexcept + : m_n(n) + { + load(k, m_a, m_b); + } + + NLOHMANN_VIEW_ALWAYS_INLINE bool matches(const unsigned char* s) const noexcept + { + std::uint64_t a = 0; + std::uint64_t b = 0; + load(s, a, b); + return a == m_a && b == m_b; + } + + private: + template + static NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t load_word(const unsigned char* s) noexcept + { + T w = 0; + std::memcpy(&w, s, sizeof(T)); + return w; + } + + NLOHMANN_VIEW_ALWAYS_INLINE void load(const unsigned char* s, std::uint64_t& a, std::uint64_t& b) const noexcept + { + if (m_n >= 8) + { + a = load_word(s); + b = load_word(s + m_n - 8); + } + else if (m_n >= 4) + { + a = load_word(s); + b = load_word(s + m_n - 4); + } + else if (m_n >= 2) + { + a = load_word(s); + b = load_word(s + m_n - 2); + } + else + { + a = m_n == 1 ? s[0] : 0; + b = 0; + } + } + + std::size_t m_n; + std::uint64_t m_a = 0; + std::uint64_t m_b = 0; +}; + +/// the key node of the first member of an object with the given key, or +/// nullptr (the search stops at the first match; materialize() and parse() +/// keep the last value of a duplicate key instead); most keys are rejected by +/// their length, from the index alone +inline const node* find_member(const document_data& d, const node* object, const char* key, std::size_t n) noexcept +{ + const node* const end = document_data::child_end(object); + const auto* const k = reinterpret_cast(key); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + if (NLOHMANN_VIEW_LIKELY(n <= 16)) + { + const short_key probe(k, n); + for (const node* m = document_data::first_child(object); m != end; m = document_data::after(m + 1)) + { + if (m->len == n && probe.matches(reinterpret_cast(d.str(*m)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + { + return m; + } + } + return nullptr; + } + for (const node* m = document_data::first_child(object); m != end; m = document_data::after(m + 1)) + { + if (m->len == n && std::memcmp(d.str(*m), key, n) == 0) + { + return m; + } + } + return nullptr; +} + +/// whether an integer type is accepted as an array index by the view's +/// operator[] and at(): every integer type but bool and size_t, which has its +/// own overload +template +struct is_index_type : std::integral_constant < bool, + std::is_integral::value && !std::is_same::value && !std::is_same::value > +{}; + +/// an integer as an index: negative values, and values that do not fit a +/// size_t, map to the largest size_t (out of range for every array) +template +SizeType to_index(IntegerType idx) noexcept +{ + const IntegerType zero = 0; + const auto result = static_cast(idx); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): negative values are mapped below + return (idx < zero || static_cast(result) != idx) ? (std::numeric_limits::max)() : result; +} + +/// the element of an array at an index below its size +inline const node* element_at(const node* array, std::size_t idx) noexcept +{ + const node* e = document_data::first_child(array); + for (std::size_t i = 0; i < idx; ++i) + { + e = document_data::after(e); + } + return e; +} + +/// the last element of a non-empty array, or the key of the last member of a +/// non-empty object +inline const node* last_child(const node* container) noexcept +{ + const std::size_t value_offset = container->kind == static_cast(value_t::object) ? 1 : 0; + const node* const end = document_data::child_end(container); + const node* last = document_data::first_child(container); + for (const node* c = document_data::after(last + value_offset); c != end; c = document_data::after(c + value_offset)) + { + last = c; + } + return last; +} + +} // namespace view +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + // #include // #include @@ -2047,6 +2495,181 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t +#include // uint64_t +#include // numeric_limits +#include // string, to_string + +// #include +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace view +{ + +/// what resolving a JSON pointer does where it cannot continue +enum class pointer_mode +{ + unchecked, ///< as const basic_json::operator[]: a discarded view where basic_json's behavior is undefined + checked, ///< as basic_json::at(): out_of_range.401/403 + value, ///< as basic_json::value(): no out_of_range exceptions (the default value is used) + contains, ///< as basic_json::contains(): no exceptions at all +}; + +/// the outcome of reading an array index from a reference token +enum class index_status +{ + ok, + leading_zero, ///< parse_error.106 + not_number, ///< parse_error.109 + unresolved, ///< out_of_range.404 + too_large, ///< out_of_range.410 +}; + +/// reads an array index like json_pointer::array_index (RFC 6901, Sect. 4), +/// but reports errors instead of throwing them +template +index_status array_index(const StringType& s, std::size_t& idx) noexcept +{ + if (s.size() > 1 && s[0] == '0') + { + return index_status::leading_zero; + } + if (s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')) + { + return index_status::not_number; + } + if (s.empty()) + { + return index_status::unresolved; + } + std::uint64_t v = 0; + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto d = static_cast(static_cast(s[i])) - '0'; + if (d > 9 || v > ((std::numeric_limits::max)() - d) / 10) + { + return index_status::unresolved; // not a number, or beyond unsigned long long + } + v = (v * 10) + d; + } + if (v >= (std::numeric_limits::max)()) // (std::size_t converts to std::uint64_t implicitly) + { + return index_status::too_large; + } + idx = static_cast(v); + return index_status::ok; +} + +/// throws the exception json_pointer::array_index throws for this status +template +[[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_error(index_status status, const StringType& s) +{ + switch (status) + { + case index_status::leading_zero: + throw_parse_error(106, concat("array index '", s, "' must not begin with '0'")); + case index_status::not_number: + throw_parse_error(109, concat("array index '", s, "' is not a number")); + case index_status::too_large: + throw_out_of_range(410, concat("array index ", s, " exceeds size_type")); // LCOV_EXCL_LINE + case index_status::unresolved: + case index_status::ok: + default: + throw_out_of_range(404, concat("unresolved reference token '", s, "'")); + } +} + +/*! +@brief resolve the reference tokens of a JSON pointer, starting at a view + +The exceptions are those basic_json throws for the same pointer; where +basic_json's behavior is undefined (a missing key or an index out of range +with const operator[]), the result is a discarded view. +*/ +template +View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode) +{ + using string_view_t = typename View::string_view_t; + const bool throwing = mode == pointer_mode::unchecked || mode == pointer_mode::checked; + for (const auto& token : tokens) + { + if (cur.is_object()) + { + const auto it = cur.find(string_view_t(token.data(), token.size())); + if (it == cur.end()) + { + if (mode == pointer_mode::checked) + { + throw_out_of_range(403, concat("key '", token, "' not found")); + } + return View(); + } + cur = *it; + } + else if (cur.is_array()) + { + if (token.size() == 1 && token[0] == '-') + { + if (throwing) + { + throw_out_of_range(402, concat("array index '-' (", std::to_string(cur.size()), ") is out of range")); + } + return View(); + } + std::size_t idx = 0; + const index_status status = array_index(token, idx); + if (status != index_status::ok) + { + const bool parse_error = status == index_status::leading_zero || status == index_status::not_number; + if (throwing || (mode == pointer_mode::value && parse_error)) + { + throw_array_index_error(status, token); + } + return View(); + } + if (idx >= cur.size()) + { + if (mode == pointer_mode::checked) + { + throw_out_of_range(401, concat("array index ", std::to_string(idx), " is out of range")); + } + return View(); + } + cur = cur[idx]; + } + else + { + if (throwing) + { + throw_out_of_range(404, concat("unresolved reference token '", token, "'")); + } + return View(); + } + } + return cur; +} + +} // namespace view +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -2163,6 +2786,121 @@ class string_ref } // namespace detail NLOHMANN_JSON_NAMESPACE_END +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // int64_t +#include // map +#include // basic_string +#include // enable_if, is_constructible +#include // unordered_map +#include // vector + +// #include +// #include + +// #include + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace view +{ + +/// selects a conversion by its target type +template +struct value_tag {}; + +/*! +@brief the number or boolean of a node converted to an arithmetic type + +As basic_json's get() for arithmetic types: integers and floats are +converted with static_cast, booleans give 0 or 1, and other types throw +type_error.302. +*/ +template +NLOHMANN_VIEW_ALWAYS_INLINE T arithmetic_value(const document_data& d, const node& n) +{ + switch (static_cast(n.kind)) + { + case value_t::number_unsigned: + return static_cast(static_cast(integer_bits(n))); + case value_t::number_integer: + return static_cast(static_cast(static_cast(integer_bits(n)))); + case value_t::number_float: + return static_cast(float_value(d.str(n), n)); + case value_t::boolean: + return static_cast((n.flags & node_flags::is_true) != 0); + 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: + throw_type_error(302, "type must be number, but is ", value_type_name(static_cast(n.kind))); + } +} + +/// std::vector from an array, element by element (type_error.302 otherwise) +template +std::vector vector_value(const View& v) +{ + if (NLOHMANN_VIEW_UNLIKELY(!v.is_array())) + { + throw_type_error(302, "type must be array, but is ", v.type_name()); + } + std::vector r; + r.reserve(v.size()); + for (const View e : v) + { + r.push_back(e.template get()); + } + return r; +} + +/// a map with string keys from an object; with duplicate keys, the last +/// value is kept, as parse() does (type_error.302 for other types) +template +Map map_value(const View& v) +{ + if (NLOHMANN_VIEW_UNLIKELY(!v.is_object())) + { + throw_type_error(302, "type must be object, but is ", v.type_name()); + } + Map r; + for (auto it = v.begin(); it != v.end(); ++it) + { + const auto key = it.key(); + r[typename Map::key_type(key.data(), key.size())] = it.value().template get(); + } + return r; +} + +/// whether a map type is read member by member (its keys are made from +/// characters and a length); other maps go through basic_json +template +struct is_string_key : std::is_constructible {}; + +} // namespace view +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + NLOHMANN_JSON_NAMESPACE_BEGIN @@ -2188,6 +2926,11 @@ class basic_json_view using size_type = std::size_t; /// std::string_view from C++17 on using string_view_t = detail::view::string_ref; + /// forward iterator over elements (arrays) or member values (objects) + using iterator = detail::view::view_iterator; + using const_iterator = iterator; + /// a (key, value) item of items() + using item = detail::view::view_item; /// an invalid view (type() == value_t::discarded) basic_json_view() noexcept = default; @@ -2269,6 +3012,12 @@ class basic_json_view return type() == value_t::discarded; } + /// the name of the type, as basic_json::type_name() + const char* type_name() const noexcept + { + return detail::value_type_name(type()); + } + ////////////// // capacity // ////////////// @@ -2318,6 +3067,343 @@ class basic_json_view } } + //////////////////// + // element access // + //////////////////// + + /// the value of the member with this key (the first one, should the key + /// occur more than once); a discarded view if there is none, or if this + /// is a discarded view (so that v["a"]["b"] is safe). Throws type_error.305 + /// if this is any other value but an object. + NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view operator[](string_view_t key) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_object())) + { + if (is_discarded()) + { + return basic_json_view(); + } + detail::view::throw_type_error(305, "cannot use operator[] with a string argument with ", type_name()); + } + return lookup(key); + } + + basic_json_view operator[](const char* key) const + { + return operator[](string_view_t(key)); + } + + basic_json_view operator[](const string_t& key) const + { + return operator[](string_view_t(key.data(), key.size())); + } + + /// the element at this index; a discarded view if the index is out of + /// range, or if this is a discarded view. Throws type_error.305 if this is + /// any other value but an array. + basic_json_view operator[](size_type idx) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_array())) + { + if (is_discarded()) + { + return basic_json_view(); + } + detail::view::throw_type_error(305, "cannot use operator[] with a numeric argument with ", type_name()); + } + return idx < m_node->len ? basic_json_view(m_doc, detail::view::element_at(m_node, idx)) : basic_json_view(); + } + + /// any other integer type (int, unsigned, long, std::int64_t, ...; a + /// single overload for size_type alone would be ambiguous for all of them + /// and for const char*); negative values are out of range + template < typename IntegerType, typename std::enable_if < detail::view::is_index_type::value, int >::type = 0 > + basic_json_view operator[](IntegerType idx) const + { + return operator[](detail::view::to_index(idx)); + } + + /// the value a JSON pointer refers to; a discarded view if a key is + /// missing or an index is out of range, or if this is a discarded view. + /// Other errors throw what const basic_json::operator[] throws. + basic_json_view operator[](const json_pointer& ptr) const + { + if (NLOHMANN_VIEW_UNLIKELY(is_discarded())) + { + return basic_json_view(); + } + return detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::unchecked); + } + + /// the value of the member with this key (the first one, should the key + /// occur more than once). Throws type_error.304 if this is not an object, + /// and out_of_range.403 if there is no such member. + basic_json_view at(string_view_t key) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_object())) + { + detail::view::throw_type_error(304, "cannot use at() with ", type_name()); + } + const basic_json_view r = lookup(key); + if (NLOHMANN_VIEW_UNLIKELY(r.is_discarded())) + { + detail::view::throw_out_of_range(403, detail::concat("key '", std::string(key.data(), key.size()), "' not found")); + } + return r; + } + + basic_json_view at(const char* key) const + { + return at(string_view_t(key)); + } + + basic_json_view at(const string_t& key) const + { + return at(string_view_t(key.data(), key.size())); + } + + /// the element at this index. Throws type_error.304 if this is not an + /// array, and out_of_range.401 if the index is out of range. + basic_json_view at(size_type idx) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_array())) + { + detail::view::throw_type_error(304, "cannot use at() with ", type_name()); + } + if (NLOHMANN_VIEW_UNLIKELY(idx >= m_node->len)) + { + detail::view::throw_out_of_range(401, detail::concat("array index ", std::to_string(idx), " is out of range")); + } + return basic_json_view(m_doc, detail::view::element_at(m_node, idx)); + } + + /// any other integer type, see operator[]; negative values are out of + /// range + template < typename IntegerType, typename std::enable_if < detail::view::is_index_type::value, int >::type = 0 > + basic_json_view at(IntegerType idx) const + { + return at(detail::view::to_index(idx)); + } + + /// the value a JSON pointer refers to; throws what basic_json::at() + /// throws if it cannot be resolved + basic_json_view at(const json_pointer& ptr) const + { + return detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::checked); + } + + /// the member with this key converted to T, or the default value if there + /// is no such member (the first one, should the key occur more than + /// once). Throws type_error.306 if this is not an object. + template < typename T, typename std::enable_if < !std::is_same::type, const char*>::value, int >::type = 0 > + T value(string_view_t key, const T& default_value) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_object())) + { + detail::view::throw_type_error(306, "cannot use value() with ", type_name()); + } + const basic_json_view r = lookup(key); + return r.is_discarded() ? default_value : r.template get(); + } + + string_t value(string_view_t key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /// the value a JSON pointer refers to converted to T, or the default + /// value if the pointer cannot be resolved. Throws type_error.306 if this + /// is neither an object nor an array. + template < typename T, typename std::enable_if < !std::is_same::type, const char*>::value, int >::type = 0 > + T value(const json_pointer& ptr, const T& default_value) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_structured())) + { + detail::view::throw_type_error(306, "cannot use value() with ", type_name()); + } + const basic_json_view r = detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::value); + return r.is_discarded() ? default_value : r.template get(); + } + + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /// the first element or member value; a primitive value itself. Throws + /// invalid_iterator.214 for null, discarded views, and empty containers. + basic_json_view front() const + { + const iterator it = begin(); + if (NLOHMANN_VIEW_UNLIKELY(it == end())) + { + detail::view::throw_invalid_iterator(214, "cannot get value"); + } + return *it; + } + + /// the last element or member value (linear in the size); a primitive + /// value itself. Throws invalid_iterator.214 for null, discarded views, + /// and empty containers. + basic_json_view back() const + { + if (is_structured() && m_node->len != 0) + { + return basic_json_view(m_doc, detail::view::last_child(m_node) + (is_object() ? 1 : 0)); + } + return front(); + } + + //////////// + // lookup // + //////////// + + /// an iterator to the member with this key (the first one, should the + /// key occur more than once), or end(); end() also for non-objects + iterator find(string_view_t key) const + { + if (!is_object()) + { + return end(); + } + const node* const k = detail::view::find_member(*m_doc, m_node, key.data(), key.size()); + return k != nullptr ? iterator(m_doc, k, true) : end(); + } + + iterator find(const char* key) const + { + return find(string_view_t(key)); + } + + iterator find(const string_t& key) const + { + return find(string_view_t(key.data(), key.size())); + } + + /// whether this is an object with a member with this key + bool contains(string_view_t key) const + { + return is_object() && detail::view::find_member(*m_doc, m_node, key.data(), key.size()) != nullptr; + } + + bool contains(const char* key) const + { + return contains(string_view_t(key)); + } + + bool contains(const string_t& key) const + { + return contains(string_view_t(key.data(), key.size())); + } + + /// whether a JSON pointer can be resolved (never throws, as + /// basic_json::contains()) + bool contains(const json_pointer& ptr) const + { + return !detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::contains).is_discarded(); + } + + /// 1 if this is an object with a member with this key, else 0 (duplicate + /// keys count once) + size_type count(string_view_t key) const + { + return contains(key) ? 1 : 0; + } + + size_type count(const char* key) const + { + return count(string_view_t(key)); + } + + size_type count(const string_t& key) const + { + return count(string_view_t(key.data(), key.size())); + } + + /////////////// + // iteration // + /////////////// + + /// the first element or member value, in document order; a primitive + /// value is a range of one element (itself), null an empty range + NLOHMANN_VIEW_ALWAYS_INLINE iterator begin() const noexcept + { + if (NLOHMANN_VIEW_LIKELY(is_structured())) + { + return iterator(m_doc, document_data::first_child(m_node), is_object()); + } + return iterator(m_doc, m_node, false); + } + + NLOHMANN_VIEW_ALWAYS_INLINE iterator end() const noexcept + { + if (NLOHMANN_VIEW_LIKELY(is_structured())) + { + return iterator(m_doc, document_data::child_end(m_node), is_object()); + } + return iterator(m_doc, (is_null() || is_discarded()) ? m_node : m_node + 1, false); + } + + iterator cbegin() const noexcept + { + return begin(); + } + + iterator cend() const noexcept + { + return end(); + } + + /// (key, value) items; the key of an array element is its index + detail::view::view_items items() const noexcept + { + return detail::view::view_items(*this); + } + + //////////////// + // conversion // + //////////////// + + /// the value converted to T, as BasicJsonType::get(): arithmetic types, + /// strings (string_view_t without a copy), std::nullptr_t, std::vector, + /// maps with string keys, and views are converted directly; other types + /// through materialize().get() + template + NLOHMANN_VIEW_ALWAYS_INLINE T get() const + { + return get_impl(detail::view::value_tag {}, detail::priority_tag<2> {}); + } + + template + T& get_to(T& v) const + { + v = get(); + return v; + } + + /// the string, without a copy; valid as long as the view is. Throws + /// type_error.302 for other types. + string_view_t get_string() const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_string())) + { + detail::view::throw_type_error(302, "type must be string, but is ", type_name()); + } + return {m_doc->str(*m_node), m_node->len}; + } + + /// the text of a number as it appears in the source (e.g. "1.50", "1E2", + /// or an integer with more digits than any number type holds). Throws + /// type_error.302 for other types. + string_view_t number_token() const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_number())) + { + detail::view::throw_type_error(302, "type must be number, but is ", type_name()); + } + return {m_doc->str(*m_node), detail::view::number_length(*m_node)}; + } + ///////////////// // materialize // ///////////////// @@ -2344,11 +3430,97 @@ class basic_json_view private: template friend class basic_json_document; + friend iterator; basic_json_view(const document_data* d, const node* n) noexcept : m_doc(d), m_node(n) {} + /// the value of the first member with this key, or a discarded view + /// (object required) + NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view lookup(string_view_t key) const noexcept + { + const node* const k = detail::view::find_member(*m_doc, m_node, key.data(), key.size()); + return k != nullptr ? basic_json_view(m_doc, k + 1) : basic_json_view(); + } + + // --- get() dispatch --- + + bool get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<2> /*unused*/) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_boolean())) + { + detail::view::throw_type_error(302, "type must be boolean, but is ", type_name()); + } + return (m_node->flags & detail::view::node_flags::is_true) != 0; + } + + template < typename T, typename std::enable_if < std::is_arithmetic::value && !std::is_same::value, int >::type = 0 > + NLOHMANN_VIEW_ALWAYS_INLINE T get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<2> /*unused*/) const + { + if (NLOHMANN_VIEW_UNLIKELY(m_node == nullptr)) + { + detail::view::throw_type_error(302, "type must be number, but is ", type_name()); + } + return detail::view::arithmetic_value(*m_doc, *m_node); + } + + std::nullptr_t get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<2> /*unused*/) const + { + if (NLOHMANN_VIEW_UNLIKELY(!is_null())) + { + detail::view::throw_type_error(302, "type must be null, but is ", type_name()); + } + return nullptr; + } + + string_view_t get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<2> /*unused*/) const + { + return get_string(); + } + + template + std::basic_string get_impl(detail::view::value_tag> /*unused*/, detail::priority_tag<2> /*unused*/) const + { + const string_view_t s = get_string(); + return std::basic_string(s.data(), s.size()); + } + + BasicJsonType get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<2> /*unused*/) const + { + return materialize(); + } + + basic_json_view get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<2> /*unused*/) const noexcept + { + return *this; + } + + template + std::vector get_impl(detail::view::value_tag> /*unused*/, detail::priority_tag<2> /*unused*/) const + { + return detail::view::vector_value(*this); + } + + template::value, int>::type = 0> + std::map get_impl(detail::view::value_tag> /*unused*/, detail::priority_tag<2> /*unused*/) const + { + return detail::view::map_value>(*this); + } + + template::value, int>::type = 0> + std::unordered_map get_impl(detail::view::value_tag> /*unused*/, detail::priority_tag<2> /*unused*/) const + { + return detail::view::map_value>(*this); + } + + /// everything else through the BasicJsonType value (from_json included) + template + T get_impl(detail::view::value_tag /*unused*/, detail::priority_tag<0> /*unused*/) const + { + return materialize().template get(); + } + const document_data* m_doc = nullptr; const node* m_node = nullptr; }; @@ -2720,6 +3892,31 @@ using ordered_json_view = basic_json_view; NLOHMANN_JSON_NAMESPACE_END +// tuple protocol for the items of basic_json_view::items() (structured bindings) +namespace std // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification) +{ + +#if defined(__clang__) + // Fix: https://github.com/nlohmann/json/issues/1401 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +class tuple_size<::nlohmann::detail::view::view_item> // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification) + : public std::integral_constant {}; + +template +class tuple_element> // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification) +{ + public: + using type = decltype(std::declval<::nlohmann::detail::view::view_item>().template get()); +}; +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +} // namespace std + // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++