mirror of
https://github.com/nlohmann/json.git
synced 2026-09-29 19:20:30 +00:00
Add the node index and scanning primitives of json_view (internal)
Internal parts of the zero-copy view (#5295), under detail/view and not included by json.hpp, so that users of json.hpp compile nothing of it: - macro_scope.hpp/macro_unscope.hpp: the few macros the view needs, under its own prefix (json.hpp undefines its own at its end); the throw macro honors JSON_NOEXCEPTION and JSON_THROW_USER like JSON_THROW - string_ref.hpp: std::string_view from C++17 on, else a small stand-in - node.hpp: the 16-byte node of the index; its kinds are value_t values (checked by a static_assert) - document_data.hpp: the storage of a parsed document (node array, decode arena, owned input) - scan.hpp: string and digit scanning with unrolled checks at fixed offsets (after yyjson) and the library's SWAR and UTF-8 checks, independent of the byte order Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -66,6 +66,12 @@ cc_library(
|
|||||||
"include/nlohmann/detail/string_escape.hpp",
|
"include/nlohmann/detail/string_escape.hpp",
|
||||||
"include/nlohmann/detail/string_utils.hpp",
|
"include/nlohmann/detail/string_utils.hpp",
|
||||||
"include/nlohmann/detail/value_t.hpp",
|
"include/nlohmann/detail/value_t.hpp",
|
||||||
|
"include/nlohmann/detail/view/document_data.hpp",
|
||||||
|
"include/nlohmann/detail/view/macro_scope.hpp",
|
||||||
|
"include/nlohmann/detail/view/macro_unscope.hpp",
|
||||||
|
"include/nlohmann/detail/view/node.hpp",
|
||||||
|
"include/nlohmann/detail/view/scan.hpp",
|
||||||
|
"include/nlohmann/detail/view/string_ref.hpp",
|
||||||
"include/nlohmann/json.hpp",
|
"include/nlohmann/json.hpp",
|
||||||
"include/nlohmann/json_fwd.hpp",
|
"include/nlohmann/json_fwd.hpp",
|
||||||
"include/nlohmann/ordered_map.hpp",
|
"include/nlohmann/ordered_map.hpp",
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | 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 <cstddef> // size_t
|
||||||
|
#include <cstring> // memcpy
|
||||||
|
#include <new> // operator new, placement new
|
||||||
|
#include <string> // string
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/view/node.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace view
|
||||||
|
{
|
||||||
|
|
||||||
|
/// storage of a parsed document; heap-allocated (header and an initial node
|
||||||
|
/// array in one block) so that views survive moves of the owning document
|
||||||
|
struct document_data
|
||||||
|
{
|
||||||
|
const char* src = nullptr;
|
||||||
|
std::size_t size = 0;
|
||||||
|
node* tape = nullptr;
|
||||||
|
std::size_t tape_size = 0;
|
||||||
|
std::size_t tape_cap = 0;
|
||||||
|
node* inline_tape = nullptr; ///< node array allocated together with this header
|
||||||
|
std::size_t inline_cap = 0;
|
||||||
|
std::string arena{}; ///< decoded strings that contained escapes
|
||||||
|
std::string owned{}; ///< owned copy of the input, if any
|
||||||
|
const char* base[4] = {nullptr, nullptr, nullptr, nullptr}; ///< string bases: source, arena (indexed by flags & node_flags::storage)
|
||||||
|
bool discarded = true;
|
||||||
|
|
||||||
|
/// one allocation for the header and room for `nodes` nodes; large
|
||||||
|
/// documents get a separate node array instead (so it can be trimmed)
|
||||||
|
static document_data* create(std::size_t nodes)
|
||||||
|
{
|
||||||
|
nodes = nodes <= 256 ? nodes : 0;
|
||||||
|
void* mem = ::operator new (sizeof(document_data) + (nodes * sizeof(node)));
|
||||||
|
auto* d = new (mem) document_data();
|
||||||
|
d->inline_tape = static_cast<node*>(static_cast<void*>(static_cast<char*>(mem) + sizeof(document_data))); // (aligned: sizeof is a multiple of the alignment)
|
||||||
|
d->inline_cap = nodes;
|
||||||
|
d->tape = d->inline_tape;
|
||||||
|
d->tape_cap = nodes;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct deleter
|
||||||
|
{
|
||||||
|
void operator()(document_data* d) const noexcept
|
||||||
|
{
|
||||||
|
d->~document_data();
|
||||||
|
::operator delete (d);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document_data() noexcept = default;
|
||||||
|
document_data(const document_data&) = delete;
|
||||||
|
document_data(document_data&&) = delete;
|
||||||
|
document_data& operator=(const document_data&) = delete;
|
||||||
|
document_data& operator=(document_data&&) = delete;
|
||||||
|
~document_data()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void release() noexcept
|
||||||
|
{
|
||||||
|
if (tape != inline_tape)
|
||||||
|
{
|
||||||
|
::operator delete (tape);
|
||||||
|
}
|
||||||
|
tape = inline_tape;
|
||||||
|
tape_cap = inline_cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// make room for n nodes; keeps the first tape_size nodes
|
||||||
|
void reserve(std::size_t n)
|
||||||
|
{
|
||||||
|
if (n <= tape_cap)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node* fresh = static_cast<node*>(::operator new (n * sizeof(node)));
|
||||||
|
if (tape_size != 0)
|
||||||
|
{
|
||||||
|
std::memcpy(fresh, tape, tape_size * sizeof(node));
|
||||||
|
}
|
||||||
|
release();
|
||||||
|
tape = fresh;
|
||||||
|
tape_cap = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* str(const node& n) const noexcept
|
||||||
|
{
|
||||||
|
return base[n.flags & node_flags::storage] + n.off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the node after n's subtree (containers span `next` nodes, scalars one)
|
||||||
|
static NLOHMANN_VIEW_ALWAYS_INLINE const node* after(const node* n) noexcept
|
||||||
|
{
|
||||||
|
return n + (is_container(*n) ? n->next : 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// first element (array) or first key (object) of a container
|
||||||
|
static NLOHMANN_VIEW_ALWAYS_INLINE const node* first_child(const node* n) noexcept
|
||||||
|
{
|
||||||
|
return n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// end of the elements of a container
|
||||||
|
static NLOHMANN_VIEW_ALWAYS_INLINE const node* child_end(const node* n) noexcept
|
||||||
|
{
|
||||||
|
return n + n->next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace view
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | 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
|
||||||
|
|
||||||
|
// Macros of json_view.hpp and its detail headers. json.hpp undefines its own
|
||||||
|
// macros at its end (macro_unscope.hpp), so the view defines the few it needs
|
||||||
|
// under its own prefix; json_view.hpp undefines them all at its end
|
||||||
|
// (detail/view/macro_unscope.hpp). Configuration that json.hpp undefines is
|
||||||
|
// read from detail::abi_config instead.
|
||||||
|
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
|
#define NLOHMANN_VIEW_HAS_CPP_17 1
|
||||||
|
#else
|
||||||
|
#define NLOHMANN_VIEW_HAS_CPP_17 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define NLOHMANN_VIEW_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define NLOHMANN_VIEW_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#define NLOHMANN_VIEW_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||||
|
#define NLOHMANN_VIEW_NOINLINE __attribute__((noinline))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define NLOHMANN_VIEW_LIKELY(x) (x)
|
||||||
|
#define NLOHMANN_VIEW_UNLIKELY(x) (x)
|
||||||
|
#define NLOHMANN_VIEW_ALWAYS_INLINE __forceinline
|
||||||
|
#define NLOHMANN_VIEW_NOINLINE __declspec(noinline)
|
||||||
|
#else
|
||||||
|
#define NLOHMANN_VIEW_LIKELY(x) (x)
|
||||||
|
#define NLOHMANN_VIEW_UNLIKELY(x) (x)
|
||||||
|
#define NLOHMANN_VIEW_ALWAYS_INLINE inline
|
||||||
|
#define NLOHMANN_VIEW_NOINLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// exceptions as in json.hpp (JSON_NOEXCEPTION, JSON_THROW_USER)
|
||||||
|
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
|
||||||
|
#define NLOHMANN_VIEW_THROW(exception) throw exception
|
||||||
|
#else
|
||||||
|
#include <cstdlib>
|
||||||
|
#define NLOHMANN_VIEW_THROW(exception) std::abort()
|
||||||
|
#endif
|
||||||
|
#if defined(JSON_THROW_USER)
|
||||||
|
#undef NLOHMANN_VIEW_THROW
|
||||||
|
#define NLOHMANN_VIEW_THROW JSON_THROW_USER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the parser stores a node's first word at once where the layout of `node` is
|
||||||
|
// known to be little-endian (MSVC targets are); elsewhere field by field
|
||||||
|
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(_MSC_VER)
|
||||||
|
#define NLOHMANN_VIEW_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
|
#define NLOHMANN_VIEW_LITTLE_ENDIAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// sixteen checks at fixed offsets 0..15
|
||||||
|
#define NLOHMANN_VIEW_REPEAT16(X) X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | 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
|
||||||
|
|
||||||
|
// undefine the macros of detail/view/macro_scope.hpp (at the end of json_view.hpp)
|
||||||
|
|
||||||
|
#undef NLOHMANN_VIEW_HAS_CPP_17
|
||||||
|
#undef NLOHMANN_VIEW_LIKELY
|
||||||
|
#undef NLOHMANN_VIEW_UNLIKELY
|
||||||
|
#undef NLOHMANN_VIEW_ALWAYS_INLINE
|
||||||
|
#undef NLOHMANN_VIEW_NOINLINE
|
||||||
|
#undef NLOHMANN_VIEW_THROW
|
||||||
|
#undef NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||||
|
#undef NLOHMANN_VIEW_REPEAT16
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | 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 <cstddef> // size_t
|
||||||
|
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
|
#include <cstring> // memcpy
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace view
|
||||||
|
{
|
||||||
|
|
||||||
|
// the node kinds are value_t values; the tests of is_container() and of the
|
||||||
|
// number kinds depend on this numbering
|
||||||
|
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
|
||||||
|
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
|
||||||
|
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
|
||||||
|
&& static_cast<std::uint8_t>(value_t::number_unsigned) == 6 && static_cast<std::uint8_t>(value_t::number_float) == 7,
|
||||||
|
"the node format depends on the numbering of value_t");
|
||||||
|
|
||||||
|
/// node flags
|
||||||
|
struct node_flags
|
||||||
|
{
|
||||||
|
static constexpr std::uint8_t escaped = 1; ///< string payload lives in the decode arena, not the source
|
||||||
|
static constexpr std::uint8_t storage = 3; ///< mask: where a string or number token lives (index into document_data::base)
|
||||||
|
static constexpr std::uint8_t is_true = 4; ///< boolean value
|
||||||
|
};
|
||||||
|
|
||||||
|
/// One entry of the flat index, in document order. An object's members are
|
||||||
|
/// stored as key node followed by the value's subtree. Integers keep their
|
||||||
|
/// converted 64-bit value in the len/next bytes (the node after a scalar is
|
||||||
|
/// always the next one, and the token length follows from `extra`).
|
||||||
|
struct node
|
||||||
|
{
|
||||||
|
std::uint8_t kind; ///< value_t
|
||||||
|
std::uint8_t flags; ///< node_flags
|
||||||
|
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; otherwise 0
|
||||||
|
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if node_flags::escaped
|
||||||
|
std::uint32_t len; ///< string: decoded bytes; float: token bytes; array/object: element count
|
||||||
|
std::uint32_t next; ///< array/object: number of nodes of the subtree (its extent in the enclosing sequence)
|
||||||
|
};
|
||||||
|
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
|
||||||
|
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE bool is_container(const node& n) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<unsigned>(n.kind) - 1u <= 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the converted value of an integer node (stored in len/next)
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t integer_bits(const node& n) noexcept
|
||||||
|
{
|
||||||
|
std::uint64_t v = 0;
|
||||||
|
std::memcpy(&v, reinterpret_cast<const unsigned char*>(&n) + 8, 8); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noexcept
|
||||||
|
{
|
||||||
|
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, &v, 8); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// token length of a number node
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
|
||||||
|
{
|
||||||
|
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
|
||||||
|
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// estimated number of nodes for an input of `size` bytes (one node per ~12
|
||||||
|
/// bytes covers typical documents without regrowth)
|
||||||
|
inline std::size_t estimate_nodes(std::size_t size) noexcept
|
||||||
|
{
|
||||||
|
return (size / 12) + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// estimated number of nodes for the input [src, src + size): pretty-printed
|
||||||
|
/// input (whitespace after the first byte) needs about a node per 12 bytes,
|
||||||
|
/// minified input up to one per 4 (yyjson tells the two apart the same way)
|
||||||
|
inline std::size_t estimate_nodes(const char* src, std::size_t size) noexcept
|
||||||
|
{
|
||||||
|
return size >= 2 && (src[1] == ' ' || src[1] == '\n' || src[1] == '\r' || src[1] == '\t') ? estimate_nodes(size) : (size / 4) + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace view
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.12.0
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-FileCopyrightText: 2020 YaoYuan <https://github.com/ibireme/yyjson>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstdint> // uint8_t, uint16_t, uint64_t
|
||||||
|
#include <cstring> // memcpy
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||||
|
|
||||||
|
// Scanning primitives of the view's parser. The unrolled checks at fixed
|
||||||
|
// offsets follow yyjson (https://github.com/ibireme/yyjson, MIT license): the
|
||||||
|
// loads do not depend on each other, so the CPU can run ahead. Words are read
|
||||||
|
// with read_eight_bytes(), so nothing here depends on the byte order.
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace view
|
||||||
|
{
|
||||||
|
|
||||||
|
/// 1 for bytes that may appear verbatim in a string: 0x20..0x7F except '"' and '\\'
|
||||||
|
inline const std::uint8_t* string_plain() noexcept
|
||||||
|
{
|
||||||
|
static const std::uint8_t table[256] =
|
||||||
|
{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00..0x1F
|
||||||
|
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20..0x3F ('"')
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 0x40..0x5F ('\\')
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60..0x7F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80..0x9F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0..0xBF
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0..0xDF
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0..0xFF
|
||||||
|
};
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE bool is_digit(unsigned char c) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<unsigned char>(c - '0') <= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// two bytes as they are in memory (only compared with byte-symmetric patterns)
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE std::uint16_t load16(const unsigned char* p) noexcept
|
||||||
|
{
|
||||||
|
std::uint16_t w = 0;
|
||||||
|
std::memcpy(&w, p, 2);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advance over plain string bytes and well-formed UTF-8. Stops at a quote,
|
||||||
|
/// a backslash, a control character, ill-formed UTF-8, or the end. The first
|
||||||
|
/// 16 bytes are checked one by one, so that the position advances by
|
||||||
|
/// constants in predicted branches (most strings are short); longer runs
|
||||||
|
/// continue eight bytes at a time.
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* scan_string_run(const unsigned char* p, const unsigned char* e) noexcept
|
||||||
|
{
|
||||||
|
const std::uint8_t* plain = string_plain();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (e - p >= 16)
|
||||||
|
{
|
||||||
|
#define NLOHMANN_VIEW_STEP(i) if (NLOHMANN_VIEW_LIKELY(plain[p[i]] != 0)) {} else { p += (i); goto stop; }
|
||||||
|
NLOHMANN_VIEW_REPEAT16(NLOHMANN_VIEW_STEP)
|
||||||
|
#undef NLOHMANN_VIEW_STEP
|
||||||
|
p += 16;
|
||||||
|
while (e - p >= 8)
|
||||||
|
{
|
||||||
|
const std::uint64_t special = swar_string_special(read_eight_bytes(p));
|
||||||
|
if (special != 0)
|
||||||
|
{
|
||||||
|
p += count_trailing_zeros(special) / 8;
|
||||||
|
goto stop;
|
||||||
|
}
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while (p != e && plain[*p] != 0)
|
||||||
|
{
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if (p == e)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
stop:
|
||||||
|
if (*p < 0x80)
|
||||||
|
{
|
||||||
|
return p; // quote, backslash, or control character
|
||||||
|
}
|
||||||
|
// non-ASCII: a run of well-formed sequences (the library's check, so
|
||||||
|
// that exactly what json::parse accepts is accepted)
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const std::size_t n = validate_one_utf8(p, static_cast<std::size_t>(e - p));
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
p += n;
|
||||||
|
}
|
||||||
|
while (p != e && *p >= 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// advance over ASCII digits
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* skip_digits(const unsigned char* p, const unsigned char* e) noexcept
|
||||||
|
{
|
||||||
|
while (e - p >= 16)
|
||||||
|
{
|
||||||
|
#define NLOHMANN_VIEW_STEP(i) if (NLOHMANN_VIEW_LIKELY(is_digit(p[i]))) {} else { return p + (i); }
|
||||||
|
NLOHMANN_VIEW_REPEAT16(NLOHMANN_VIEW_STEP)
|
||||||
|
#undef NLOHMANN_VIEW_STEP
|
||||||
|
p += 16;
|
||||||
|
}
|
||||||
|
while (p != e && is_digit(*p))
|
||||||
|
{
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// powers of ten up to 10^19 as integers
|
||||||
|
inline std::uint64_t int_pow10(unsigned k) noexcept
|
||||||
|
{
|
||||||
|
static const std::uint64_t table[20] =
|
||||||
|
{
|
||||||
|
1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u, 100000000u, 1000000000u,
|
||||||
|
10000000000u, 100000000000u, 1000000000000u, 10000000000000u, 100000000000000u, 1000000000000000u,
|
||||||
|
10000000000000000u, 100000000000000000u, 1000000000000000000u, 10000000000000000000u
|
||||||
|
};
|
||||||
|
return table[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// value of k <= 8 digits at p in one step if [p, p + 8) lies below limit,
|
||||||
|
/// else one digit at a time
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t parse_upto8(const unsigned char* p, unsigned k, const unsigned char* limit) noexcept
|
||||||
|
{
|
||||||
|
if (NLOHMANN_VIEW_LIKELY(limit - p >= 8))
|
||||||
|
{
|
||||||
|
if (k == 8)
|
||||||
|
{
|
||||||
|
return parse_eight_digits(read_eight_bytes(p));
|
||||||
|
}
|
||||||
|
// move the k digits to the top and pad the vacated low bytes with '0'
|
||||||
|
const unsigned shift = 8 * (8 - k);
|
||||||
|
return parse_eight_digits((read_eight_bytes(p) << shift) | (0x3030303030303030u >> (8 * k)));
|
||||||
|
}
|
||||||
|
std::uint64_t v = 0;
|
||||||
|
for (unsigned i = 0; i < k; ++i)
|
||||||
|
{
|
||||||
|
v = (v * 10) + static_cast<std::uint64_t>(p[i] - '0');
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// value of k <= 19 digits at p
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t parse_upto19(const unsigned char* p, unsigned k, const unsigned char* limit) noexcept
|
||||||
|
{
|
||||||
|
std::uint64_t w = 0;
|
||||||
|
while (k >= 8)
|
||||||
|
{
|
||||||
|
w = (w * 100000000u) + parse_upto8(p, 8, limit);
|
||||||
|
p += 8;
|
||||||
|
k -= 8;
|
||||||
|
}
|
||||||
|
if (k != 0)
|
||||||
|
{
|
||||||
|
w = (w * int_pow10(k)) + parse_upto8(p, k, limit);
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace view
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | 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 <algorithm> // min
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstring> // memcmp, strlen
|
||||||
|
#include <string> // basic_string
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||||
|
|
||||||
|
#if NLOHMANN_VIEW_HAS_CPP_17
|
||||||
|
#include <string_view> // string_view
|
||||||
|
#endif
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
#include <ostream> // ostream
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace view
|
||||||
|
{
|
||||||
|
|
||||||
|
#if NLOHMANN_VIEW_HAS_CPP_17
|
||||||
|
using string_ref = std::string_view;
|
||||||
|
#else
|
||||||
|
/// minimal C++11 stand-in for std::string_view
|
||||||
|
class string_ref
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using const_iterator = const char*;
|
||||||
|
|
||||||
|
string_ref() noexcept = default;
|
||||||
|
string_ref(const char* s) : m_data(s), m_size(std::strlen(s)) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||||
|
string_ref(const char* s, std::size_t n) noexcept : m_data(s), m_size(n) {}
|
||||||
|
template<typename Traits, typename Alloc>
|
||||||
|
string_ref(const std::basic_string<char, Traits, Alloc>& s) noexcept : m_data(s.data()), m_size(s.size()) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||||
|
|
||||||
|
const char* data() const noexcept
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
std::size_t size() const noexcept
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
std::size_t length() const noexcept
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
const char* begin() const noexcept
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
const char* end() const noexcept
|
||||||
|
{
|
||||||
|
return m_data + m_size;
|
||||||
|
}
|
||||||
|
char operator[](std::size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Traits, typename Alloc>
|
||||||
|
explicit operator std::basic_string<char, Traits, Alloc>() const
|
||||||
|
{
|
||||||
|
return std::basic_string<char, Traits, Alloc>(m_data, m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(string_ref a, string_ref b) noexcept
|
||||||
|
{
|
||||||
|
return a.m_size == b.m_size && (a.m_size == 0 || std::memcmp(a.m_data, b.m_data, a.m_size) == 0);
|
||||||
|
}
|
||||||
|
friend bool operator!=(string_ref a, string_ref b) noexcept
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
friend bool operator<(string_ref a, string_ref b) noexcept
|
||||||
|
{
|
||||||
|
const int c = std::memcmp(a.m_data, b.m_data, (std::min)(a.m_size, b.m_size));
|
||||||
|
return c != 0 ? c < 0 : a.m_size < b.m_size;
|
||||||
|
}
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
friend std::ostream& operator<<(std::ostream& o, string_ref s)
|
||||||
|
{
|
||||||
|
return o.write(s.m_data, static_cast<std::streamsize>(s.m_size));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_data = "";
|
||||||
|
std::size_t m_size = 0;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace view
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
Reference in New Issue
Block a user