mirror of
https://github.com/nlohmann/json.git
synced 2026-10-31 09:55:42 +00:00
With JSON_DIAGNOSTICS and JSON_DIAGNOSTIC_POSITIONS, the exceptions of views now carry the same context as those of basic_json: "(/path) " and "(bytes a-b) " in front of the message, in basic_json's format (with JSON_DIAGNOSTICS, no context for the root). Before, views threw without any context, and since get<T>() reads the view directly, conversions had lost even the relative path they used to get through materialize(). The throw helpers of detail/view/errors.hpp take an error_site (document and node; empty without the two macros). Only on the error path, the path is found by descending from the root (pruned by subtree extent before the first edit, a full walk through edited sequences after), and the bytes as materialize() sets them (position_source; a container's end by following the chain of last elements and scanning to the closing brackets). from_json() for views and the strict enum macro put the same context in front through exception_prefix(). Iterators keep their container only under the two macros, for key(). Without the macros, the accessors compile to the same code as before. Tests compare every value's exceptions with those of the parsed or materialized basic_json value, including edited documents; the checks that were disabled under the two macros run again. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
128 lines
3.9 KiB
C++
128 lines
3.9 KiB
C++
// __ _____ _____ _____
|
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
|
// | | |__ | | | | | | version 3.12.0
|
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|
//
|
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
// helpers shared by the unit-json_view*.cpp files, which are split to keep every
|
|
// object file small enough for the MinGW linker (it fails to link objects with
|
|
// more than 32767 sections)
|
|
|
|
#include <nlohmann/json_view.hpp>
|
|
|
|
#include <algorithm> // any_of
|
|
#include <cstddef> // size_t
|
|
#include <functional> // function
|
|
#include <random> // mt19937
|
|
#include <string> // string
|
|
|
|
namespace json_view_test
|
|
{
|
|
// a small deterministic generator of documents
|
|
struct generator
|
|
{
|
|
std::mt19937 rng{5295}; // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed)
|
|
|
|
int r(int n)
|
|
{
|
|
return static_cast<int>(rng() % static_cast<unsigned>(n));
|
|
}
|
|
|
|
void str(std::string& o)
|
|
{
|
|
static const char* const pieces[] = {"a", "Z", " ", "\\n", "\\\"", "\\u00e9", "\\ud83d\\ude00", "\xc3\xa9", "\xe3\x81\x82", "long text beyond the first sixteen bytes"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
|
o += '"';
|
|
for (int n = r(5); n > 0; --n)
|
|
{
|
|
o += pieces[r(10)];
|
|
}
|
|
o += '"';
|
|
}
|
|
|
|
void value(std::string& o, int depth)
|
|
{
|
|
static const char* const scalars[] = {"0", "-1", "123456789012", "18446744073709551615", "18446744073709551616", "-9223372036854775809", // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
|
"1.5", "-2.25e-3", "1E2", "0.1", "true", "false", "null"
|
|
};
|
|
const int k = depth > 5 ? 2 + r(4) : r(6);
|
|
if (k < 2)
|
|
{
|
|
const bool object = k == 0;
|
|
o += object ? '{' : '[';
|
|
for (int i = r(5); i > 0; --i)
|
|
{
|
|
if (object)
|
|
{
|
|
str(o);
|
|
o += r(2) == 0 ? ":" : " : ";
|
|
}
|
|
value(o, depth + 1);
|
|
o += i > 1 ? ", " : "";
|
|
}
|
|
o += object ? '}' : ']';
|
|
}
|
|
else if (k < 4)
|
|
{
|
|
str(o);
|
|
}
|
|
else
|
|
{
|
|
o += scalars[r(13)];
|
|
}
|
|
}
|
|
};
|
|
|
|
// whether an object of the view repeats a key
|
|
inline bool has_duplicate_keys(const nlohmann::ordered_json_view& v)
|
|
{
|
|
if (v.is_object() && v.size() != v.materialize().size())
|
|
{
|
|
return true;
|
|
}
|
|
return std::any_of(v.begin(), v.end(), [](const nlohmann::ordered_json_view e)
|
|
{
|
|
return e.is_structured() && has_duplicate_keys(e);
|
|
});
|
|
}
|
|
|
|
// the message of an exception about the value at path (a JSON pointer, "" for
|
|
// the root) whose source bytes are [start, end): the context basic_json adds
|
|
// with JSON_DIAGNOSTICS and JSON_DIAGNOSTIC_POSITIONS, if enabled, then what
|
|
inline std::string message(const std::string& id, const std::string& path, std::size_t start, std::size_t end, const std::string& what)
|
|
{
|
|
std::string context;
|
|
#if JSON_DIAGNOSTIC_POSITIONS
|
|
context = "(bytes " + std::to_string(start) + "-" + std::to_string(end) + ") ";
|
|
#else
|
|
static_cast<void>(start);
|
|
static_cast<void>(end);
|
|
#endif
|
|
#if JSON_DIAGNOSTICS
|
|
context = path.empty() ? "" : "(" + path + ") " + context;
|
|
#else
|
|
static_cast<void>(path);
|
|
#endif
|
|
return "[json.exception." + id + "] " + context + what;
|
|
}
|
|
|
|
#if !defined(JSON_NOEXCEPTION)
|
|
// the exception a call throws, or "" if it throws none
|
|
inline std::string exception_of_call(const std::function<void()>& f)
|
|
{
|
|
try
|
|
{
|
|
f();
|
|
}
|
|
catch (const nlohmann::json::exception& e)
|
|
{
|
|
return e.what();
|
|
}
|
|
return "";
|
|
}
|
|
#endif
|
|
} // namespace json_view_test
|