mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 19:50:34 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
954bdad63b | ||
|
|
2dc43e8bf8 | ||
|
|
e0eb3e7490 | ||
|
|
3ae4d7c45e |
@@ -100,7 +100,7 @@ jobs:
|
|||||||
container: ubuntu:focal
|
container: ubuntu:focal
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local]
|
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local]
|
||||||
steps:
|
steps:
|
||||||
- name: Install build-essential
|
- name: Install build-essential
|
||||||
run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev
|
run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ option(JSON_Diagnostic_Positions "Enable diagnostic positions." OFF)
|
|||||||
option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON)
|
option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON)
|
||||||
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
|
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
|
||||||
option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF)
|
option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF)
|
||||||
option(JSON_DisableTupleReferenceConversion "Disable conversion from a one-element tuple of a JSON reference." OFF)
|
|
||||||
option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF)
|
option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF)
|
||||||
option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT})
|
option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT})
|
||||||
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." ON)
|
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." ON)
|
||||||
@@ -102,10 +101,6 @@ if (JSON_DisableEnumSerialization)
|
|||||||
message(STATUS "Enum integer serialization is disabled (JSON_DISABLE_ENUM_SERIALIZATION=1)")
|
message(STATUS "Enum integer serialization is disabled (JSON_DISABLE_ENUM_SERIALIZATION=1)")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (JSON_DisableTupleReferenceConversion)
|
|
||||||
message(STATUS "Tuple reference conversion is disabled (JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1)")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (JSON_LegacyDiscardedValueComparison)
|
if (JSON_LegacyDiscardedValueComparison)
|
||||||
message(STATUS "Legacy discarded value comparison enabled (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1)")
|
message(STATUS "Legacy discarded value comparison enabled (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1)")
|
||||||
endif()
|
endif()
|
||||||
@@ -148,7 +143,6 @@ target_compile_definitions(
|
|||||||
$<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:JSON_USE_GLOBAL_UDLS=0>
|
$<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:JSON_USE_GLOBAL_UDLS=0>
|
||||||
$<$<NOT:$<BOOL:${JSON_ImplicitConversions}>>:JSON_USE_IMPLICIT_CONVERSIONS=0>
|
$<$<NOT:$<BOOL:${JSON_ImplicitConversions}>>:JSON_USE_IMPLICIT_CONVERSIONS=0>
|
||||||
$<$<BOOL:${JSON_DisableEnumSerialization}>:JSON_DISABLE_ENUM_SERIALIZATION=1>
|
$<$<BOOL:${JSON_DisableEnumSerialization}>:JSON_DISABLE_ENUM_SERIALIZATION=1>
|
||||||
$<$<BOOL:${JSON_DisableTupleReferenceConversion}>:JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1>
|
|
||||||
$<$<BOOL:${JSON_Diagnostics}>:JSON_DIAGNOSTICS=1>
|
$<$<BOOL:${JSON_Diagnostics}>:JSON_DIAGNOSTICS=1>
|
||||||
$<$<BOOL:${JSON_Diagnostic_Positions}>:JSON_DIAGNOSTIC_POSITIONS=1>
|
$<$<BOOL:${JSON_Diagnostic_Positions}>:JSON_DIAGNOSTIC_POSITIONS=1>
|
||||||
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
|
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
|
||||||
|
|||||||
@@ -276,20 +276,6 @@ add_custom_target(ci_test_disableenumserialization
|
|||||||
COMMENT "Compile and test with enum serialization disabled"
|
COMMENT "Compile and test with enum serialization disabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Disable conversion from a one-element tuple of a JSON reference.
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
add_custom_target(ci_test_disabletuplereferenceconversion
|
|
||||||
COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
|
||||||
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DisableTupleReferenceConversion=ON
|
|
||||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion
|
|
||||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion
|
|
||||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
|
||||||
COMMENT "Compile and test with tuple reference conversion disabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Skip the multiple-inclusion library version check.
|
# Skip the multiple-inclusion library version check.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -210,7 +210,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'a
|
|||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html');
|
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html');
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html');
|
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html');
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html');
|
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html');
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_TUPLE_REFERENCE_CONVERSION', 'Macro', 'api/macros/json_disable_tuple_reference_conversion/index.html');
|
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
||||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'api/macros/json_has_cpp_11/index.html');
|
||||||
|
|||||||
@@ -159,8 +159,6 @@ basic_json(basic_json&& other) noexcept;
|
|||||||
- `CompatibleType` is not `basic_json` (to avoid hijacking copy/move constructors),
|
- `CompatibleType` is not `basic_json` (to avoid hijacking copy/move constructors),
|
||||||
- `CompatibleType` is not a different `basic_json` type (i.e. with different template arguments)
|
- `CompatibleType` is not a different `basic_json` type (i.e. with different template arguments)
|
||||||
- `CompatibleType` is not a `basic_json` nested type (e.g., `json_pointer`, `iterator`, etc.)
|
- `CompatibleType` is not a `basic_json` nested type (e.g., `json_pointer`, `iterator`, etc.)
|
||||||
- if [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../macros/json_disable_tuple_reference_conversion.md) is defined
|
|
||||||
to `1`: `CompatibleType` is not a one-element `std::tuple` holding a reference to `basic_json`
|
|
||||||
- `json_serializer<U>` (with `U = uncvref_t<CompatibleType>`) has a `to_json(basic_json_t&, CompatibleType&&)`
|
- `json_serializer<U>` (with `U = uncvref_t<CompatibleType>`) has a `to_json(basic_json_t&, CompatibleType&&)`
|
||||||
method
|
method
|
||||||
|
|
||||||
@@ -274,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"
|
||||||
@@ -422,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
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ header. See also the [macro overview page](../../features/macros.md).
|
|||||||
|
|
||||||
- [**JSON_BRACE_INIT_COPY_SEMANTICS**](json_brace_init_copy_semantics.md) - opt in to copy/move semantics for single-element brace initialization
|
- [**JSON_BRACE_INIT_COPY_SEMANTICS**](json_brace_init_copy_semantics.md) - opt in to copy/move semantics for single-element brace initialization
|
||||||
- [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums
|
- [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums
|
||||||
- [**JSON_DISABLE_TUPLE_REFERENCE_CONVERSION**](json_disable_tuple_reference_conversion.md) - switch off conversion from a one-element tuple of a JSON reference
|
|
||||||
- [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions
|
- [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions
|
||||||
|
|
||||||
## Comparison behavior
|
## Comparison behavior
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
# JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION /* value */
|
|
||||||
```
|
|
||||||
|
|
||||||
When defined to `1`, a `basic_json` value can no longer be constructed from a one-element `std::tuple` whose element is
|
|
||||||
a reference to that `basic_json` type, such as `std::tuple<json&>`, `std::tuple<const json&>`, or `std::tuple<json&&>`.
|
|
||||||
These are the tuples created by `std::forward_as_tuple(j)`.
|
|
||||||
|
|
||||||
## Default definition
|
|
||||||
|
|
||||||
The default value is `0` (disabled — existing behavior is preserved).
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
!!! note "Background"
|
|
||||||
|
|
||||||
By default, `basic_json` can be constructed from any `std::tuple` whose elements can be converted to JSON; the result
|
|
||||||
is an array. This includes `std::tuple<json&>`, which becomes a one-element array.
|
|
||||||
|
|
||||||
`std::tuple` only converts another tuple element by element if its element type cannot be constructed from the whole
|
|
||||||
source tuple. Because `json` *can* be constructed from `std::tuple<json&>`, `std::tuple` instead converts the whole
|
|
||||||
tuple into a single `json` value. This has two surprising effects:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
json j = true;
|
|
||||||
|
|
||||||
// rejected by some standard libraries (e.g., libc++); with others, the
|
|
||||||
// reference binds to a temporary that is destroyed right away
|
|
||||||
std::tuple<const json&> t1(std::forward_as_tuple(j));
|
|
||||||
|
|
||||||
// compiles, but std::get<0>(t2) is [true], not true
|
|
||||||
std::tuple<json> t2(std::forward_as_tuple(j));
|
|
||||||
```
|
|
||||||
|
|
||||||
Enabling this macro removes the conversion, so both tuples are converted element by element: `std::get<0>(t1)`
|
|
||||||
refers to `j`, and `std::get<0>(t2)` is a copy of `j` (see [#2226](https://github.com/nlohmann/json/issues/2226)).
|
|
||||||
|
|
||||||
!!! warning "Opt-in only"
|
|
||||||
|
|
||||||
This macro must be defined **before** including `<nlohmann/json.hpp>`. Defining it after the include has no effect.
|
|
||||||
|
|
||||||
!!! note "Affected conversions"
|
|
||||||
|
|
||||||
Only one-element tuples holding a reference to the **same** `basic_json` type are affected. Constructing a JSON value
|
|
||||||
from them no longer compiles:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
json j = true;
|
|
||||||
json a = std::forward_as_tuple(j); // error with the macro enabled
|
|
||||||
json b = json::array({j}); // use this instead: [true]
|
|
||||||
```
|
|
||||||
|
|
||||||
Tuples holding a JSON value (`std::make_tuple(j)`), tuples with more than one element, and tuples holding references
|
|
||||||
to other types (including other `basic_json` specializations) are converted to arrays as before.
|
|
||||||
|
|
||||||
!!! hint "CMake option"
|
|
||||||
|
|
||||||
This behavior can also be controlled with the CMake option
|
|
||||||
[`JSON_DisableTupleReferenceConversion`](../../integration/cmake.md#json_disabletuplereferenceconversion)
|
|
||||||
(`OFF` by default) which defines `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION` accordingly.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
??? example "Default behavior (macro not defined)"
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
json j = true;
|
|
||||||
|
|
||||||
std::tuple<json> t(std::forward_as_tuple(j));
|
|
||||||
// std::get<0>(t) is [true] -- the whole tuple was converted
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
??? example "Conversion disabled (macro defined to 1)"
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
json j = true;
|
|
||||||
|
|
||||||
std::tuple<json> t(std::forward_as_tuple(j));
|
|
||||||
// std::get<0>(t) is true -- a copy of j
|
|
||||||
|
|
||||||
std::tuple<const json&> r(std::forward_as_tuple(j));
|
|
||||||
// std::get<0>(r) refers to j
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [**basic_json(CompatibleType&&)**](../basic_json/basic_json.md) - the affected constructor
|
|
||||||
- [:simple-cmake: JSON_DisableTupleReferenceConversion](../../integration/cmake.md#json_disabletuplereferenceconversion) -
|
|
||||||
CMake option to control the macro
|
|
||||||
|
|
||||||
## Version history
|
|
||||||
|
|
||||||
- Added in version 3.13.0.
|
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -83,13 +83,6 @@ When defined, default parse and serialize functions for enums are excluded and h
|
|||||||
|
|
||||||
See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md).
|
See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md).
|
||||||
|
|
||||||
## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`
|
|
||||||
|
|
||||||
When defined to `1`, a JSON value can no longer be created from a one-element `std::tuple` holding a reference to a JSON
|
|
||||||
value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise.
|
|
||||||
|
|
||||||
See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md).
|
|
||||||
|
|
||||||
## `JSON_NO_AUTOMATIC_UDLS`
|
## `JSON_NO_AUTOMATIC_UDLS`
|
||||||
|
|
||||||
When defined, `<nlohmann/json.hpp>` does not include `<nlohmann/json_literals.hpp>` with the user-defined string literals
|
When defined, `<nlohmann/json.hpp>` does not include `<nlohmann/json_literals.hpp>` with the user-defined string literals
|
||||||
|
|||||||
@@ -169,12 +169,6 @@ Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../a
|
|||||||
Disable default `enum` serialization by defining the macro
|
Disable default `enum` serialization by defining the macro
|
||||||
[`JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). This option is `OFF` by default.
|
[`JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). This option is `OFF` by default.
|
||||||
|
|
||||||
### `JSON_DisableTupleReferenceConversion`
|
|
||||||
|
|
||||||
Disable the conversion from a one-element `std::tuple` holding a reference to a JSON value by defining the macro
|
|
||||||
[`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md). This option is
|
|
||||||
`OFF` by default.
|
|
||||||
|
|
||||||
### `JSON_FastTests`
|
### `JSON_FastTests`
|
||||||
|
|
||||||
Skip expensive/slow test suites. This option is `OFF` by default. Depends on `JSON_BuildTests`.
|
Skip expensive/slow test suites. This option is `OFF` by default. Depends on `JSON_BuildTests`.
|
||||||
|
|||||||
@@ -287,7 +287,6 @@ nav:
|
|||||||
- 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md
|
- 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md
|
||||||
- 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md
|
- 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md
|
||||||
- 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md
|
- 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md
|
||||||
- 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
|
|
||||||
- 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md
|
- 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md
|
||||||
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
|
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
|
||||||
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.md
|
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.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
|
||||||
{
|
{
|
||||||
@@ -471,13 +473,11 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<
|
|||||||
j = { std::get<Idx>(t)... };
|
j = { std::get<Idx>(t)... };
|
||||||
}
|
}
|
||||||
|
|
||||||
// A one-element braced list does not reliably wrap its element: with
|
#if JSON_BRACE_INIT_COPY_SEMANTICS
|
||||||
// JSON_BRACE_INIT_COPY_SEMANTICS it copies it, which would serialize
|
// JSON_BRACE_INIT_COPY_SEMANTICS makes a one-element braced list copy its
|
||||||
// std::tuple<int>{5} as 5 rather than [5], and some compilers (e.g., Apple clang
|
// element instead of wrapping it, which would serialize std::tuple<int>{5} as 5
|
||||||
// 15 and 16) copy an element that is itself a basic_json even without it, so
|
// rather than [5]. Build what the default deduction builds instead: an object
|
||||||
// std::tuple<json>{true} became true rather than [true]. Build what the default
|
// if the element is a [string, value] pair, a one-element array otherwise.
|
||||||
// deduction builds instead: an object if the element is a [string, value] pair,
|
|
||||||
// a one-element array otherwise.
|
|
||||||
template<typename BasicJsonType, typename Tuple>
|
template<typename BasicJsonType, typename Tuple>
|
||||||
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<0> /*unused*/)
|
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<0> /*unused*/)
|
||||||
{
|
{
|
||||||
@@ -495,6 +495,7 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<
|
|||||||
j = BasicJsonType::array({std::move(element)});
|
j = BasicJsonType::array({std::move(element)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename BasicJsonType, typename Tuple>
|
template<typename BasicJsonType, typename Tuple>
|
||||||
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)
|
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)
|
||||||
|
|||||||
@@ -915,7 +915,3 @@ void templated_json_throw(ExceptionType exception)
|
|||||||
#ifndef JSON_DISABLE_ENUM_SERIALIZATION
|
#ifndef JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#undef JSON_INLINE_VARIABLE
|
#undef JSON_INLINE_VARIABLE
|
||||||
#undef JSON_NO_UNIQUE_ADDRESS
|
#undef JSON_NO_UNIQUE_ADDRESS
|
||||||
#undef JSON_DISABLE_ENUM_SERIALIZATION
|
#undef JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
#undef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
|
|
||||||
#ifndef JSON_TEST_KEEP_MACROS
|
#ifndef JSON_TEST_KEEP_MACROS
|
||||||
#undef JSON_CATCH
|
#undef JSON_CATCH
|
||||||
|
|||||||
@@ -636,18 +636,6 @@ template<typename BasicJsonType, typename CompatibleType>
|
|||||||
struct is_compatible_type
|
struct is_compatible_type
|
||||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||||
|
|
||||||
// a one-element std::tuple holding a reference to BasicJsonType, as created by
|
|
||||||
// std::forward_as_tuple(j); see JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
template<typename BasicJsonType, typename T>
|
|
||||||
struct is_basic_json_reference_tuple : std::false_type {};
|
|
||||||
|
|
||||||
template<typename BasicJsonType, typename T>
|
|
||||||
struct is_basic_json_reference_tuple<BasicJsonType, std::tuple<T>>
|
|
||||||
{
|
|
||||||
static constexpr bool value =
|
|
||||||
std::is_reference<T>::value && std::is_same<uncvref_t<T>, BasicJsonType>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
struct is_compatible_binary_type
|
struct is_compatible_binary_type
|
||||||
{
|
{
|
||||||
|
|||||||
+82
-236
@@ -906,11 +906,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/*!
|
/*!
|
||||||
@brief how many levels the operation going on in this thread has descended into
|
@brief how many levels the operation going on in this thread has descended into
|
||||||
|
|
||||||
Copying a value, converting one from another specialization, and comparing
|
Copying a value and comparing two values share this count. The library never
|
||||||
two values share this count. The library never nests one of them inside
|
nests one inside the other - copying a value does not compare one, and
|
||||||
another - none of them does either of the other two on the way - and where
|
comparing two values does not copy them - and where user code nests them
|
||||||
user code nests them anyway, sharing the count only ends a descent sooner
|
anyway, sharing the count only ends a descent sooner than it had to, which
|
||||||
than it had to, which costs a little speed and is never wrong.
|
costs a little speed and is never wrong.
|
||||||
|
|
||||||
A byte is enough: the count never exceeds the limit by more than the single
|
A byte is enough: the count never exceeds the limit by more than the single
|
||||||
level that notices the limit has been reached.
|
level that notices the limit has been reached.
|
||||||
@@ -1267,222 +1267,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
copy_iteratively(src);
|
copy_iteratively(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the value @a val of another specialization into this null
|
|
||||||
value; @a val must be neither an object nor an array
|
|
||||||
|
|
||||||
Converting such a value never descends, so both ways of converting an
|
|
||||||
object or an array (@ref convert_structured) leave their elements of this
|
|
||||||
kind to the converting constructor, which leaves them to this.
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_leaf(const BasicJsonType& val)
|
|
||||||
{
|
|
||||||
using other_boolean_t = typename BasicJsonType::boolean_t;
|
|
||||||
using other_number_float_t = typename BasicJsonType::number_float_t;
|
|
||||||
using other_number_integer_t = typename BasicJsonType::number_integer_t;
|
|
||||||
using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
|
||||||
using other_string_t = typename BasicJsonType::string_t;
|
|
||||||
using other_binary_t = typename BasicJsonType::binary_t;
|
|
||||||
|
|
||||||
switch (val.type())
|
|
||||||
{
|
|
||||||
case value_t::boolean:
|
|
||||||
JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
|
|
||||||
break;
|
|
||||||
case value_t::number_float:
|
|
||||||
JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
|
|
||||||
break;
|
|
||||||
case value_t::number_integer:
|
|
||||||
JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
|
|
||||||
break;
|
|
||||||
case value_t::number_unsigned:
|
|
||||||
JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
|
|
||||||
break;
|
|
||||||
case value_t::string:
|
|
||||||
JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
|
|
||||||
break;
|
|
||||||
case value_t::binary:
|
|
||||||
JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
|
|
||||||
break;
|
|
||||||
case value_t::null:
|
|
||||||
// m_data.m_type is already value_t::null
|
|
||||||
break;
|
|
||||||
case value_t::discarded:
|
|
||||||
m_data.m_type = value_t::discarded;
|
|
||||||
break;
|
|
||||||
case value_t::object: // LCOV_EXCL_LINE
|
|
||||||
case value_t::array: // LCOV_EXCL_LINE
|
|
||||||
default: // LCOV_EXCL_LINE
|
|
||||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// scratch space for the converted elements of the arrays that
|
|
||||||
/// @ref convert_iteratively has yet to create
|
|
||||||
using convert_scratch_t = std::vector<basic_json, AllocatorType<basic_json>>;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief create the object or array @a val converted into this null value
|
|
||||||
|
|
||||||
Its converted elements are the last `val.size()` entries of @a elements (an
|
|
||||||
array) or of @a members (an object); they are moved into the container in
|
|
||||||
one go and then removed.
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_level(const BasicJsonType& val, convert_scratch_t& elements, copy_scratch_t& members)
|
|
||||||
{
|
|
||||||
if (val.is_object())
|
|
||||||
{
|
|
||||||
const auto first = members.end() - static_cast<typename copy_scratch_t::difference_type>(val.size());
|
|
||||||
m_data.m_value.object = create<object_t>(std::make_move_iterator(first),
|
|
||||||
std::make_move_iterator(members.end()));
|
|
||||||
// only now that the object exists may this stop being a null value
|
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
members.erase(first, members.end());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto first = elements.end() - static_cast<typename convert_scratch_t::difference_type>(val.size());
|
|
||||||
m_data.m_value.array = create<array_t>(std::make_move_iterator(first),
|
|
||||||
std::make_move_iterator(elements.end()));
|
|
||||||
// only now that the array exists may this stop being a null value
|
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
elements.erase(first, elements.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
set_parents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the object or array @a val of another specialization into
|
|
||||||
this null value without recursing
|
|
||||||
|
|
||||||
The containers whose conversion has begun are kept on an explicit stack
|
|
||||||
rather than on the call stack. Unlike @ref copy_iteratively, this builds
|
|
||||||
every container from the bottom up: all its elements are converted first,
|
|
||||||
and the container is then created from them in one go, the way the range
|
|
||||||
constructor that converts the levels above the bound does. The two object
|
|
||||||
types need not enumerate their members in the same order, so the members
|
|
||||||
could not be paired up by position anyway, and building from a range keeps
|
|
||||||
what the range constructor does with keys that become equal on conversion.
|
|
||||||
|
|
||||||
Every value is complete before it is handed on, and a container gets its
|
|
||||||
type only once it exists, so whatever throws, every value left behind can
|
|
||||||
be destroyed.
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_iteratively(const BasicJsonType& val)
|
|
||||||
{
|
|
||||||
using other_const_iterator = typename BasicJsonType::const_iterator;
|
|
||||||
|
|
||||||
// the containers whose conversion has begun, innermost last, each with
|
|
||||||
// its element to convert next
|
|
||||||
std::vector<std::pair<const BasicJsonType*, other_const_iterator>> pending;
|
|
||||||
|
|
||||||
// the converted elements of the pending arrays and the converted
|
|
||||||
// members of the pending objects, those of the innermost one last
|
|
||||||
convert_scratch_t elements;
|
|
||||||
copy_scratch_t members;
|
|
||||||
|
|
||||||
pending.emplace_back(&val, val.cbegin());
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
const BasicJsonType& container = *pending.back().first;
|
|
||||||
// a copy, as descending below can reallocate pending; the
|
|
||||||
// iterator kept in pending is only advanced through pending.back()
|
|
||||||
const other_const_iterator next = pending.back().second;
|
|
||||||
|
|
||||||
if (next != container.cend())
|
|
||||||
{
|
|
||||||
if (next->is_structured())
|
|
||||||
{
|
|
||||||
// convert its elements first; next stays where it is until
|
|
||||||
// the converted container is handed back to this one
|
|
||||||
pending.emplace_back(&*next, next->cbegin());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the converting constructor does not descend into this value
|
|
||||||
if (container.is_object())
|
|
||||||
{
|
|
||||||
members.emplace_back(next.key(), *next);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elements.emplace_back(*next);
|
|
||||||
}
|
|
||||||
++pending.back().second;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all elements of the container are converted: create it
|
|
||||||
pending.pop_back();
|
|
||||||
|
|
||||||
if (pending.empty())
|
|
||||||
{
|
|
||||||
convert_level(container, elements, members);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_json converted;
|
|
||||||
converted.convert_level(container, elements, members);
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
|
||||||
converted.start_position = container.start_pos();
|
|
||||||
converted.end_position = container.end_pos();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// hand it to the container it is an element of
|
|
||||||
if (pending.back().first->is_object())
|
|
||||||
{
|
|
||||||
members.emplace_back(pending.back().second.key(), std::move(converted));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elements.push_back(std::move(converted));
|
|
||||||
}
|
|
||||||
++pending.back().second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the object or array @a val of another specialization into
|
|
||||||
this null value
|
|
||||||
|
|
||||||
Converting a container converts its elements, so a value nested deeply
|
|
||||||
enough used to exhaust the call stack. The descent is bounded here as in
|
|
||||||
@ref copy_structured: the first `detail::recursion_depth_limit()` levels
|
|
||||||
are converted by the containers' range constructors, just as they always were,
|
|
||||||
and anything below that is converted without the call stack by
|
|
||||||
@ref convert_iteratively.
|
|
||||||
|
|
||||||
@sa https://github.com/nlohmann/json/issues/5650
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_structured(const BasicJsonType& val)
|
|
||||||
{
|
|
||||||
const nesting_depth_guard guard;
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_LIKELY(guard.okay()))
|
|
||||||
{
|
|
||||||
// every element comes back to the converting constructor
|
|
||||||
if (val.is_object())
|
|
||||||
{
|
|
||||||
using other_object_t = typename BasicJsonType::object_t;
|
|
||||||
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using other_array_t = typename BasicJsonType::array_t;
|
|
||||||
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_iteratively(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// the result of comparing two values, including values that cannot be
|
/// the result of comparing two values, including values that cannot be
|
||||||
/// ordered at all, such as a discarded value or a NaN
|
/// ordered at all, such as a discarded value or a NaN
|
||||||
@@ -1812,12 +1596,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
template < typename CompatibleType,
|
template < typename CompatibleType,
|
||||||
typename U = detail::uncvref_t<CompatibleType>,
|
typename U = detail::uncvref_t<CompatibleType>,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
!detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value
|
!detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
|
||||||
#if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
// see https://github.com/nlohmann/json/issues/2226
|
|
||||||
&& !detail::is_basic_json_reference_tuple<basic_json_t, U>::value
|
|
||||||
#endif
|
|
||||||
, int > = 0 >
|
|
||||||
basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
|
basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
|
||||||
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
|
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
|
||||||
std::forward<CompatibleType>(val))))
|
std::forward<CompatibleType>(val))))
|
||||||
@@ -1827,24 +1606,90 @@ 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())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (val.is_structured())
|
using other_boolean_t = typename BasicJsonType::boolean_t;
|
||||||
|
using other_number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using other_number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using other_string_t = typename BasicJsonType::string_t;
|
||||||
|
using other_object_t = typename BasicJsonType::object_t;
|
||||||
|
using other_array_t = typename BasicJsonType::array_t;
|
||||||
|
using other_binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
|
switch (val.type())
|
||||||
{
|
{
|
||||||
convert_structured(val);
|
case value_t::boolean:
|
||||||
}
|
JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
|
||||||
else
|
break;
|
||||||
{
|
case value_t::number_float:
|
||||||
convert_leaf(val);
|
JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
|
||||||
|
break;
|
||||||
|
case value_t::number_integer:
|
||||||
|
JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
|
||||||
|
break;
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
|
||||||
|
break;
|
||||||
|
case value_t::string:
|
||||||
|
JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::object:
|
||||||
|
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::array:
|
||||||
|
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::binary:
|
||||||
|
JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::null:
|
||||||
|
*this = nullptr;
|
||||||
|
break;
|
||||||
|
case value_t::discarded:
|
||||||
|
m_data.m_type = value_t::discarded;
|
||||||
|
break;
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
JSON_ASSERT(m_data.m_type == val.type());
|
JSON_ASSERT(m_data.m_type == val.type());
|
||||||
|
|
||||||
@@ -1852,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,
|
||||||
@@ -2618,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -2757,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3329,10 +3329,6 @@ void templated_json_throw(ExceptionType exception)
|
|||||||
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
#include <compare> // partial_ordering
|
#include <compare> // partial_ordering
|
||||||
#endif
|
#endif
|
||||||
@@ -4648,18 +4644,6 @@ template<typename BasicJsonType, typename CompatibleType>
|
|||||||
struct is_compatible_type
|
struct is_compatible_type
|
||||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||||
|
|
||||||
// a one-element std::tuple holding a reference to BasicJsonType, as created by
|
|
||||||
// std::forward_as_tuple(j); see JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
template<typename BasicJsonType, typename T>
|
|
||||||
struct is_basic_json_reference_tuple : std::false_type {};
|
|
||||||
|
|
||||||
template<typename BasicJsonType, typename T>
|
|
||||||
struct is_basic_json_reference_tuple<BasicJsonType, std::tuple<T>>
|
|
||||||
{
|
|
||||||
static constexpr bool value =
|
|
||||||
std::is_reference<T>::value && std::is_same<uncvref_t<T>, BasicJsonType>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
struct is_compatible_binary_type
|
struct is_compatible_binary_type
|
||||||
{
|
{
|
||||||
@@ -6838,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
|
||||||
{
|
{
|
||||||
@@ -7018,13 +7004,11 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<
|
|||||||
j = { std::get<Idx>(t)... };
|
j = { std::get<Idx>(t)... };
|
||||||
}
|
}
|
||||||
|
|
||||||
// A one-element braced list does not reliably wrap its element: with
|
#if JSON_BRACE_INIT_COPY_SEMANTICS
|
||||||
// JSON_BRACE_INIT_COPY_SEMANTICS it copies it, which would serialize
|
// JSON_BRACE_INIT_COPY_SEMANTICS makes a one-element braced list copy its
|
||||||
// std::tuple<int>{5} as 5 rather than [5], and some compilers (e.g., Apple clang
|
// element instead of wrapping it, which would serialize std::tuple<int>{5} as 5
|
||||||
// 15 and 16) copy an element that is itself a basic_json even without it, so
|
// rather than [5]. Build what the default deduction builds instead: an object
|
||||||
// std::tuple<json>{true} became true rather than [true]. Build what the default
|
// if the element is a [string, value] pair, a one-element array otherwise.
|
||||||
// deduction builds instead: an object if the element is a [string, value] pair,
|
|
||||||
// a one-element array otherwise.
|
|
||||||
template<typename BasicJsonType, typename Tuple>
|
template<typename BasicJsonType, typename Tuple>
|
||||||
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<0> /*unused*/)
|
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<0> /*unused*/)
|
||||||
{
|
{
|
||||||
@@ -7042,6 +7026,7 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<
|
|||||||
j = BasicJsonType::array({std::move(element)});
|
j = BasicJsonType::array({std::move(element)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename BasicJsonType, typename Tuple>
|
template<typename BasicJsonType, typename Tuple>
|
||||||
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)
|
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)
|
||||||
@@ -27850,11 +27835,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/*!
|
/*!
|
||||||
@brief how many levels the operation going on in this thread has descended into
|
@brief how many levels the operation going on in this thread has descended into
|
||||||
|
|
||||||
Copying a value, converting one from another specialization, and comparing
|
Copying a value and comparing two values share this count. The library never
|
||||||
two values share this count. The library never nests one of them inside
|
nests one inside the other - copying a value does not compare one, and
|
||||||
another - none of them does either of the other two on the way - and where
|
comparing two values does not copy them - and where user code nests them
|
||||||
user code nests them anyway, sharing the count only ends a descent sooner
|
anyway, sharing the count only ends a descent sooner than it had to, which
|
||||||
than it had to, which costs a little speed and is never wrong.
|
costs a little speed and is never wrong.
|
||||||
|
|
||||||
A byte is enough: the count never exceeds the limit by more than the single
|
A byte is enough: the count never exceeds the limit by more than the single
|
||||||
level that notices the limit has been reached.
|
level that notices the limit has been reached.
|
||||||
@@ -28211,222 +28196,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
copy_iteratively(src);
|
copy_iteratively(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the value @a val of another specialization into this null
|
|
||||||
value; @a val must be neither an object nor an array
|
|
||||||
|
|
||||||
Converting such a value never descends, so both ways of converting an
|
|
||||||
object or an array (@ref convert_structured) leave their elements of this
|
|
||||||
kind to the converting constructor, which leaves them to this.
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_leaf(const BasicJsonType& val)
|
|
||||||
{
|
|
||||||
using other_boolean_t = typename BasicJsonType::boolean_t;
|
|
||||||
using other_number_float_t = typename BasicJsonType::number_float_t;
|
|
||||||
using other_number_integer_t = typename BasicJsonType::number_integer_t;
|
|
||||||
using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
|
||||||
using other_string_t = typename BasicJsonType::string_t;
|
|
||||||
using other_binary_t = typename BasicJsonType::binary_t;
|
|
||||||
|
|
||||||
switch (val.type())
|
|
||||||
{
|
|
||||||
case value_t::boolean:
|
|
||||||
JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
|
|
||||||
break;
|
|
||||||
case value_t::number_float:
|
|
||||||
JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
|
|
||||||
break;
|
|
||||||
case value_t::number_integer:
|
|
||||||
JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
|
|
||||||
break;
|
|
||||||
case value_t::number_unsigned:
|
|
||||||
JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
|
|
||||||
break;
|
|
||||||
case value_t::string:
|
|
||||||
JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
|
|
||||||
break;
|
|
||||||
case value_t::binary:
|
|
||||||
JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
|
|
||||||
break;
|
|
||||||
case value_t::null:
|
|
||||||
// m_data.m_type is already value_t::null
|
|
||||||
break;
|
|
||||||
case value_t::discarded:
|
|
||||||
m_data.m_type = value_t::discarded;
|
|
||||||
break;
|
|
||||||
case value_t::object: // LCOV_EXCL_LINE
|
|
||||||
case value_t::array: // LCOV_EXCL_LINE
|
|
||||||
default: // LCOV_EXCL_LINE
|
|
||||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// scratch space for the converted elements of the arrays that
|
|
||||||
/// @ref convert_iteratively has yet to create
|
|
||||||
using convert_scratch_t = std::vector<basic_json, AllocatorType<basic_json>>;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief create the object or array @a val converted into this null value
|
|
||||||
|
|
||||||
Its converted elements are the last `val.size()` entries of @a elements (an
|
|
||||||
array) or of @a members (an object); they are moved into the container in
|
|
||||||
one go and then removed.
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_level(const BasicJsonType& val, convert_scratch_t& elements, copy_scratch_t& members)
|
|
||||||
{
|
|
||||||
if (val.is_object())
|
|
||||||
{
|
|
||||||
const auto first = members.end() - static_cast<typename copy_scratch_t::difference_type>(val.size());
|
|
||||||
m_data.m_value.object = create<object_t>(std::make_move_iterator(first),
|
|
||||||
std::make_move_iterator(members.end()));
|
|
||||||
// only now that the object exists may this stop being a null value
|
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
members.erase(first, members.end());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto first = elements.end() - static_cast<typename convert_scratch_t::difference_type>(val.size());
|
|
||||||
m_data.m_value.array = create<array_t>(std::make_move_iterator(first),
|
|
||||||
std::make_move_iterator(elements.end()));
|
|
||||||
// only now that the array exists may this stop being a null value
|
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
elements.erase(first, elements.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
set_parents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the object or array @a val of another specialization into
|
|
||||||
this null value without recursing
|
|
||||||
|
|
||||||
The containers whose conversion has begun are kept on an explicit stack
|
|
||||||
rather than on the call stack. Unlike @ref copy_iteratively, this builds
|
|
||||||
every container from the bottom up: all its elements are converted first,
|
|
||||||
and the container is then created from them in one go, the way the range
|
|
||||||
constructor that converts the levels above the bound does. The two object
|
|
||||||
types need not enumerate their members in the same order, so the members
|
|
||||||
could not be paired up by position anyway, and building from a range keeps
|
|
||||||
what the range constructor does with keys that become equal on conversion.
|
|
||||||
|
|
||||||
Every value is complete before it is handed on, and a container gets its
|
|
||||||
type only once it exists, so whatever throws, every value left behind can
|
|
||||||
be destroyed.
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_iteratively(const BasicJsonType& val)
|
|
||||||
{
|
|
||||||
using other_const_iterator = typename BasicJsonType::const_iterator;
|
|
||||||
|
|
||||||
// the containers whose conversion has begun, innermost last, each with
|
|
||||||
// its element to convert next
|
|
||||||
std::vector<std::pair<const BasicJsonType*, other_const_iterator>> pending;
|
|
||||||
|
|
||||||
// the converted elements of the pending arrays and the converted
|
|
||||||
// members of the pending objects, those of the innermost one last
|
|
||||||
convert_scratch_t elements;
|
|
||||||
copy_scratch_t members;
|
|
||||||
|
|
||||||
pending.emplace_back(&val, val.cbegin());
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
const BasicJsonType& container = *pending.back().first;
|
|
||||||
// a copy, as descending below can reallocate pending; the
|
|
||||||
// iterator kept in pending is only advanced through pending.back()
|
|
||||||
const other_const_iterator next = pending.back().second;
|
|
||||||
|
|
||||||
if (next != container.cend())
|
|
||||||
{
|
|
||||||
if (next->is_structured())
|
|
||||||
{
|
|
||||||
// convert its elements first; next stays where it is until
|
|
||||||
// the converted container is handed back to this one
|
|
||||||
pending.emplace_back(&*next, next->cbegin());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the converting constructor does not descend into this value
|
|
||||||
if (container.is_object())
|
|
||||||
{
|
|
||||||
members.emplace_back(next.key(), *next);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elements.emplace_back(*next);
|
|
||||||
}
|
|
||||||
++pending.back().second;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all elements of the container are converted: create it
|
|
||||||
pending.pop_back();
|
|
||||||
|
|
||||||
if (pending.empty())
|
|
||||||
{
|
|
||||||
convert_level(container, elements, members);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_json converted;
|
|
||||||
converted.convert_level(container, elements, members);
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
|
||||||
converted.start_position = container.start_pos();
|
|
||||||
converted.end_position = container.end_pos();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// hand it to the container it is an element of
|
|
||||||
if (pending.back().first->is_object())
|
|
||||||
{
|
|
||||||
members.emplace_back(pending.back().second.key(), std::move(converted));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elements.push_back(std::move(converted));
|
|
||||||
}
|
|
||||||
++pending.back().second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief convert the object or array @a val of another specialization into
|
|
||||||
this null value
|
|
||||||
|
|
||||||
Converting a container converts its elements, so a value nested deeply
|
|
||||||
enough used to exhaust the call stack. The descent is bounded here as in
|
|
||||||
@ref copy_structured: the first `detail::recursion_depth_limit()` levels
|
|
||||||
are converted by the containers' range constructors, just as they always were,
|
|
||||||
and anything below that is converted without the call stack by
|
|
||||||
@ref convert_iteratively.
|
|
||||||
|
|
||||||
@sa https://github.com/nlohmann/json/issues/5650
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
void convert_structured(const BasicJsonType& val)
|
|
||||||
{
|
|
||||||
const nesting_depth_guard guard;
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_LIKELY(guard.okay()))
|
|
||||||
{
|
|
||||||
// every element comes back to the converting constructor
|
|
||||||
if (val.is_object())
|
|
||||||
{
|
|
||||||
using other_object_t = typename BasicJsonType::object_t;
|
|
||||||
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using other_array_t = typename BasicJsonType::array_t;
|
|
||||||
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_iteratively(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// the result of comparing two values, including values that cannot be
|
/// the result of comparing two values, including values that cannot be
|
||||||
/// ordered at all, such as a discarded value or a NaN
|
/// ordered at all, such as a discarded value or a NaN
|
||||||
@@ -28756,12 +28525,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
template < typename CompatibleType,
|
template < typename CompatibleType,
|
||||||
typename U = detail::uncvref_t<CompatibleType>,
|
typename U = detail::uncvref_t<CompatibleType>,
|
||||||
detail::enable_if_t <
|
detail::enable_if_t <
|
||||||
!detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value
|
!detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
|
||||||
#if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
// see https://github.com/nlohmann/json/issues/2226
|
|
||||||
&& !detail::is_basic_json_reference_tuple<basic_json_t, U>::value
|
|
||||||
#endif
|
|
||||||
, int > = 0 >
|
|
||||||
basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
|
basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
|
||||||
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
|
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
|
||||||
std::forward<CompatibleType>(val))))
|
std::forward<CompatibleType>(val))))
|
||||||
@@ -28771,24 +28535,90 @@ 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())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (val.is_structured())
|
using other_boolean_t = typename BasicJsonType::boolean_t;
|
||||||
|
using other_number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using other_number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using other_string_t = typename BasicJsonType::string_t;
|
||||||
|
using other_object_t = typename BasicJsonType::object_t;
|
||||||
|
using other_array_t = typename BasicJsonType::array_t;
|
||||||
|
using other_binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
|
switch (val.type())
|
||||||
{
|
{
|
||||||
convert_structured(val);
|
case value_t::boolean:
|
||||||
}
|
JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
|
||||||
else
|
break;
|
||||||
{
|
case value_t::number_float:
|
||||||
convert_leaf(val);
|
JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
|
||||||
|
break;
|
||||||
|
case value_t::number_integer:
|
||||||
|
JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
|
||||||
|
break;
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
|
||||||
|
break;
|
||||||
|
case value_t::string:
|
||||||
|
JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::object:
|
||||||
|
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::array:
|
||||||
|
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::binary:
|
||||||
|
JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
|
||||||
|
break;
|
||||||
|
case value_t::null:
|
||||||
|
*this = nullptr;
|
||||||
|
break;
|
||||||
|
case value_t::discarded:
|
||||||
|
m_data.m_type = value_t::discarded;
|
||||||
|
break;
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
JSON_ASSERT(m_data.m_type == val.type());
|
JSON_ASSERT(m_data.m_type == val.type());
|
||||||
|
|
||||||
@@ -28796,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,
|
||||||
@@ -29562,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -29701,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33774,7 +33605,6 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
|
|||||||
#undef JSON_INLINE_VARIABLE
|
#undef JSON_INLINE_VARIABLE
|
||||||
#undef JSON_NO_UNIQUE_ADDRESS
|
#undef JSON_NO_UNIQUE_ADDRESS
|
||||||
#undef JSON_DISABLE_ENUM_SERIALIZATION
|
#undef JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
#undef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
|
|
||||||
#ifndef JSON_TEST_KEEP_MACROS
|
#ifndef JSON_TEST_KEEP_MACROS
|
||||||
#undef JSON_CATCH
|
#undef JSON_CATCH
|
||||||
|
|||||||
@@ -479,77 +479,6 @@ TEST_CASE("deep copy uses the provided allocator")
|
|||||||
CHECK(copy == j);
|
CHECK(copy == j);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// the number of constructions countdown_allocator lets happen, including the
|
|
||||||
// one that fails; 0 means none ever fails
|
|
||||||
std::size_t constructions_until_failure = 0;
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct countdown_allocator : std::allocator<T>
|
|
||||||
{
|
|
||||||
using std::allocator<T>::allocator;
|
|
||||||
|
|
||||||
template<class U, class... Args>
|
|
||||||
void construct(U* p, Args&& ... args)
|
|
||||||
{
|
|
||||||
if (constructions_until_failure != 0 && --constructions_until_failure == 0)
|
|
||||||
{
|
|
||||||
throw std::bad_alloc();
|
|
||||||
}
|
|
||||||
|
|
||||||
::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U>
|
|
||||||
struct rebind
|
|
||||||
{
|
|
||||||
using other = countdown_allocator<U>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST_CASE("converting a deeply nested value from another specialization fails cleanly (#5650)")
|
|
||||||
{
|
|
||||||
using countdown_json = nlohmann::basic_json<std::map,
|
|
||||||
std::vector,
|
|
||||||
std::string,
|
|
||||||
bool,
|
|
||||||
std::int64_t,
|
|
||||||
std::uint64_t,
|
|
||||||
double,
|
|
||||||
countdown_allocator>;
|
|
||||||
|
|
||||||
// deeper than the 128 levels the converting constructor descends into, so
|
|
||||||
// that failures land on both sides of the bound - or, built with
|
|
||||||
// JSON_NO_THREAD_LOCAL, all in the iterative conversion
|
|
||||||
json j = {1, "two", {{"three", 3}}};
|
|
||||||
for (std::size_t i = 0; i < 150; ++i)
|
|
||||||
{
|
|
||||||
j = json{{"a", json::array({j, "sibling"})}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fail every construction in turn. Each failure has to reach the caller,
|
|
||||||
// and everything built until then has to be destroyed cleanly.
|
|
||||||
std::size_t failures = 0;
|
|
||||||
for (std::size_t n = 1;; ++n)
|
|
||||||
{
|
|
||||||
constructions_until_failure = n;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const countdown_json converted = j;
|
|
||||||
constructions_until_failure = 0;
|
|
||||||
CHECK(converted.dump() == j.dump());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (const std::bad_alloc&)
|
|
||||||
{
|
|
||||||
++failures;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CHECK(failures > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -419,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
|
||||||
|
|||||||
@@ -141,58 +141,6 @@ TEST_CASE("Better diagnostics with positions")
|
|||||||
check_objects(300);
|
check_objects(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("converting keeps the positions of nested values (#5650)")
|
|
||||||
{
|
|
||||||
// Values nested deeper than the converting constructor's descent bound
|
|
||||||
// are converted without the call stack, on a path that has to carry the
|
|
||||||
// positions of every value over itself. Objects and arrays take turns,
|
|
||||||
// and the innermost value is null, which used to lose its positions.
|
|
||||||
const auto check_conversion = [](std::size_t depth)
|
|
||||||
{
|
|
||||||
CAPTURE(depth)
|
|
||||||
|
|
||||||
std::string text;
|
|
||||||
std::string closing;
|
|
||||||
for (std::size_t i = 0; i < depth; ++i)
|
|
||||||
{
|
|
||||||
text += (i % 2 == 0) ? "[12, " : R"({"b":1, "a":)";
|
|
||||||
closing += (i % 2 == 0) ? ']' : '}';
|
|
||||||
}
|
|
||||||
text += "null";
|
|
||||||
text.append(closing.rbegin(), closing.rend());
|
|
||||||
|
|
||||||
const json original = json::parse(text);
|
|
||||||
const nlohmann::ordered_json converted = original;
|
|
||||||
|
|
||||||
const json* o = &original;
|
|
||||||
const nlohmann::ordered_json* c = &converted;
|
|
||||||
for (std::size_t level = 0; level <= depth; ++level)
|
|
||||||
{
|
|
||||||
CAPTURE(level)
|
|
||||||
REQUIRE(c->start_pos() == o->start_pos());
|
|
||||||
REQUIRE(c->end_pos() == o->end_pos());
|
|
||||||
|
|
||||||
if (level < depth)
|
|
||||||
{
|
|
||||||
// the number beside the value nested next
|
|
||||||
const json& o_number = o->is_object() ? o->at("b") : o->at(0);
|
|
||||||
const nlohmann::ordered_json& c_number = c->is_object() ? c->at("b") : c->at(0);
|
|
||||||
REQUIRE(c_number.start_pos() == o_number.start_pos());
|
|
||||||
REQUIRE(c_number.end_pos() == o_number.end_pos());
|
|
||||||
|
|
||||||
o = o->is_object() ? &o->at("a") : &o->at(1);
|
|
||||||
c = c->is_object() ? &c->at("a") : &c->at(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
check_conversion(1);
|
|
||||||
check_conversion(127);
|
|
||||||
check_conversion(128);
|
|
||||||
check_conversion(129);
|
|
||||||
check_conversion(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("JSON patch add to primitive parent (#4292)")
|
SECTION("JSON patch add to primitive parent (#4292)")
|
||||||
{
|
{
|
||||||
// the JSON Patch "add" target /foo/bar/baz has a string parent
|
// the JSON Patch "add" target /foo/bar/baz has a string parent
|
||||||
|
|||||||
@@ -341,36 +341,6 @@ TEST_CASE("Regression tests for extended diagnostics")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Regression test for issue #5650 - converting keeps the parents of nested values")
|
|
||||||
{
|
|
||||||
// A value nested deeper than the converting constructor's descent bound
|
|
||||||
// is converted without the call stack. Every container that path creates
|
|
||||||
// has to have the parents of its children set, or the JSON Pointer in the
|
|
||||||
// diagnostic is cut short. Objects and arrays take turns.
|
|
||||||
const std::size_t pairs = 150;
|
|
||||||
|
|
||||||
json j = "not a number";
|
|
||||||
std::string pointer;
|
|
||||||
for (std::size_t i = 0; i < pairs; ++i)
|
|
||||||
{
|
|
||||||
j = json{{"a", json::array({j})}};
|
|
||||||
pointer += "/a/0";
|
|
||||||
}
|
|
||||||
|
|
||||||
const nlohmann::ordered_json converted = j;
|
|
||||||
|
|
||||||
const nlohmann::ordered_json* inner = &converted;
|
|
||||||
for (std::size_t i = 0; i < pairs; ++i)
|
|
||||||
{
|
|
||||||
inner = &inner->at("a").at(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const expected = "[json.exception.type_error.302] (" + pointer + ") type must be number, but is string";
|
|
||||||
int i = 0;
|
|
||||||
CHECK_THROWS_WITH_AS(i = inner->get<int>(), expected.c_str(), nlohmann::ordered_json::type_error);
|
|
||||||
CHECK(i == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Regression test for issue #5668 - wrong path for std::map/unordered_map with non-string keys")
|
SECTION("Regression test for issue #5668 - wrong path for std::map/unordered_map with non-string keys")
|
||||||
{
|
{
|
||||||
// a map with non-string keys is read from an array of [key, value] arrays;
|
// a map with non-string keys is read from an array of [key, value] arrays;
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
// __ _____ _____ _____
|
|
||||||
// __| | __| | | | 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
|
|
||||||
|
|
||||||
#include "doctest_compatibility.h"
|
|
||||||
|
|
||||||
// This file tests the opt-in JSON_DISABLE_TUPLE_REFERENCE_CONVERSION, so it
|
|
||||||
// defines the macro itself rather than relying on a -D flag, and runs in every
|
|
||||||
// build.
|
|
||||||
#ifdef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
#undef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
using nlohmann::json;
|
|
||||||
using nlohmann::ordered_json;
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <tuple>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
// clang before 4 and GCC before 5 cannot create a std::tuple of basic_json
|
|
||||||
// references at all, with or without JSON_DISABLE_TUPLE_REFERENCE_CONVERSION:
|
|
||||||
// the tuple constructors make them instantiate basic_json's conversion operator
|
|
||||||
// for libstdc++'s internal tuple bases, which fails hard
|
|
||||||
#if (defined(__clang__) && __clang_major__ < 4) || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5)
|
|
||||||
#define SKIP_TESTS_FOR_JSON_REFERENCE_TUPLES
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST_CASE("JSON_DISABLE_TUPLE_REFERENCE_CONVERSION")
|
|
||||||
{
|
|
||||||
SECTION("json is not constructible from a one-element tuple of a json reference")
|
|
||||||
{
|
|
||||||
CHECK_FALSE(std::is_constructible<json, std::tuple<json&>>::value);
|
|
||||||
CHECK_FALSE(std::is_constructible<json, std::tuple<const json&>>::value);
|
|
||||||
CHECK_FALSE(std::is_constructible < json, std::tuple < json && >>::value);
|
|
||||||
CHECK_FALSE(std::is_constructible<json, const std::tuple<json&>&>::value);
|
|
||||||
CHECK_FALSE(std::is_constructible<ordered_json, std::tuple<ordered_json&>>::value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef SKIP_TESTS_FOR_JSON_REFERENCE_TUPLES
|
|
||||||
SECTION("issue #2226 - tuple<const json&> from tuple<json&> keeps the reference")
|
|
||||||
{
|
|
||||||
json j = true;
|
|
||||||
const std::tuple<const json&> tup(std::forward_as_tuple(j));
|
|
||||||
CHECK(&std::get<0>(tup) == &j);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("tuple<json> from tuple<json&> copies the element")
|
|
||||||
{
|
|
||||||
const json j = {{"key", "value"}};
|
|
||||||
const std::tuple<json> t1(std::forward_as_tuple(j));
|
|
||||||
CHECK(std::get<0>(t1) == j);
|
|
||||||
|
|
||||||
json j2 = "text";
|
|
||||||
const std::tuple<json> t2(std::forward_as_tuple(std::move(j2)));
|
|
||||||
CHECK(std::get<0>(t2) == "text");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SECTION("other tuple conversions are not affected")
|
|
||||||
{
|
|
||||||
const json j = true;
|
|
||||||
|
|
||||||
// one-element tuple holding a json value
|
|
||||||
CHECK(json(std::make_tuple(j)) == json::array({true}));
|
|
||||||
|
|
||||||
// tuples with more than one element, even when holding references
|
|
||||||
int i = 1;
|
|
||||||
#ifndef SKIP_TESTS_FOR_JSON_REFERENCE_TUPLES
|
|
||||||
CHECK(json(std::forward_as_tuple(i, j)) == json::array({1, true}));
|
|
||||||
CHECK(json(std::forward_as_tuple(j, j)) == json::array({true, true}));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// one-element tuples holding references to other types
|
|
||||||
std::string s = "text";
|
|
||||||
CHECK(json(std::forward_as_tuple(s)) == json::array({"text"}));
|
|
||||||
CHECK(json(std::forward_as_tuple(i)) == json::array({1}));
|
|
||||||
|
|
||||||
#ifndef SKIP_TESTS_FOR_JSON_REFERENCE_TUPLES
|
|
||||||
// a reference to a different basic_json specialization
|
|
||||||
ordered_json oj = true;
|
|
||||||
CHECK(json(std::forward_as_tuple(oj)) == json::array({true}));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,6 @@ using nlohmann::json;
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
TEST_CASE("tests on very large JSONs")
|
TEST_CASE("tests on very large JSONs")
|
||||||
{
|
{
|
||||||
@@ -54,24 +53,6 @@ const json* innermost_value(const json& j, std::size_t& depth)
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The text of a value nested depth levels deep around the number 0. Level i is
|
|
||||||
// an array if pattern[i % pattern.size()] is '[', and otherwise an object with
|
|
||||||
// the single member "a", which every object type enumerates in the same order.
|
|
||||||
std::string nested_text(std::size_t depth, const std::string& pattern)
|
|
||||||
{
|
|
||||||
std::string text;
|
|
||||||
std::string closing;
|
|
||||||
for (std::size_t i = 0; i < depth; ++i)
|
|
||||||
{
|
|
||||||
const bool array = pattern[i % pattern.size()] == '[';
|
|
||||||
text += array ? "[" : "{\"a\":";
|
|
||||||
closing += array ? ']' : '}';
|
|
||||||
}
|
|
||||||
text += '0';
|
|
||||||
text.append(closing.rbegin(), closing.rend());
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_CASE("tests on deeply nested JSONs")
|
TEST_CASE("tests on deeply nested JSONs")
|
||||||
@@ -243,114 +224,5 @@ TEST_CASE("tests on deeply nested JSONs")
|
|||||||
CHECK(*innermost_value(j, unused) == 0);
|
CHECK(*innermost_value(j, unused) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("issue #5650 - stack overflow converting between specializations")
|
|
||||||
{
|
|
||||||
const std::vector<std::string> patterns = {"[", "{", "[{"};
|
|
||||||
|
|
||||||
SECTION("json to ordered_json")
|
|
||||||
{
|
|
||||||
for (const auto& pattern : patterns)
|
|
||||||
{
|
|
||||||
CAPTURE(pattern);
|
|
||||||
const std::string text = nested_text(depth, pattern);
|
|
||||||
const json j = json::parse(text);
|
|
||||||
|
|
||||||
const nlohmann::ordered_json converted = j;
|
|
||||||
CHECK(converted.dump() == text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("ordered_json to json")
|
|
||||||
{
|
|
||||||
for (const auto& pattern : patterns)
|
|
||||||
{
|
|
||||||
CAPTURE(pattern);
|
|
||||||
const std::string text = nested_text(depth, pattern);
|
|
||||||
const nlohmann::ordered_json o = nlohmann::ordered_json::parse(text);
|
|
||||||
|
|
||||||
const json converted = o;
|
|
||||||
CHECK(converted.dump() == text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("get<ordered_json>()")
|
|
||||||
{
|
|
||||||
for (const auto& pattern : patterns)
|
|
||||||
{
|
|
||||||
CAPTURE(pattern);
|
|
||||||
const std::string text = nested_text(depth, pattern);
|
|
||||||
const json j = json::parse(text);
|
|
||||||
|
|
||||||
CHECK(j.get<nlohmann::ordered_json>().dump() == text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("depths around the bound of the recursive descent")
|
|
||||||
{
|
|
||||||
for (std::size_t d = 1; d <= 300; ++d)
|
|
||||||
{
|
|
||||||
CAPTURE(d);
|
|
||||||
for (const auto& pattern : patterns)
|
|
||||||
{
|
|
||||||
CAPTURE(pattern);
|
|
||||||
const std::string text = nested_text(d, pattern);
|
|
||||||
const json j = json::parse(text);
|
|
||||||
|
|
||||||
const nlohmann::ordered_json converted = j;
|
|
||||||
CHECK(converted.dump() == text);
|
|
||||||
const json back = converted;
|
|
||||||
CHECK(back.dump() == text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("values below the bound are converted as values above it")
|
|
||||||
{
|
|
||||||
// Bury a value below the bound, where it is converted without the
|
|
||||||
// call stack, and compare it with the same value converted on its
|
|
||||||
// own by the containers' range constructors. Its objects have
|
|
||||||
// members that the two object types enumerate in different orders.
|
|
||||||
const auto bury = [](nlohmann::ordered_json value)
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < 200; ++i)
|
|
||||||
{
|
|
||||||
value = nlohmann::ordered_json::array({std::move(value)});
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
const auto dig = [](const json & value)
|
|
||||||
{
|
|
||||||
const json* current = &value;
|
|
||||||
for (std::size_t i = 0; i < 200; ++i)
|
|
||||||
{
|
|
||||||
current = ¤t->at(0);
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
};
|
|
||||||
|
|
||||||
nlohmann::ordered_json value = nlohmann::ordered_json::object();
|
|
||||||
value["z"] = {1, -2, 3U, 4.5, true, nullptr, "six", nlohmann::ordered_json::binary({7, 8}, 9),
|
|
||||||
nlohmann::ordered_json::binary({10}), nlohmann::ordered_json::array(), nlohmann::ordered_json::object()
|
|
||||||
};
|
|
||||||
value["y"] = {{"x", {{"w", 1}, {"v", 2}}}, {"u", {3, {{"t", 4}, {"s", 5}}}}};
|
|
||||||
value["r"] = nlohmann::ordered_json::array({nlohmann::ordered_json(nlohmann::ordered_json::value_t::discarded)});
|
|
||||||
|
|
||||||
const json converted_above = value;
|
|
||||||
const json buried = bury(value);
|
|
||||||
const json& converted_below = *dig(buried);
|
|
||||||
|
|
||||||
CHECK(converted_below.dump() == converted_above.dump());
|
|
||||||
CHECK(converted_below.at("z").at(7).get_binary().subtype() == 9);
|
|
||||||
CHECK_FALSE(converted_below.at("z").at(8).get_binary().has_subtype());
|
|
||||||
CHECK(converted_below.at("r").at(0).is_discarded());
|
|
||||||
|
|
||||||
// a discarded value is never equal to anything, so compare the rest
|
|
||||||
value.erase("r");
|
|
||||||
const json without_discarded_above = value;
|
|
||||||
const json without_discarded_buried = bury(value);
|
|
||||||
CHECK(*dig(without_discarded_buried) == without_discarded_above);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,19 +18,6 @@
|
|||||||
// for some reason including this after the json header leads to linker errors with VS 2017...
|
// for some reason including this after the json header leads to linker errors with VS 2017...
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
// skip tests if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1 (#2226)
|
|
||||||
#if defined(JSON_DISABLE_TUPLE_REFERENCE_CONVERSION) && (JSON_DISABLE_TUPLE_REFERENCE_CONVERSION == 1)
|
|
||||||
#define SKIP_TESTS_FOR_TUPLE_REFERENCE_CONVERSION
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clang before 4 and GCC before 5 cannot create a std::tuple of basic_json
|
|
||||||
// references at all, with or without JSON_DISABLE_TUPLE_REFERENCE_CONVERSION:
|
|
||||||
// the tuple constructors make them instantiate basic_json's conversion operator
|
|
||||||
// for libstdc++'s internal tuple bases, which fails hard
|
|
||||||
#if (defined(__clang__) && __clang_major__ < 4) || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5)
|
|
||||||
#define SKIP_TESTS_FOR_JSON_REFERENCE_TUPLES
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define JSON_TESTS_PRIVATE
|
#define JSON_TESTS_PRIVATE
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
@@ -41,7 +28,6 @@ using ordered_json = nlohmann::ordered_json;
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <tuple>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -556,20 +542,6 @@ TEST_CASE("regression tests 2")
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SKIP_TESTS_FOR_TUPLE_REFERENCE_CONVERSION
|
|
||||||
SECTION("issue #2226 - std::tuple dangling reference - implicit conversion")
|
|
||||||
{
|
|
||||||
// by default, a one-element tuple holding a json reference converts to
|
|
||||||
// a one-element array; JSON_DISABLE_TUPLE_REFERENCE_CONVERSION removes
|
|
||||||
// this conversion (see unit-disable-tuple-reference-conversion.cpp)
|
|
||||||
const json j = true;
|
|
||||||
CHECK(std::is_constructible<json, std::tuple<const json&>>::value);
|
|
||||||
#ifndef SKIP_TESTS_FOR_JSON_REFERENCE_TUPLES
|
|
||||||
CHECK(json(std::forward_as_tuple(j)) == json::array({true}));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SECTION("PR #2181 - regression bug with lvalue")
|
SECTION("PR #2181 - regression bug with lvalue")
|
||||||
{
|
{
|
||||||
// see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
|
// see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
|
||||||
|
|||||||
Reference in New Issue
Block a user