mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 19:50:34 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
954bdad63b | ||
|
|
6a073dbae4 | ||
|
|
fdcc569eee | ||
|
|
2dc43e8bf8 | ||
|
|
e0eb3e7490 | ||
|
|
3ae4d7c45e |
@@ -272,6 +272,15 @@ basic_json(basic_json&& other) noexcept;
|
|||||||
When used without parentheses around an empty initializer list, `basic_json()` is called instead of this
|
When used without parentheses around an empty initializer list, `basic_json()` is called instead of this
|
||||||
function, yielding the JSON `#!json null` value.
|
function, yielding the JSON `#!json null` value.
|
||||||
|
|
||||||
|
- Overload 4:
|
||||||
|
|
||||||
|
!!! info "Implicit conversion"
|
||||||
|
|
||||||
|
The conversion is implicit unless [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md)
|
||||||
|
is defined to `0` and `BasicJsonType::string_t` differs from `string_t`. In that case, the constructor is
|
||||||
|
`explicit`, so a JSON value with a different string type is no longer silently converted, for example when it is
|
||||||
|
passed to a function taking `#!cpp const json&`. Write `#!cpp json(other)` or `#!cpp other.get<json>()` instead.
|
||||||
|
|
||||||
- Overload 7:
|
- Overload 7:
|
||||||
|
|
||||||
!!! info "Preconditions"
|
!!! info "Preconditions"
|
||||||
@@ -420,7 +429,8 @@ basic_json(basic_json&& other) noexcept;
|
|||||||
1. Since version 1.0.0.
|
1. Since version 1.0.0.
|
||||||
2. Since version 1.0.0.
|
2. Since version 1.0.0.
|
||||||
3. Since version 2.1.0.
|
3. Since version 2.1.0.
|
||||||
4. Since version 3.2.0.
|
4. Since version 3.2.0. Explicit for different string types if `JSON_USE_IMPLICIT_CONVERSIONS` is `0` since
|
||||||
|
version 3.13.0.
|
||||||
5. Since version 1.0.0.
|
5. Since version 1.0.0.
|
||||||
6. Since version 1.0.0.
|
6. Since version 1.0.0.
|
||||||
7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range
|
7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ By default, `#!cpp JSON_NO_AUTOMATIC_UDLS` is not defined, and `<nlohmann/json.h
|
|||||||
- [`operator""_json`](../operator_literal_json.md)
|
- [`operator""_json`](../operator_literal_json.md)
|
||||||
- [`operator""_json_pointer`](../operator_literal_json_pointer.md)
|
- [`operator""_json_pointer`](../operator_literal_json_pointer.md)
|
||||||
- [`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace
|
- [`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace
|
||||||
- [Compile times](../../integration/compile_times.md) - options to reduce compile times
|
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
When defined to `0`, implicit conversions are switched off. By default, implicit conversions are switched on. The
|
When defined to `0`, implicit conversions are switched off. By default, implicit conversions are switched on. The
|
||||||
value directly affects [`operator ValueType`](../basic_json/operator_ValueType.md).
|
value directly affects [`operator ValueType`](../basic_json/operator_ValueType.md) and the
|
||||||
|
[converting constructor](../basic_json/basic_json.md) from a `basic_json` specialization with a different string
|
||||||
|
type (overload 4).
|
||||||
|
|
||||||
## Default definition
|
## Default definition
|
||||||
|
|
||||||
@@ -57,6 +59,25 @@ By default, implicit conversions are enabled.
|
|||||||
auto s = j.get<std::string>();
|
auto s = j.get<std::string>();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? example "Conversion between `basic_json` specializations"
|
||||||
|
|
||||||
|
A `basic_json` specialization with a different string type is also no longer converted implicitly when
|
||||||
|
`JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using wjson = nlohmann::basic_json<std::map, std::vector, std::wstring>;
|
||||||
|
|
||||||
|
void load(const nlohmann::json& j);
|
||||||
|
|
||||||
|
wjson wj = /* ... */;
|
||||||
|
load(wj); // error: no implicit conversion
|
||||||
|
load(nlohmann::json(wj)); // OK: explicit conversion
|
||||||
|
load(wj.get<nlohmann::json>()); // OK: explicit conversion
|
||||||
|
```
|
||||||
|
|
||||||
|
Specializations that share the same string type, such as `json` and `ordered_json`, remain implicitly
|
||||||
|
convertible.
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [**operator ValueType**](../basic_json/operator_ValueType.md) - get a value (implicit)
|
- [**operator ValueType**](../basic_json/operator_ValueType.md) - get a value (implicit)
|
||||||
@@ -66,3 +87,4 @@ By default, implicit conversions are enabled.
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.9.0.
|
- Added in version 3.9.0.
|
||||||
|
- Also affects the conversion between `basic_json` specializations with different string types since version 3.13.0.
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ Deserializes an input stream to a JSON value.
|
|||||||
|
|
||||||
the stream `i`
|
the stream `i`
|
||||||
|
|
||||||
|
## Exception safety
|
||||||
|
|
||||||
|
Strong guarantee: if an exception is thrown, there are no changes in `j`.
|
||||||
|
|
||||||
## Exceptions
|
## Exceptions
|
||||||
|
|
||||||
- Throws [`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token, or if
|
- Throws [`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token, or if
|
||||||
@@ -125,3 +129,5 @@ being read.
|
|||||||
the stream; planned to become the default in version 4.0.0.
|
the stream; planned to become the default in version 4.0.0.
|
||||||
- Fixed a null pointer dereference for an `std::istream` without a stream buffer (now throws `parse_error.101`), and a
|
- Fixed a null pointer dereference for an `std::istream` without a stream buffer (now throws `parse_error.101`), and a
|
||||||
crash (`std::terminate`) when `i` has `eofbit` in its exception mask, in version 3.13.0.
|
crash (`std::terminate`) when `i` has `eofbit` in its exception mask, in version 3.13.0.
|
||||||
|
- Changed to the strong exception safety guarantee in version 3.13.0: `j` is no longer left with a partially parsed
|
||||||
|
value if parsing throws.
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
|||||||
| Functionality | Additional requirement |
|
| Functionality | Additional requirement |
|
||||||
|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| [`diff`](../../api/basic_json/diff.md), [`items`](../../api/basic_json/items.md), [`std::hash`](../../api/basic_json/std_hash.md) | conversion of a `#!cpp std::size_t` to `StringType`: either assignability from the result of `#!cpp std::to_string`, or an ADL overload `#!cpp void int_to_string(StringType&, std::size_t)` |
|
| [`diff`](../../api/basic_json/diff.md), [`items`](../../api/basic_json/items.md), [`std::hash`](../../api/basic_json/std_hash.md) | conversion of a `#!cpp std::size_t` to `StringType`: either assignability from the result of `#!cpp std::to_string`, or an ADL overload `#!cpp void int_to_string(StringType&, std::size_t)` |
|
||||||
|
| [`operator/(std::size_t)`](../../api/json_pointer/operator_slash.md) | the same conversion of a `#!cpp std::size_t` to `StringType` as `diff`, `items`, and `std::hash` above |
|
||||||
| [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) | additionally a specialization of `#!cpp std::hash<StringType>` |
|
| [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) | additionally a specialization of `#!cpp std::hash<StringType>` |
|
||||||
| [`to_bson`](../../api/basic_json/to_bson.md) | `find(value_type)` and `npos` |
|
| [`to_bson`](../../api/basic_json/to_bson.md) | `find(value_type)` and `npos` |
|
||||||
| [`parse`](../../api/basic_json/parse.md) from a `string_t` | the input adapters must accept it; otherwise pass a character range |
|
| [`parse`](../../api/basic_json/parse.md) from a `string_t` | the input adapters must accept it; otherwise pass a character range |
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
# Compile times
|
|
||||||
|
|
||||||
The library is header-only and makes heavy use of templates, so every translation unit that includes
|
|
||||||
`<nlohmann/json.hpp>` pays for parsing the header and instantiating what it uses. This page lists the options to reduce
|
|
||||||
that cost, ordered by how much they typically save.
|
|
||||||
|
|
||||||
!!! info "Measurements"
|
|
||||||
|
|
||||||
The numbers below are medians of nine runs compiling a single translation unit with `-std=c++17 -c` against the
|
|
||||||
single-header version, with Apple clang and GCC 16 on macOS (Apple silicon). They show the order of magnitude to
|
|
||||||
expect; measure your own code before and after a change.
|
|
||||||
|
|
||||||
## Include `json_fwd.hpp` in headers
|
|
||||||
|
|
||||||
Header files that only need to *name* the `json` type — for function declarations, members held by pointer or
|
|
||||||
reference, or friend declarations — can include `<nlohmann/json_fwd.hpp>` instead of `<nlohmann/json.hpp>`. It only
|
|
||||||
forward-declares `basic_json`, `json`, `ordered_json`, `json_pointer`, and `adl_serializer`. The translation units that
|
|
||||||
actually use the values then include `<nlohmann/json.hpp>`.
|
|
||||||
|
|
||||||
```cpp title="person.hpp"
|
|
||||||
#pragma once
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
|
||||||
|
|
||||||
struct person;
|
|
||||||
void to_json(nlohmann::json& j, const person& p);
|
|
||||||
void from_json(const nlohmann::json& j, person& p);
|
|
||||||
```
|
|
||||||
|
|
||||||
```cpp title="person.cpp"
|
|
||||||
#include "person.hpp"
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
void to_json(nlohmann::json& j, const person& p) { /* ... */ }
|
|
||||||
void from_json(const nlohmann::json& j, person& p) { /* ... */ }
|
|
||||||
```
|
|
||||||
|
|
||||||
| Compiler | `json.hpp` (`-O0`) | `json_fwd.hpp` (`-O0`) | Change |
|
|
||||||
|-------------|-------------------:|-----------------------:|-------:|
|
|
||||||
| Apple clang | 704 ms | 329 ms | −53% |
|
|
||||||
| GCC 16 | 779 ms | 242 ms | −69% |
|
|
||||||
|
|
||||||
This is the most effective option, because it avoids the full header in every translation unit that includes
|
|
||||||
*your* headers.
|
|
||||||
|
|
||||||
## Opt out of the automatic user-defined string literals
|
|
||||||
|
|
||||||
The user-defined string literals [`operator""_json`](../api/operator_literal_json.md) and
|
|
||||||
[`operator""_json_pointer`](../api/operator_literal_json_pointer.md) are ordinary inline functions whose bodies call the
|
|
||||||
parser. As `<nlohmann/json.hpp>` includes them by default, every translation unit instantiates the parser, even if it
|
|
||||||
never parses anything itself.
|
|
||||||
|
|
||||||
Define [`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md) for the whole project and include
|
|
||||||
`<nlohmann/json_literals.hpp>` only in the files that use the literals:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
target_compile_definitions(my_target PRIVATE JSON_NO_AUTOMATIC_UDLS)
|
|
||||||
```
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <nlohmann/json_literals.hpp> // only where "..."_json is used
|
|
||||||
```
|
|
||||||
|
|
||||||
The saving applies to translation units that do not parse JSON, for example ones that define types and their
|
|
||||||
conversions or only pass `json` values around:
|
|
||||||
|
|
||||||
| Compiler | Translation unit | Default (`-O0` / `-O2`) | `JSON_NO_AUTOMATIC_UDLS` (`-O0` / `-O2`) | Change |
|
|
||||||
|-------------|------------------|------------------------:|-----------------------------------------:|------------:|
|
|
||||||
| Apple clang | model | 776 ms / 846 ms | 629 ms / 692 ms | −19% / −18% |
|
|
||||||
| GCC 16 | model | 1022 ms / 1120 ms | 882 ms / 965 ms | −14% / −14% |
|
|
||||||
| Apple clang | parsing | 992 ms / 1815 ms | 1006 ms / 1823 ms | +1% / 0% |
|
|
||||||
| GCC 16 | parsing | 2018 ms / 3420 ms | 1990 ms / 3454 ms | −1% / +1% |
|
|
||||||
|
|
||||||
Translation units that include only the header save up to a third. Translation units that parse anyway instantiate
|
|
||||||
the parser regardless and see no difference.
|
|
||||||
|
|
||||||
## Instantiate `basic_json` once
|
|
||||||
|
|
||||||
Each translation unit instantiates the member functions of `nlohmann::json` it uses. An explicit instantiation
|
|
||||||
declaration tells the compiler that the non-template members are instantiated elsewhere, so it can skip them:
|
|
||||||
|
|
||||||
```cpp title="json_instance.hpp"
|
|
||||||
#pragma once
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
extern template class nlohmann::basic_json<>;
|
|
||||||
```
|
|
||||||
|
|
||||||
```cpp title="json_instance.cpp"
|
|
||||||
#include "json_instance.hpp"
|
|
||||||
|
|
||||||
template class nlohmann::basic_json<>;
|
|
||||||
```
|
|
||||||
|
|
||||||
Include `json_instance.hpp` instead of `<nlohmann/json.hpp>` and compile and link `json_instance.cpp` once.
|
|
||||||
|
|
||||||
| Compiler | Translation unit | Default (`-O0` / `-O2`) | `extern template` (`-O0` / `-O2`) | Change |
|
|
||||||
|-------------|---------------------|------------------------:|----------------------------------:|------------:|
|
|
||||||
| Apple clang | parsing | 992 ms / 1815 ms | 953 ms / 1625 ms | −4% / −10% |
|
|
||||||
| GCC 16 | parsing | 2018 ms / 3420 ms | 1522 ms / 2728 ms | −25% / −20% |
|
|
||||||
| Apple clang | `json_instance.cpp` | — | 2166 ms / 4660 ms | — |
|
|
||||||
| GCC 16 | `json_instance.cpp` | — | 5085 ms / 10616 ms | — |
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
- The saving grows with the number of translation units that use `json`, while the instantiation translation unit is
|
|
||||||
compiled only once (and is rarely recompiled, as it does not depend on your code).
|
|
||||||
- Member function templates (such as `get<T>()`, `parse(InputType&&)`, or `value(key, default)`) are not covered by
|
|
||||||
the explicit instantiation and are still instantiated where they are used.
|
|
||||||
- The declaration covers exactly `nlohmann::json`. Add the same lines for `nlohmann::ordered_json`
|
|
||||||
(`nlohmann::basic_json<nlohmann::ordered_map>`) or your own `basic_json` specializations if you use them.
|
|
||||||
|
|
||||||
## Use C++20 modules
|
|
||||||
|
|
||||||
With a toolchain that supports named modules, `import nlohmann.json;` compiles the library once into a module and
|
|
||||||
avoids parsing the header in every translation unit. See [Modules](../features/modules.md) for requirements and known
|
|
||||||
issues. Module support is experimental and currently depends heavily on the compiler version.
|
|
||||||
|
|
||||||
## Use precompiled headers
|
|
||||||
|
|
||||||
Build systems can precompile `<nlohmann/json.hpp>` together with other stable headers, for example with CMake's
|
|
||||||
[`target_precompile_headers`](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html):
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
target_precompile_headers(my_target PRIVATE <nlohmann/json.hpp>)
|
|
||||||
```
|
|
||||||
|
|
||||||
This removes the cost of parsing the header, but not of instantiating templates in each translation unit, so it
|
|
||||||
combines well with the options above.
|
|
||||||
|
|
||||||
## Options without effect on compile times
|
|
||||||
|
|
||||||
Some configuration macros change what the library declares, but do not measurably change compile times:
|
|
||||||
|
|
||||||
| Macro | Apple clang, model (`-O0` / `-O2`) | GCC 16, model (`-O0` / `-O2`) |
|
|
||||||
|------------------------------------------------------------------------|-----------------------------------:|------------------------------:|
|
|
||||||
| default | 776 ms / 846 ms | 1022 ms / 1120 ms |
|
|
||||||
| [`JSON_NO_IO`](../api/macros/json_no_io.md) | 764 ms / 836 ms | 1022 ms / 1117 ms |
|
|
||||||
| [`JSON_USE_GLOBAL_UDLS`](../api/macros/json_use_global_udls.md)`=0` | 763 ms / 852 ms | 1019 ms / 1106 ms |
|
|
||||||
|
|
||||||
`JSON_USE_GLOBAL_UDLS` only controls *where* the literals are declared; to avoid their cost, use
|
|
||||||
`JSON_NO_AUTOMATIC_UDLS` instead.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md) - do not include the user-defined string
|
|
||||||
literals automatically
|
|
||||||
- [Modules](../features/modules.md) - C++20 module support
|
|
||||||
- [Header only](index.md) - including the library
|
|
||||||
@@ -15,7 +15,7 @@ Clang).
|
|||||||
|
|
||||||
You can further use file
|
You can further use file
|
||||||
[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp)
|
[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp)
|
||||||
for forward declarations (see [Compile times](compile_times.md)), and file
|
for forward declarations, and file
|
||||||
[`single_include/nlohmann/json_literals.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_literals.hpp)
|
[`single_include/nlohmann/json_literals.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_literals.hpp)
|
||||||
for the user-defined string literals if you define
|
for the user-defined string literals if you define
|
||||||
[`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md).
|
[`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md).
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ nav:
|
|||||||
- integration/cmake.md
|
- integration/cmake.md
|
||||||
- integration/package_managers.md
|
- integration/package_managers.md
|
||||||
- integration/pkg-config.md
|
- integration/pkg-config.md
|
||||||
- integration/compile_times.md
|
|
||||||
- API Documentation:
|
- API Documentation:
|
||||||
- basic_json:
|
- basic_json:
|
||||||
- 'Overview': api/basic_json/index.md
|
- 'Overview': api/basic_json/index.md
|
||||||
|
|||||||
@@ -291,7 +291,9 @@ void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(std::is_not
|
|||||||
{
|
{
|
||||||
if (opt.has_value())
|
if (opt.has_value())
|
||||||
{
|
{
|
||||||
j = *opt;
|
// explicit construction, as the conversion from a basic_json with a different
|
||||||
|
// string type is explicit if JSON_USE_IMPLICIT_CONVERSIONS is 0 (#2649)
|
||||||
|
j = BasicJsonType(*opt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
#include <nlohmann/detail/string_concat.hpp>
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
#include <nlohmann/detail/string_escape.hpp>
|
#include <nlohmann/detail/string_escape.hpp>
|
||||||
|
#include <nlohmann/detail/string_utils.hpp>
|
||||||
#include <nlohmann/detail/value_t.hpp>
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
@@ -116,7 +117,7 @@ class json_pointer
|
|||||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||||
json_pointer& operator/=(std::size_t array_idx)
|
json_pointer& operator/=(std::size_t array_idx)
|
||||||
{
|
{
|
||||||
return *this /= std::to_string(array_idx);
|
return *this /= detail::to_string<string_t>(array_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
||||||
@@ -752,7 +753,7 @@ class json_pointer
|
|||||||
// would throw out_of_range.404 -- contains() must not throw (see #5395)
|
// would throw out_of_range.404 -- contains() must not throw (see #5395)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
|
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !('0' <= reference_token[0] && reference_token[0] <= '9')))
|
||||||
{
|
{
|
||||||
// invalid char
|
// invalid char
|
||||||
return false;
|
return false;
|
||||||
@@ -780,7 +781,7 @@ class json_pointer
|
|||||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
// not throw (see #5395), so such a reference token is treated as "not found"
|
||||||
errno = 0; // strtoull() does not reset errno on success
|
errno = 0; // strtoull() does not reset errno on success
|
||||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
const unsigned long long magnitude = std::strtoull(reference_token.data(), &p_end, 10); // NOLINT(runtime/int)
|
||||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
||||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1606,12 +1606,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// whether a basic_json specialization can be converted implicitly into this one;
|
||||||
|
/// with JSON_USE_IMPLICIT_CONVERSIONS set to 0, this is only the case if both share
|
||||||
|
/// the same string type (see https://github.com/nlohmann/json/issues/2649)
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
using is_implicitly_convertible_basic_json = std::integral_constant < bool,
|
||||||
|
(JSON_USE_IMPLICIT_CONVERSIONS != 0)
|
||||||
|
|| std::is_same<typename BasicJsonType::string_t, string_t>::value >;
|
||||||
|
|
||||||
|
/// tag to select the constructor that performs the conversion from another basic_json specialization
|
||||||
|
struct convert_basic_json_tag {};
|
||||||
|
|
||||||
|
public:
|
||||||
/// @brief create a JSON value from an existing one
|
/// @brief create a JSON value from an existing one
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||||
template < typename BasicJsonType,
|
template < typename BasicJsonType,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
|
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||||
|
&& is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||||
basic_json(const BasicJsonType& val)
|
basic_json(const BasicJsonType& val)
|
||||||
|
: basic_json(val, convert_basic_json_tag{})
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @brief create a JSON value from an existing one
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||||
|
template < typename BasicJsonType,
|
||||||
|
detail::enable_if_t <
|
||||||
|
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||||
|
&& !is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||||
|
explicit basic_json(const BasicJsonType& val)
|
||||||
|
: basic_json(val, convert_basic_json_tag{})
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
basic_json(const BasicJsonType& val, convert_basic_json_tag /*unused*/)
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
: start_position(val.start_pos()),
|
: start_position(val.start_pos()),
|
||||||
end_position(val.end_pos())
|
end_position(val.end_pos())
|
||||||
@@ -1667,6 +1697,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
/// @brief create a container (array or object) from an initializer list
|
/// @brief create a container (array or object) from an initializer list
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||||
basic_json(initializer_list_t init,
|
basic_json(initializer_list_t init,
|
||||||
@@ -2433,7 +2464,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
int > = 0 >
|
int > = 0 >
|
||||||
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
||||||
{
|
{
|
||||||
return *this;
|
return BasicJsonType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -2572,7 +2603,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
int> = 0>
|
int> = 0>
|
||||||
ValueType & get_to(ValueType& v) const
|
ValueType & get_to(ValueType& v) const
|
||||||
{
|
{
|
||||||
v = *this;
|
v = ValueType(*this);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5092,7 +5123,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
|
||||||
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
||||||
{
|
{
|
||||||
parser(detail::input_adapter(i)).parse(false, j);
|
// parse into a temporary so that j is left unchanged if parsing fails
|
||||||
|
basic_json result;
|
||||||
|
parser(detail::input_adapter(i)).parse(false, result);
|
||||||
|
j = std::move(result);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
#endif // JSON_NO_IO
|
#endif // JSON_NO_IO
|
||||||
|
|||||||
@@ -6822,7 +6822,9 @@ void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(std::is_not
|
|||||||
{
|
{
|
||||||
if (opt.has_value())
|
if (opt.has_value())
|
||||||
{
|
{
|
||||||
j = *opt;
|
// explicit construction, as the conversion from a basic_json with a different
|
||||||
|
// string type is explicit if JSON_USE_IMPLICIT_CONVERSIONS is 0 (#2649)
|
||||||
|
j = BasicJsonType(*opt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -19636,6 +19638,8 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
// #include <nlohmann/detail/string_escape.hpp>
|
// #include <nlohmann/detail/string_escape.hpp>
|
||||||
|
|
||||||
|
// #include <nlohmann/detail/string_utils.hpp>
|
||||||
|
|
||||||
// #include <nlohmann/detail/value_t.hpp>
|
// #include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
|
||||||
@@ -19727,7 +19731,7 @@ class json_pointer
|
|||||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||||
json_pointer& operator/=(std::size_t array_idx)
|
json_pointer& operator/=(std::size_t array_idx)
|
||||||
{
|
{
|
||||||
return *this /= std::to_string(array_idx);
|
return *this /= detail::to_string<string_t>(array_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
||||||
@@ -20363,7 +20367,7 @@ class json_pointer
|
|||||||
// would throw out_of_range.404 -- contains() must not throw (see #5395)
|
// would throw out_of_range.404 -- contains() must not throw (see #5395)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
|
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !('0' <= reference_token[0] && reference_token[0] <= '9')))
|
||||||
{
|
{
|
||||||
// invalid char
|
// invalid char
|
||||||
return false;
|
return false;
|
||||||
@@ -20391,7 +20395,7 @@ class json_pointer
|
|||||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
// not throw (see #5395), so such a reference token is treated as "not found"
|
||||||
errno = 0; // strtoull() does not reset errno on success
|
errno = 0; // strtoull() does not reset errno on success
|
||||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
const unsigned long long magnitude = std::strtoull(reference_token.data(), &p_end, 10); // NOLINT(runtime/int)
|
||||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
||||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||||
{
|
{
|
||||||
@@ -28531,12 +28535,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// whether a basic_json specialization can be converted implicitly into this one;
|
||||||
|
/// with JSON_USE_IMPLICIT_CONVERSIONS set to 0, this is only the case if both share
|
||||||
|
/// the same string type (see https://github.com/nlohmann/json/issues/2649)
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
using is_implicitly_convertible_basic_json = std::integral_constant < bool,
|
||||||
|
(JSON_USE_IMPLICIT_CONVERSIONS != 0)
|
||||||
|
|| std::is_same<typename BasicJsonType::string_t, string_t>::value >;
|
||||||
|
|
||||||
|
/// tag to select the constructor that performs the conversion from another basic_json specialization
|
||||||
|
struct convert_basic_json_tag {};
|
||||||
|
|
||||||
|
public:
|
||||||
/// @brief create a JSON value from an existing one
|
/// @brief create a JSON value from an existing one
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||||
template < typename BasicJsonType,
|
template < typename BasicJsonType,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
|
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||||
|
&& is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||||
basic_json(const BasicJsonType& val)
|
basic_json(const BasicJsonType& val)
|
||||||
|
: basic_json(val, convert_basic_json_tag{})
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @brief create a JSON value from an existing one
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||||
|
template < typename BasicJsonType,
|
||||||
|
detail::enable_if_t <
|
||||||
|
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||||
|
&& !is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||||
|
explicit basic_json(const BasicJsonType& val)
|
||||||
|
: basic_json(val, convert_basic_json_tag{})
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
basic_json(const BasicJsonType& val, convert_basic_json_tag /*unused*/)
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
: start_position(val.start_pos()),
|
: start_position(val.start_pos()),
|
||||||
end_position(val.end_pos())
|
end_position(val.end_pos())
|
||||||
@@ -28592,6 +28626,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
/// @brief create a container (array or object) from an initializer list
|
/// @brief create a container (array or object) from an initializer list
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||||
basic_json(initializer_list_t init,
|
basic_json(initializer_list_t init,
|
||||||
@@ -29358,7 +29393,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
int > = 0 >
|
int > = 0 >
|
||||||
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
||||||
{
|
{
|
||||||
return *this;
|
return BasicJsonType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -29497,7 +29532,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
int> = 0>
|
int> = 0>
|
||||||
ValueType & get_to(ValueType& v) const
|
ValueType & get_to(ValueType& v) const
|
||||||
{
|
{
|
||||||
v = *this;
|
v = ValueType(*this);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32017,7 +32052,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
|
||||||
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
||||||
{
|
{
|
||||||
parser(detail::input_adapter(i)).parse(false, j);
|
// parse into a temporary so that j is left unchanged if parsing fails
|
||||||
|
basic_json result;
|
||||||
|
parser(detail::input_adapter(i)).parse(false, result);
|
||||||
|
j = std::move(result);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
#endif // JSON_NO_IO
|
#endif // JSON_NO_IO
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -352,6 +353,41 @@ TEST_CASE("alternative string type")
|
|||||||
CHECK(j2.flatten().unflatten() == j2);
|
CHECK(j2.flatten().unflatten() == j2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("contains(json_pointer)")
|
||||||
|
{
|
||||||
|
// contains(json_pointer) must compile and work with a string_t that has
|
||||||
|
// no c_str() and no comparison with const char* (see #5666)
|
||||||
|
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
||||||
|
|
||||||
|
// present: object key and array indices
|
||||||
|
CHECK(j.contains(alt_json::json_pointer("/foo")));
|
||||||
|
CHECK(j.contains(alt_json::json_pointer("/foo/0")));
|
||||||
|
CHECK(j.contains(alt_json::json_pointer("/foo/1")));
|
||||||
|
|
||||||
|
// missing: absent object key and out-of-range array index
|
||||||
|
CHECK_FALSE(j.contains(alt_json::json_pointer("/bar")));
|
||||||
|
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/2")));
|
||||||
|
|
||||||
|
// "-" always fails the range check
|
||||||
|
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/-")));
|
||||||
|
|
||||||
|
// an array index must not have a leading zero
|
||||||
|
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/01")));
|
||||||
|
|
||||||
|
// a reference token that is not a number
|
||||||
|
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/bar")));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("operator/(std::size_t)")
|
||||||
|
{
|
||||||
|
// json_pointer::operator/=(std::size_t) must compile without string_t
|
||||||
|
// being constructible from std::string (see #5666)
|
||||||
|
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
||||||
|
|
||||||
|
CHECK(j.at(alt_json::json_pointer("/foo") / std::size_t(0)) == j["foo"][0]);
|
||||||
|
CHECK(j.at(alt_json::json_pointer("/foo") / std::size_t(1)) == j["foo"][1]);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("patch")
|
SECTION("patch")
|
||||||
{
|
{
|
||||||
alt_json const patch1 = alt_json::parse(R"([{ "op": "add", "path": "/a/b", "value": [ "foo", "bar" ] }])");
|
alt_json const patch1 = alt_json::parse(R"([{ "op": "add", "path": "/a/b", "value": [ "foo", "bar" ] }])");
|
||||||
@@ -384,6 +420,41 @@ TEST_CASE("alternative string type")
|
|||||||
CHECK(j2.dump() == R"({"/foo/0":"bar","/foo/1":"baz"})");
|
CHECK(j2.dump() == R"({"/foo/0":"bar","/foo/1":"baz"})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("conversion between basic_json specializations (#2649)")
|
||||||
|
{
|
||||||
|
// explicit conversions are always possible
|
||||||
|
CHECK(std::is_constructible<nlohmann::json, alt_json>::value);
|
||||||
|
CHECK(std::is_constructible<alt_json, nlohmann::json>::value);
|
||||||
|
CHECK(std::is_constructible<nlohmann::json, nlohmann::ordered_json>::value);
|
||||||
|
CHECK(std::is_constructible<nlohmann::ordered_json, nlohmann::json>::value);
|
||||||
|
|
||||||
|
// specializations with the same string type are implicitly convertible
|
||||||
|
CHECK(std::is_convertible<nlohmann::ordered_json, nlohmann::json>::value);
|
||||||
|
CHECK(std::is_convertible<nlohmann::json, nlohmann::ordered_json>::value);
|
||||||
|
|
||||||
|
// specializations with different string types are only implicitly convertible
|
||||||
|
// if implicit conversions are enabled
|
||||||
|
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||||
|
CHECK(std::is_convertible<alt_json, nlohmann::json>::value);
|
||||||
|
CHECK(std::is_convertible<nlohmann::json, alt_json>::value);
|
||||||
|
#else
|
||||||
|
CHECK_FALSE(std::is_convertible<alt_json, nlohmann::json>::value);
|
||||||
|
CHECK_FALSE(std::is_convertible<nlohmann::json, alt_json>::value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get<BasicJsonType>() works in either case
|
||||||
|
const nlohmann::json j = {{"foo", 1}, {"bar", true}};
|
||||||
|
CHECK(j.get<nlohmann::ordered_json>() == nlohmann::ordered_json(j));
|
||||||
|
// (only a number is converted here, as objects and strings are affected by #3425)
|
||||||
|
CHECK(nlohmann::json(42).get<alt_json>() == 42);
|
||||||
|
CHECK(alt_json(nlohmann::json(42)) == 42);
|
||||||
|
|
||||||
|
// get_to() also works in either case
|
||||||
|
alt_json a;
|
||||||
|
nlohmann::json(42).get_to(a);
|
||||||
|
CHECK(a == 42);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("strict enum")
|
SECTION("strict enum")
|
||||||
{
|
{
|
||||||
// regression test for #5667: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json
|
// regression test for #5667: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using nlohmann::json;
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
TEST_CASE("Better diagnostics")
|
TEST_CASE("Better diagnostics")
|
||||||
{
|
{
|
||||||
@@ -492,6 +493,21 @@ TEST_CASE("Regression tests for extended diagnostics")
|
|||||||
CHECK(copy == j);
|
CHECK(copy == j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("Regression test for issue #5652 - operator>> leaves a partial value in its target on a parse error")
|
||||||
|
{
|
||||||
|
json j = "old value";
|
||||||
|
std::istringstream is("[1, x");
|
||||||
|
CHECK_THROWS_WITH_AS(is >> j, "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '1, x'", json::parse_error);
|
||||||
|
|
||||||
|
// j must be left unchanged, as json::parse() guarantees for its result
|
||||||
|
CHECK(j == "old value");
|
||||||
|
|
||||||
|
// copying j must not trigger assert_invariant(): a failed parse must
|
||||||
|
// not leave array/object elements without a parent pointer
|
||||||
|
json const copy = j; // NOLINT(performance-unnecessary-copy-initialization)
|
||||||
|
CHECK(copy == j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Better diagnostics past the descent bound of update() and merge_patch()")
|
TEST_CASE("Better diagnostics past the descent bound of update() and merge_patch()")
|
||||||
|
|||||||
Reference in New Issue
Block a user