mirror of
https://github.com/nlohmann/json.git
synced 2026-10-07 15:07:13 +00:00
Add json_document and json_view: node index, parser, and document
Add json_document and json_view, a read-only, zero-copy index of a JSON text, as the first public slice of the zero-copy view (#5295). A parse produces a flat array of 16-byte nodes in document order, one per value and one per object key. Strings stay in the source text; escaped strings are decoded into an arena. Integers are converted while their digits are in the cache; floats keep only their digit layout and are converted on read. Containers store the size of their subtree, so a reader can step over one in constant time. A document makes a handful of allocations, however many values it has. The parser accepts exactly what json::parse accepts, with every combination of ignore_comments and ignore_trailing_commas, with and without a trailing NUL, and under JSON_STRICT_NUL_HANDLING. It is portable C++11 and does not depend on byte order. basic_json_document adds parse, parse_copy, accept, read (reuses a document's memory), root, is_discarded, source, owns_source, node_count, memory_usage, and shrink_to_fit. basic_json_view adds type, the is_* queries, operator bool, size, empty, materialize, and source_offset. A parse error throws the same exception basic_json::parse would throw for the same input, message and position included. detail::abi_config keeps JSON_STRICT_NUL_HANDLING and JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON readable after json.hpp undefines them, in the ABI namespace so they always match the basic_json in use. A NUL byte that ends a // comment is the end of the input, as in parse() since #5696. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
17842694f6
commit
4303ba674d
146 files changed
+9611
-13
No files matched your search
@@ -0,0 +1,131 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // int64_t, uint8_t
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/document_data.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
#include <nlohmann/detail/view/number.hpp>
|
||||
|
||||
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<typename BasicJsonType>
|
||||
BasicJsonType materialize(const document_data& d, const node* n)
|
||||
{
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using sax_t = json_sax_dom_parser<BasicJsonType, iterator_input_adapter<const char*>>;
|
||||
|
||||
BasicJsonType result;
|
||||
sax_t sax(result, true);
|
||||
const string_t no_token{};
|
||||
// the ends of the open containers, and whether they are objects
|
||||
std::vector<std::pair<const node*, bool>> open;
|
||||
for (;;)
|
||||
{
|
||||
switch (static_cast<value_t>(n->kind))
|
||||
{
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
{
|
||||
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
|
||||
if (object)
|
||||
{
|
||||
sax.start_object(n->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
sax.start_array(n->len);
|
||||
}
|
||||
open.emplace_back(document_data::child_end(n), object);
|
||||
n = document_data::first_child(n);
|
||||
break;
|
||||
}
|
||||
case value_t::string:
|
||||
{
|
||||
string_t s(d.str(*n), n->len);
|
||||
sax.string(s);
|
||||
++n;
|
||||
break;
|
||||
}
|
||||
case value_t::number_integer:
|
||||
sax.number_integer(static_cast<typename BasicJsonType::number_integer_t>(static_cast<std::int64_t>(integer_bits(*n))));
|
||||
++n;
|
||||
break;
|
||||
case value_t::number_unsigned:
|
||||
sax.number_unsigned(static_cast<typename BasicJsonType::number_unsigned_t>(integer_bits(*n)));
|
||||
++n;
|
||||
break;
|
||||
case value_t::number_float:
|
||||
sax.number_float(float_value<typename BasicJsonType::number_float_t>(d.str(*n), *n), no_token);
|
||||
++n;
|
||||
break;
|
||||
case value_t::boolean:
|
||||
sax.boolean((n->flags & node_flags::is_true) != 0);
|
||||
++n;
|
||||
break;
|
||||
case value_t::null:
|
||||
case value_t::binary:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
sax.null();
|
||||
++n;
|
||||
break;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
if (open.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (n != open.back().first)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (open.back().second)
|
||||
{
|
||||
sax.end_object();
|
||||
}
|
||||
else
|
||||
{
|
||||
sax.end_array();
|
||||
}
|
||||
open.pop_back();
|
||||
}
|
||||
if (open.back().second)
|
||||
{
|
||||
// the key of the next member
|
||||
string_t key(d.str(*n), n->len);
|
||||
sax.key(key);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
Reference in new issue
Block a user