Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12fc67313e | ||
|
|
43a2d24f6f |
No files matched your search
@@ -10,6 +10,13 @@ at its root, a [Natvis](https://learn.microsoft.com/en-us/visualstudio/debugger/
|
|||||||
file that gives `json`/`ordered_json` values a friendly, key/value debugger view instead of showing raw internal
|
file that gives `json`/`ordered_json` values a friendly, key/value debugger view instead of showing raw internal
|
||||||
fields, when debugging with the MSVC debug engine (`cppvsdbg`) in Visual Studio or VS Code.
|
fields, when debugging with the MSVC debug engine (`cppvsdbg`) in Visual Studio or VS Code.
|
||||||
|
|
||||||
|
The file also has visualizers for `json_document` and `json_view` (and their `ordered_json`/editable variants). They
|
||||||
|
show the value of the document or view, and its elements as an expandable list. Because a document is only a flat index
|
||||||
|
into the source text, the strings of the direct elements are shown, but the elements of nested arrays and objects are
|
||||||
|
shown as index nodes (their kind, size, and numbers; strings only by length). Arrays and objects that have been edited
|
||||||
|
in a `json_editable_document` are not expanded. The visualizers read the internal layout of the MSVC STL (`std::array`,
|
||||||
|
`std::unique_ptr`).
|
||||||
|
|
||||||
The checked-in visualizers cover namespace variants with zero, one, or two ABI tags. Configurations with three or more
|
The checked-in visualizers cover namespace variants with zero, one, or two ABI tags. Configurations with three or more
|
||||||
ABI tags are not covered and may show raw internal fields instead. To generate a Natvis file for such a configuration:
|
ABI tags are not covered and may show raw internal fields instead. To generate a Natvis file for such a configuration:
|
||||||
|
|
||||||
@@ -29,7 +36,7 @@ ABI tags are not covered and may show raw internal fields instead. To generate a
|
|||||||
|
|
||||||
4. Use the generated file instead of `nlohmann_json.natvis`.
|
4. Use the generated file instead of `nlohmann_json.natvis`.
|
||||||
|
|
||||||
`--abi-tags` can be repeated for several configurations, and `--all` generates every combination (about 60 MB for 12
|
`--abi-tags` can be repeated for several configurations, and `--all` generates every combination (about 60 MB for 11
|
||||||
ABI tags, doubling with each further tag). See
|
ABI tags, doubling with each further tag). See
|
||||||
[`tools/generate_natvis`](https://github.com/nlohmann/json/tree/develop/tools/generate_natvis) for all options.
|
[`tools/generate_natvis`](https://github.com/nlohmann/json/tree/develop/tools/generate_natvis) for all options.
|
||||||
|
|
||||||
|
|||||||
@@ -1977,23 +1977,6 @@ class serializer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 17 to 20 digits: the first one to four, then twice eight
|
|
||||||
if (magnitude_fits_64_bits(abs_value, std::integral_constant<bool, magnitude_has_at_most_64_bits>()))
|
|
||||||
{
|
|
||||||
const auto value = static_cast<std::uint64_t>(abs_value);
|
|
||||||
const std::uint64_t top = value / 10000000000000000u; // 1 to 1844
|
|
||||||
const std::uint64_t low16 = value - (top * 10000000000000000u);
|
|
||||||
const std::uint64_t middle = low16 / 100000000u;
|
|
||||||
const std::uint64_t first = dtoa_impl::eight_digit_bytes(top);
|
|
||||||
const auto leading = static_cast<unsigned>(count_leading_zeros(first) / 8); // (first is not 0)
|
|
||||||
char* const p = buffer_ptr + n_chars;
|
|
||||||
dtoa_impl::store_msb_first(p, (first << (8 * leading)) + 0x3030303030303030u);
|
|
||||||
dtoa_impl::store_msb_first(p + 8 - leading, dtoa_impl::eight_digit_bytes(middle) + 0x3030303030303030u);
|
|
||||||
dtoa_impl::store_msb_first(p + 16 - leading, dtoa_impl::eight_digit_bytes(low16 - (middle * 100000000u)) + 0x3030303030303030u);
|
|
||||||
write_buffer_pos += n_chars + 24 - leading;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
n_chars += count_digits(abs_value);
|
n_chars += count_digits(abs_value);
|
||||||
|
|
||||||
// spare 1 byte for '\0'
|
// spare 1 byte for '\0'
|
||||||
@@ -2139,23 +2122,6 @@ class serializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// whether every number_magnitude_t fits 64 bits
|
|
||||||
static constexpr bool magnitude_has_at_most_64_bits = std::numeric_limits<number_magnitude_t>::is_specialized
|
|
||||||
&& std::numeric_limits<number_magnitude_t>::digits <= 64;
|
|
||||||
|
|
||||||
/// whether @a x fits 64 bits: always if number_magnitude_t has at most
|
|
||||||
/// 64 bits (selected by type, as the comparison would be reported as
|
|
||||||
/// always true), else compared
|
|
||||||
static bool magnitude_fits_64_bits(const number_magnitude_t& /*unused*/, std::true_type /*unused*/) noexcept
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool magnitude_fits_64_bits(const number_magnitude_t& x, std::false_type /*unused*/) noexcept
|
|
||||||
{
|
|
||||||
return x <= 18446744073709551615u;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper function for dump_integer
|
* Helper function for dump_integer
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -343,21 +343,6 @@ class builder
|
|||||||
}
|
}
|
||||||
arena_ensure(w, w_end, 4);
|
arena_ensure(w, w_end, 4);
|
||||||
w = put_utf8(w, cp);
|
w = put_utf8(w, cp);
|
||||||
// A chain of unicode escapes ("\u3042\u3044\u3046", as Python's json.dumps writes non-ASCII text) is
|
|
||||||
// decoded here, without going round the loop above for each of them. Anything else (a surrogate, a
|
|
||||||
// bad digit, fewer than six bytes) leaves p at the backslash: the loop above handles it, and reports
|
|
||||||
// the same error at the same position as it would without this loop.
|
|
||||||
while (end - p >= 6 && p[0] == '\\' && p[1] == 'u')
|
|
||||||
{
|
|
||||||
const int next = hex_codepoint(p + 2);
|
|
||||||
if (next < 0 || (next & 0xF800) == 0xD800)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p += 6;
|
|
||||||
arena_ensure(w, w_end, 4);
|
|
||||||
w = put_utf8(w, next);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (NLOHMANN_VIEW_LIKELY(d < 128 && simple_escape[d] != 0))
|
else if (NLOHMANN_VIEW_LIKELY(d < 128 && simple_escape[d] != 0))
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+11880
File diff suppressed because it is too large.
Load diff
Generated
-34
@@ -36224,23 +36224,6 @@ class serializer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 17 to 20 digits: the first one to four, then twice eight
|
|
||||||
if (magnitude_fits_64_bits(abs_value, std::integral_constant<bool, magnitude_has_at_most_64_bits>()))
|
|
||||||
{
|
|
||||||
const auto value = static_cast<std::uint64_t>(abs_value);
|
|
||||||
const std::uint64_t top = value / 10000000000000000u; // 1 to 1844
|
|
||||||
const std::uint64_t low16 = value - (top * 10000000000000000u);
|
|
||||||
const std::uint64_t middle = low16 / 100000000u;
|
|
||||||
const std::uint64_t first = dtoa_impl::eight_digit_bytes(top);
|
|
||||||
const auto leading = static_cast<unsigned>(count_leading_zeros(first) / 8); // (first is not 0)
|
|
||||||
char* const p = buffer_ptr + n_chars;
|
|
||||||
dtoa_impl::store_msb_first(p, (first << (8 * leading)) + 0x3030303030303030u);
|
|
||||||
dtoa_impl::store_msb_first(p + 8 - leading, dtoa_impl::eight_digit_bytes(middle) + 0x3030303030303030u);
|
|
||||||
dtoa_impl::store_msb_first(p + 16 - leading, dtoa_impl::eight_digit_bytes(low16 - (middle * 100000000u)) + 0x3030303030303030u);
|
|
||||||
write_buffer_pos += n_chars + 24 - leading;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
n_chars += count_digits(abs_value);
|
n_chars += count_digits(abs_value);
|
||||||
|
|
||||||
// spare 1 byte for '\0'
|
// spare 1 byte for '\0'
|
||||||
@@ -36386,23 +36369,6 @@ class serializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// whether every number_magnitude_t fits 64 bits
|
|
||||||
static constexpr bool magnitude_has_at_most_64_bits = std::numeric_limits<number_magnitude_t>::is_specialized
|
|
||||||
&& std::numeric_limits<number_magnitude_t>::digits <= 64;
|
|
||||||
|
|
||||||
/// whether @a x fits 64 bits: always if number_magnitude_t has at most
|
|
||||||
/// 64 bits (selected by type, as the comparison would be reported as
|
|
||||||
/// always true), else compared
|
|
||||||
static bool magnitude_fits_64_bits(const number_magnitude_t& /*unused*/, std::true_type /*unused*/) noexcept
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool magnitude_fits_64_bits(const number_magnitude_t& x, std::false_type /*unused*/) noexcept
|
|
||||||
{
|
|
||||||
return x <= 18446744073709551615u;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper function for dump_integer
|
* Helper function for dump_integer
|
||||||
*
|
*
|
||||||
|
|||||||
Generated
-15
@@ -1585,21 +1585,6 @@ class builder
|
|||||||
}
|
}
|
||||||
arena_ensure(w, w_end, 4);
|
arena_ensure(w, w_end, 4);
|
||||||
w = put_utf8(w, cp);
|
w = put_utf8(w, cp);
|
||||||
// A chain of unicode escapes ("\u3042\u3044\u3046", as Python's json.dumps writes non-ASCII text) is
|
|
||||||
// decoded here, without going round the loop above for each of them. Anything else (a surrogate, a
|
|
||||||
// bad digit, fewer than six bytes) leaves p at the backslash: the loop above handles it, and reports
|
|
||||||
// the same error at the same position as it would without this loop.
|
|
||||||
while (end - p >= 6 && p[0] == '\\' && p[1] == 'u')
|
|
||||||
{
|
|
||||||
const int next = hex_codepoint(p + 2);
|
|
||||||
if (next < 0 || (next & 0xF800) == 0xD800)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p += 6;
|
|
||||||
arena_ensure(w, w_end, 4);
|
|
||||||
w = put_utf8(w, next);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (NLOHMANN_VIEW_LIKELY(d < 128 && simple_escape[d] != 0))
|
else if (NLOHMANN_VIEW_LIKELY(d < 128 && simple_escape[d] != 0))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -575,59 +575,6 @@ TEST_CASE("json_view builder: escapes between runs of text")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("json_view builder: chains of unicode escapes")
|
|
||||||
{
|
|
||||||
// Consecutive \uXXXX escapes are decoded in a loop of their own. Chains of
|
|
||||||
// every length from 1 to 40 of escapes that give one, two, and three
|
|
||||||
// bytes of UTF-8, in upper and lower case, followed by what ends a chain:
|
|
||||||
// the end of the string, text, another escape, UTF-8, and everything that
|
|
||||||
// is not a valid escape (a bad digit at every position of the last
|
|
||||||
// escape, a lone surrogate, a surrogate pair, a cut in every place).
|
|
||||||
const std::array<const char*, 8> chain = {{"\\u0041", "\\u00e4", "\\u00E4", "\\u20ac", "\\u3042", "\\uFFFF", "\\u0000", "\\u07ff"}};
|
|
||||||
const std::array<const char*, 12> ends = {{"", "abc", "\\n", "\\u00e9", "\\ud83d\\ude00", "\\ud83d", "\\ude00", "\\ud83d\\u0041", "\\u12G4", "\\u12", "\xc3\xa4", "\\"}};
|
|
||||||
std::mt19937 rng(2027); // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed): reproducible
|
|
||||||
for (std::size_t length = 1; length <= 40; ++length)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 20; ++i)
|
|
||||||
{
|
|
||||||
std::string content = std::string(rng() % 20, 'a');
|
|
||||||
for (std::size_t k = 0; k < length; ++k)
|
|
||||||
{
|
|
||||||
content += chain[rng() % chain.size()];
|
|
||||||
}
|
|
||||||
const std::string whole = content;
|
|
||||||
for (const char* end : ends)
|
|
||||||
{
|
|
||||||
check_string(whole + end);
|
|
||||||
check_string(whole + end + std::string(rng() % 19, 'z'));
|
|
||||||
}
|
|
||||||
// a bad digit at every position of every escape near the end of the chain
|
|
||||||
for (std::size_t back = 1; back <= 6 && back <= length; ++back)
|
|
||||||
{
|
|
||||||
for (std::size_t digit = 2; digit < 6; ++digit)
|
|
||||||
{
|
|
||||||
std::string broken = whole;
|
|
||||||
broken[broken.size() - (6 * back) + digit] = "gG\"\x01 z"[rng() % 6];
|
|
||||||
check_string(broken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// the text cut in every place of the last three escapes
|
|
||||||
for (std::size_t cut = 0; cut <= 18 && cut <= whole.size(); ++cut)
|
|
||||||
{
|
|
||||||
check_string(whole.substr(0, whole.size() - cut));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// a chain longer than the first growth of the arena, in a key and in a value
|
|
||||||
std::string long_chain;
|
|
||||||
for (int i = 0; i < 3000; ++i)
|
|
||||||
{
|
|
||||||
long_chain += chain[static_cast<std::size_t>(i) % chain.size()];
|
|
||||||
}
|
|
||||||
check_string(long_chain);
|
|
||||||
check_string(long_chain + "\\ud83d\\ude00" + long_chain);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("json_view node integer bits")
|
TEST_CASE("json_view node integer bits")
|
||||||
{
|
{
|
||||||
using nlohmann::detail::view::integer_bits;
|
using nlohmann::detail::view::integer_bits;
|
||||||
|
|||||||
@@ -443,30 +443,6 @@ TEST_CASE("json_view from_json")
|
|||||||
CHECK(d.root().materialize().get<point>().x == 3);
|
CHECK(d.root().materialize().get<point>().x == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("escaped keys: members are found by their decoded names")
|
|
||||||
{
|
|
||||||
// keys are decoded before they are compared, as by parse(); a lookup
|
|
||||||
// that compares the raw bytes of the source would miss these members
|
|
||||||
const json_document d = json_document::parse(R"([{"\u0078": 1, "y": 2}, {"V\u0061lue": 3, "Te\u0078t": "t"}, {"\u0062": "escaped"}, {"x": 1, "\u0078": 3, "y": 2}])");
|
|
||||||
const json j = d.root().materialize();
|
|
||||||
CHECK(d.root()[0].get<point>().x == 1);
|
|
||||||
CHECK(d.root()[0].get<point>().y == 2);
|
|
||||||
CHECK((d.root()[0].get<point>() == j[0].get<point>()));
|
|
||||||
CHECK(d.root()[1].get<with_names>().value == 3);
|
|
||||||
CHECK(d.root()[1].get<with_names>().text == "t");
|
|
||||||
CHECK(d.root()[2].get<with_defaults>().b == "escaped");
|
|
||||||
CHECK(d.root()[2].get<with_defaults>().a == 1);
|
|
||||||
// a duplicate key written once plain and once escaped: still the first member
|
|
||||||
CHECK(d.root()[3].get<point>().x == 1);
|
|
||||||
CHECK(j[3].get<point>().x == 3);
|
|
||||||
#if !defined(JSON_NOEXCEPTION) && !JSON_DIAGNOSTICS && !JSON_DIAGNOSTIC_POSITIONS
|
|
||||||
// an escaped backslash is part of the decoded key: "x\\" is not "x"
|
|
||||||
const json_document e = json_document::parse(R"({"x\\": 1, "y": 2})");
|
|
||||||
CHECK(exception_of_call([&] { static_cast<void>(e.root().get<point>()); }) == exception_of_call([&] { static_cast<void>(e.root().materialize().get<point>()); }));
|
|
||||||
CHECK(exception_of_call([&] { static_cast<void>(e.root().get<point>()); }) == "[json.exception.out_of_range.403] key 'x' not found");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("editable documents and ordered_json")
|
SECTION("editable documents and ordered_json")
|
||||||
{
|
{
|
||||||
json_editable_document e = json_editable_document::parse(R"({"x": 1, "y": 2})");
|
json_editable_document e = json_editable_document::parse(R"({"x": 1, "y": 2})");
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ using nlohmann::json;
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <limits>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -249,51 +248,6 @@ TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("integers of every digit count are written like std::to_string")
|
|
||||||
{
|
|
||||||
// dump_integer() writes up to 16 digits in two groups of eight and 17 to
|
|
||||||
// 20 digits as one to four digits and two groups of eight
|
|
||||||
std::vector<std::uint64_t> values;
|
|
||||||
std::uint64_t power = 1;
|
|
||||||
for (int digits = 1; digits <= 20; ++digits)
|
|
||||||
{
|
|
||||||
values.push_back(power); // 1 followed by zeros
|
|
||||||
values.push_back(power + 1);
|
|
||||||
values.push_back((power * 2) - 1);
|
|
||||||
if (digits < 20)
|
|
||||||
{
|
|
||||||
values.push_back((power * 10) - 1); // all 9s
|
|
||||||
values.push_back((power * 10) - power); // 9 followed by zeros
|
|
||||||
power *= 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
values.push_back((std::numeric_limits<std::uint64_t>::max)());
|
|
||||||
values.push_back(static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()));
|
|
||||||
values.push_back(static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()) + 1);
|
|
||||||
std::uint64_t state = 0x9E3779B97F4A7C15u;
|
|
||||||
for (int i = 0; i < 20000; ++i)
|
|
||||||
{
|
|
||||||
state = (state * 6364136223846793005u) + 1442695040888963407u;
|
|
||||||
values.push_back(state >> (state % 61)); // every bit length
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto v : values)
|
|
||||||
{
|
|
||||||
CAPTURE(v)
|
|
||||||
CHECK(json(v).dump() == std::to_string(v));
|
|
||||||
if (v <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
|
|
||||||
{
|
|
||||||
const auto s = static_cast<std::int64_t>(v);
|
|
||||||
CHECK(json(s).dump() == std::to_string(s));
|
|
||||||
CHECK(json(-s).dump() == std::to_string(-s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CHECK(json((std::numeric_limits<std::int64_t>::min)()).dump() == "-9223372036854775808");
|
|
||||||
|
|
||||||
// in a container, so the digits are followed by other output
|
|
||||||
CHECK(json::array({std::uint64_t{18446744073709551615u}, std::int64_t{-1234567890123456789}, 1}).dump() == "[18446744073709551615,-1234567890123456789,1]");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("dump with binary values")
|
TEST_CASE("dump with binary values")
|
||||||
{
|
{
|
||||||
auto binary = json::binary({1, 2, 3, 4});
|
auto binary = json::binary({1, 2, 3, 4});
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ The checked-in `nlohmann_json.natvis` covers the default namespace (no ABI tags)
|
|||||||
of ABI tags, with both versioned and unversioned namespace variants. Configurations that enable three or more ABI tags
|
of ABI tags, with both versioned and unversioned namespace variants. Configurations that enable three or more ABI tags
|
||||||
are not covered by this reduced file; use `--abi-tags` or `--all` (see below) to generate a file for them.
|
are not covered by this reduced file; use `--abi-tags` or `--all` (see below) to generate a file for them.
|
||||||
|
|
||||||
|
The visualizers of `basic_json_document` and `basic_json_view` live in the same inline namespaces as `basic_json`, so the
|
||||||
|
ABI tags apply to them in the same way, and the `view_mode` template argument is covered by a wildcard: it does not
|
||||||
|
multiply the namespaces. Each namespace gets three more types (`basic_json_view<*,*>`, `basic_json_document<*,*>`, and
|
||||||
|
`detail::view::node`), which roughly doubles the size of the file.
|
||||||
|
|
||||||
The ABI tag list and the library version are parsed from
|
The ABI tag list and the library version are parsed from
|
||||||
`include/nlohmann/detail/abi_macros.hpp`, so this script must be re-run (via
|
`include/nlohmann/detail/abi_macros.hpp`, so this script must be re-run (via
|
||||||
`make natvis`) whenever an `NLOHMANN_JSON_ABI_TAG_*` macro is added to that
|
`make natvis`) whenever an `NLOHMANN_JSON_ABI_TAG_*` macro is added to that
|
||||||
@@ -35,7 +40,7 @@ version other than the one in `abi_macros.hpp`.
|
|||||||
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `--list-tags` | Print every ABI tag (in namespace order) with the macro that enables it and the `NLOHMANN_JSON_ABI_TAG_*` identifier, then exit. |
|
| `--list-tags` | Print every ABI tag (in namespace order) with the macro that enables it and the `NLOHMANN_JSON_ABI_TAG_*` identifier, then exit. |
|
||||||
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_ns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
|
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_ns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
|
||||||
| `--all` | Generate the namespaces for every combination of ABI tags. The file size doubles with each tag (about 60 MB for 12 tags). Cannot be combined with `--abi-tags`. |
|
| `--all` | Generate the namespaces for every combination of ABI tags. The file size doubles with each tag (about 60 MB for 11 tags). Cannot be combined with `--abi-tags`. |
|
||||||
| `--output FILE` | Write the Natvis file to `FILE` instead of `nlohmann_json.natvis` in the repository root. |
|
| `--output FILE` | Write the Natvis file to `FILE` instead of `nlohmann_json.natvis` in the repository root. |
|
||||||
|
|
||||||
Each configuration gets both the versioned (`json_abi_diag_dp_ns_v3_12_0`) and the unversioned (`json_abi_diag_dp_ns`,
|
Each configuration gets both the versioned (`json_abi_diag_dp_ns_v3_12_0`) and the unversioned (`json_abi_diag_dp_ns`,
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ if __name__ == '__main__':
|
|||||||
'optional) of one configuration to add to the default namespaces; can be repeated')
|
'optional) of one configuration to add to the default namespaces; can be repeated')
|
||||||
selection.add_argument('--all', action='store_true',
|
selection.add_argument('--all', action='store_true',
|
||||||
help='Generate the namespaces for every combination of ABI tags; the file size doubles '
|
help='Generate the namespaces for every combination of ABI tags; the file size doubles '
|
||||||
'with each ABI tag (about 60 MB for 12 tags)')
|
'with each ABI tag (about 60 MB for 11 tags)')
|
||||||
parser.add_argument('--list-tags', action='store_true',
|
parser.add_argument('--list-tags', action='store_true',
|
||||||
help='List the ABI tags with the macros that enable them, and exit')
|
help='List the ABI tags with the macros that enable them, and exit')
|
||||||
parser.add_argument('--output', metavar='FILE',
|
parser.add_argument('--output', metavar='FILE',
|
||||||
|
|||||||
@@ -5,6 +5,39 @@
|
|||||||
<!-- * * * * * * * * AUTO-GENERATED FILE * * * * * * * * -->
|
<!-- * * * * * * * * AUTO-GENERATED FILE * * * * * * * * -->
|
||||||
|
|
||||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
{# The children of the container node `node` (a pointer expression) of the document `doc` (a document_data pointer
|
||||||
|
expression). A node is only an index into the source text: strings are read from `doc`, so the strings of the
|
||||||
|
direct children are readable here, but the children of a nested container are shown as nodes (see the node
|
||||||
|
visualizer below). Containers with edits (flag 8, "moved") are not expanded. The node kinds are the numbers of
|
||||||
|
node_kind: 1 object, 2 array, 3 string; the float token is shown only by the node visualizer. #}
|
||||||
|
{% macro children(node, doc=none) %}
|
||||||
|
<CustomListItems MaxItemsPerView="1000">
|
||||||
|
<Variable Name="nd" InitialValue="{{ node }}" />
|
||||||
|
<Variable Name="obj" InitialValue="nd != 0 && (int)nd->kind == 1" />
|
||||||
|
<Variable Name="n" InitialValue="(nd != 0 && ((int)nd->kind == 1 || (int)nd->kind == 2) && (nd->flags & 8) == 0) ? (int)nd->len : 0" />
|
||||||
|
<Variable Name="p" InitialValue="nd + 1" />
|
||||||
|
<Variable Name="i" InitialValue="0" />
|
||||||
|
<Size>obj ? 2 * n : n</Size>
|
||||||
|
<Loop Condition="i < n">
|
||||||
|
{% if doc %}
|
||||||
|
<Item Name="key" Condition="obj">{{ doc }}->base._Elems[p->flags & 3] + p->off,[p->len]s8</Item>
|
||||||
|
{% else %}
|
||||||
|
<Item Name="key" Condition="obj">*p</Item>
|
||||||
|
{% endif %}
|
||||||
|
<Exec Condition="obj">p = p + 1</Exec>
|
||||||
|
{% if doc %}
|
||||||
|
<Item Name="value" Condition="obj && (int)p->kind == 3">{{ doc }}->base._Elems[p->flags & 3] + p->off,[p->len]s8</Item>
|
||||||
|
{% endif %}
|
||||||
|
<Item Name="value" Condition="obj{% if doc %} && (int)p->kind != 3{% endif %}">*p</Item>
|
||||||
|
{% if doc %}
|
||||||
|
<Item Condition="!obj && (int)p->kind == 3">{{ doc }}->base._Elems[p->flags & 3] + p->off,[p->len]s8</Item>
|
||||||
|
{% endif %}
|
||||||
|
<Item Condition="!obj{% if doc %} && (int)p->kind != 3{% endif %}">*p</Item>
|
||||||
|
<Exec>p = p + (((int)p->kind == 1 || (int)p->kind == 2) ? p->next : 1)</Exec>
|
||||||
|
<Exec>i = i + 1</Exec>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
{%- endmacro %}
|
||||||
{% for ns in namespaces %}
|
{% for ns in namespaces %}
|
||||||
<!-- Namespace {{ ns }} -->
|
<!-- Namespace {{ ns }} -->
|
||||||
<Type Name="{{ ns }}::basic_json<*>">
|
<Type Name="{{ ns }}::basic_json<*>">
|
||||||
@@ -62,5 +95,44 @@
|
|||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<!-- json_view / json_document (include/nlohmann/json_view.hpp). They live in the same inline namespaces as
|
||||||
|
basic_json, so the ABI tags need no extra entries; the view_mode is a template argument that the wildcard
|
||||||
|
covers. A view is a pointer to the document's data and a pointer to a node of its flat index; the
|
||||||
|
strings of the source are found through document_data::base (std::array of the MSVC STL: _Elems). -->
|
||||||
|
<Type Name="{{ ns }}::detail::view::node">
|
||||||
|
<DisplayString Condition="(int)kind == 0">null</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 1">object, size={len}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 2">array, size={len}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 3">string, length={len}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 4">boolean: {(flags & 4) != 0}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 5">int64: {(__int64)((unsigned __int64)len | ((unsigned __int64)next << 32))}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 6">uint64: {(unsigned __int64)len | ((unsigned __int64)next << 32)}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)kind == 7">float, length={len}</DisplayString>
|
||||||
|
<DisplayString>link</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
{{ children('this') }}
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="{{ ns }}::basic_json_view<*,*>">
|
||||||
|
<DisplayString Condition="m_node == 0">discarded</DisplayString>
|
||||||
|
<DisplayString Condition="(int)m_node->kind == 3">{m_doc->base._Elems[m_node->flags & 3] + m_node->off,[m_node->len]s8}</DisplayString>
|
||||||
|
<DisplayString Condition="(int)m_node->kind == 7">{m_doc->base._Elems[m_node->flags & 3] + m_node->off,[m_node->len]s8b}</DisplayString>
|
||||||
|
<DisplayString>{*m_node}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
{{ children('m_node', 'm_doc') }}
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="{{ ns }}::basic_json_document<*,*>">
|
||||||
|
<DisplayString Condition="m_data._Mypair._Myval2 == 0 || m_data._Mypair._Myval2->discarded">discarded</DisplayString>
|
||||||
|
<DisplayString>{*m_data._Mypair._Myval2->nodes}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[source]" Condition="m_data._Mypair._Myval2 != 0">m_data._Mypair._Myval2->src,[m_data._Mypair._Myval2->size]s8b</Item>
|
||||||
|
<Item Name="[nodes]" Condition="m_data._Mypair._Myval2 != 0">m_data._Mypair._Myval2->node_count</Item>
|
||||||
|
{{ children('m_data._Mypair._Myval2->nodes', 'm_data._Mypair._Myval2') }}
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</AutoVisualizer>
|
</AutoVisualizer>
|
||||||
Reference in new issue
Block a user