// __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ // | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once #include // max #include // size_t #include // int64_t, uint8_t #include // string #include // vector #include #include #include #include #include NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { namespace view { /*! @brief the basic_json value of the subtree at n The subtree is replayed into the SAX handler that parse() uses to build its values, so the result is the value parse() would produce: duplicate keys keep the last value, and with JSON_DIAGNOSTICS the parent pointers are set. It is iterative, so the nesting depth is limited by memory only, as for parse(). Without a lexer the handler records no source positions (JSON_DIAGNOSTIC_POSITIONS). */ template BasicJsonType materialize(const document_data& d, const node* n) { using string_t = typename BasicJsonType::string_t; using sax_t = json_sax_dom_parser>; using nav = navigation; // the open containers: their next element (or key of the next member), // their end, and whether they are objects; sized once from the // document's deepest nesting (for a subtree an upper bound) struct frame { const node* pos; const node* end; bool object; }; BasicJsonType result; sax_t sax(result, true); const string_t no_token{}; std::vector open((std::max)(d.max_depth, std::size_t{1})); std::size_t depth = 0; for (;;) { // false positive: n comes from nav::value(), which never returns null for a valid index // @infer-ignore NULLPTR_DEREFERENCE switch (static_cast(n->kind)) { case value_t::object: case value_t::array: { const bool object = n->kind == static_cast(value_t::object); if (object) { sax.start_object(n->len); } else { sax.start_array(n->len); } if (NLOHMANN_VIEW_UNLIKELY(depth == open.size())) { open.resize(depth * 2); // (deeper than the recorded nesting, e.g. after edits) } open[depth++] = frame{nav::first(d, n), nav::end(d, n), object}; break; } case value_t::string: { string_t s(d.str(*n), n->len); sax.string(s); break; } case value_t::number_integer: sax.number_integer(static_cast(static_cast(integer_bits(*n)))); break; case value_t::number_unsigned: sax.number_unsigned(static_cast(integer_bits(*n))); break; case value_t::number_float: sax.number_float(float_value(d, *n), no_token); break; case value_t::boolean: sax.boolean((n->flags & node_flags::is_true) != 0); break; case value_t::null: case value_t::binary: case value_t::discarded: default: sax.null(); break; } // the next value: close finished containers, then read the key for (;;) { if (depth == 0) { return result; } frame& f = open[depth - 1]; if (f.pos == f.end) { if (f.object) { sax.end_object(); } else { sax.end_array(); } --depth; continue; } const node* entry = f.pos; if (f.object) { string_t key(d.str(*entry), entry->len); sax.key(key); ++entry; } n = nav::value(entry); f.pos = document_data::after(entry); break; } } } } // namespace view } // namespace detail NLOHMANN_JSON_NAMESPACE_END