Compare commits

..

1 Commits

Author SHA1 Message Date
Niels Lohmann 282f84cc8e 🤜 Doctest 2.5.3
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-08 11:04:03 +02:00
68 changed files with 7246 additions and 5673 deletions
-12
View File
@@ -4,8 +4,6 @@ updates:
directory: / directory: /
schedule: schedule:
interval: daily interval: daily
cooldown:
default-days: 7
groups: groups:
codeql-action: codeql-action:
patterns: patterns:
@@ -15,33 +13,23 @@ updates:
directory: /docs/mkdocs directory: /docs/mkdocs
schedule: schedule:
interval: daily interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip - package-ecosystem: pip
directory: /tools/astyle directory: /tools/astyle
schedule: schedule:
interval: daily interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip - package-ecosystem: pip
directory: /tools/generate_natvis directory: /tools/generate_natvis
schedule: schedule:
interval: daily interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip - package-ecosystem: pip
directory: /tools/serve_header directory: /tools/serve_header
schedule: schedule:
interval: daily interval: daily
cooldown:
default-days: 7
- package-ecosystem: pip - package-ecosystem: pip
directory: /cmake/requirements directory: /cmake/requirements
schedule: schedule:
interval: daily interval: daily
cooldown:
default-days: 7
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
# SEMGREP_APP_TOKEN is still passed through so registry auth works if a # SEMGREP_APP_TOKEN is still passed through so registry auth works if a
# token is ever added. # token is ever added.
- name: Install Semgrep - name: Install Semgrep
run: python3 -m pip install --user semgrep==1.168.0 run: python3 -m pip install --user semgrep
# `semgrep scan --sarif` always exits 0 even with findings; continue-on-error # `semgrep scan --sarif` always exits 0 even with findings; continue-on-error
# is a safety net so the SARIF upload still runs if the scan itself errors. # is a safety net so the SARIF upload still runs if the scan itself errors.
+1 -12
View File
@@ -234,22 +234,11 @@ jobs:
ci_cuda_example: ci_cuda_example:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: container: ghcr.io/nlohmann/json-ci:v2.4.0
fail-fast: false
matrix:
# 11.8.0: newest pre-C++20 CUDA release, exercises the C++17 fallback
# path (tests/cuda_example/CMakeLists.txt picks the standard per nvcc
# version); 12.1.1: permanent regression guard for #3907 (nvcc 12.0/12.1
# choke on enable_borrowed_range at C++20, fixed in 12.2); 12.6.3: recent
# CUDA/C++20 coverage.
cuda: ['11.8.0', '12.1.1', '12.6.3']
container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu22.04
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with: with:
persist-credentials: false persist-credentials: false
- name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
- name: Run CMake - name: Run CMake
run: cmake -S . -B build -DJSON_CI=On run: cmake -S . -B build -DJSON_CI=On
- name: Build - name: Build
+2 -4
View File
@@ -90,13 +90,11 @@ jobs:
- name: Get latest CMake and ninja - name: Get latest CMake and ninja
uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4 uses: lukka/get-cmake@f5b8fbb4d77cec1acc5a5f9f0df4beffaf5d98d9 # v4.3.4
- name: Set extra CXX_FLAGS for latest std_version - name: Set extra CXX_FLAGS for latest std_version
# /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which
# specializes std::tuple (newly diagnosed by the VS2026 v145 toolset)
run: | run: |
if [ "${{ matrix.std_version }}" = "latest" ]; then if [ "${{ matrix.std_version }}" = "latest" ]; then
echo "flags=/permissive- /std:c++latest /utf-8 /W4 /WX /wd5285" >> $GITHUB_ENV echo "flags=/permissive- /std:c++latest /utf-8 /W4 /WX" >> $GITHUB_ENV
else else
echo "flags=/W4 /WX /wd5285" >> $GITHUB_ENV echo "flags=/W4 /WX" >> $GITHUB_ENV
fi fi
shell: bash shell: bash
- name: Run CMake (Release) - name: Run CMake (Release)
+2 -6
View File
@@ -669,6 +669,7 @@ add_custom_target(ci_test_compiler_default
add_custom_target(ci_cuda_example add_custom_target(ci_cuda_example
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_CUDA_HOST_COMPILER=g++-8
-S${PROJECT_SOURCE_DIR}/tests/cuda_example -B${PROJECT_BINARY_DIR}/build_cuda_example -S${PROJECT_SOURCE_DIR}/tests/cuda_example -B${PROJECT_BINARY_DIR}/build_cuda_example
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_cuda_example COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_cuda_example
) )
@@ -719,11 +720,6 @@ add_custom_target(ci_icpx
# to zero and does not honor NaN ordering; -Kieee restores strict IEEE 754 behavior # to zero and does not honor NaN ordering; -Kieee restores strict IEEE 754 behavior
# (needed for the dtoa/grisu and NaN-comparison code paths). # (needed for the dtoa/grisu and NaN-comparison code paths).
# #
# -tp=px pins the target processor to the generic x86-64 baseline (SSE2-only) to avoid
# a nvc++ 25.5 / LLVM issue: when nvc++ auto-detects -tp from the runner's CPU (e.g. -tp znver4),
# certain attribute combinations trigger an llc instruction-selection crash on std::ldexp<unsigned>.
# Pinning to px removes this variability and is robust to future llc/nvc++ updates.
#
# The following tests are excluded as they trigger known nvc++ 25.5 defects (not # The following tests are excluded as they trigger known nvc++ 25.5 defects (not
# library bugs); see https://github.com/nlohmann/json for tracking. Only the # library bugs); see https://github.com/nlohmann/json for tracking. Only the
# affected language-standard variants are excluded so coverage is otherwise kept: # affected language-standard variants are excluded so coverage is otherwise kept:
@@ -737,7 +733,7 @@ add_custom_target(ci_nvhpc
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -GNinja
-DCMAKE_C_COMPILER=nvc -DCMAKE_CXX_COMPILER=nvc++ -DCMAKE_C_COMPILER=nvc -DCMAKE_CXX_COMPILER=nvc++
-DCMAKE_CXX_FLAGS="-Kieee;-tp=px" -DCMAKE_CXX_FLAGS=-Kieee
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_BuildTests=ON -DJSON_FastTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_nvhpc -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_nvhpc
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_nvhpc COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_nvhpc
+3 -5
View File
@@ -5,11 +5,8 @@
# -Wno-extra-semi-stmt The library uses assert which triggers this warning. # -Wno-extra-semi-stmt The library uses assert which triggers this warning.
# -Wno-padded We do not care about padding warnings. # -Wno-padded We do not care about padding warnings.
# -Wno-covered-switch-default All switches list all cases and a default case. # -Wno-covered-switch-default All switches list all cases and a default case.
# -Wno-unsafe-buffer-usage Pervasive: the library's own low-level numeric/buffer code # -Wno-unsafe-buffer-usage Otherwise library code (strlen) would not compile.
# (to_chars, serializer, lexer, binary reader/writer, input # -Wno-missing-noreturn We found no way to silence this warning otherwise, see PR #4871
# adapters, json_pointer) plus vendored Doctest itself (~208
# distinct sites measured 2026-07-08 on clang trunk) all use
# raw pointer arithmetic / libc string calls by necessity.
set(CLANG_CXXFLAGS set(CLANG_CXXFLAGS
-Werror -Werror
@@ -21,4 +18,5 @@ set(CLANG_CXXFLAGS
-Wno-padded -Wno-padded
-Wno-covered-switch-default -Wno-covered-switch-default
-Wno-unsafe-buffer-usage -Wno-unsafe-buffer-usage
-Wno-missing-noreturn
) )
-2
View File
@@ -4,7 +4,6 @@
# -Wno-aggregate-return The library uses aggregate returns. # -Wno-aggregate-return The library uses aggregate returns.
# -Wno-long-long The library uses the long long type to interface with system functions. # -Wno-long-long The library uses the long long type to interface with system functions.
# -Wno-namespaces The library uses namespaces. # -Wno-namespaces The library uses namespaces.
# -Wno-nrvo Doctest triggers this warning.
# -Wno-padded We do not care about padding warnings. # -Wno-padded We do not care about padding warnings.
# -Wno-system-headers We do not care about warnings in system headers. # -Wno-system-headers We do not care about warnings in system headers.
# -Wno-templates The library uses templates. # -Wno-templates The library uses templates.
@@ -232,7 +231,6 @@ set(GCC_CXXFLAGS
-Wnonnull -Wnonnull
-Wnonnull-compare -Wnonnull-compare
-Wnormalized=nfkc -Wnormalized=nfkc
-Wno-nrvo
-Wnull-dereference -Wnull-dereference
-Wodr -Wodr
-Wold-style-cast -Wold-style-cast
+1 -1
View File
@@ -4,7 +4,7 @@
"archive": "JSON_for_Modern_C++.tgz", "archive": "JSON_for_Modern_C++.tgz",
"author": { "author": {
"name": "Niels Lohmann", "name": "Niels Lohmann",
"link": "https://nlohmann.me" "link": "https://twitter.com/nlohmann"
}, },
"aliases": ["nlohmann/json"] "aliases": ["nlohmann/json"]
} }
+1 -1
View File
@@ -109,7 +109,7 @@ A UTF-8 byte order mark is silently ignored.
- Added in version 3.0.0. - Added in version 3.0.0.
- Ignoring comments via `ignore_comments` added in version 3.9.0. - Ignoring comments via `ignore_comments` added in version 3.9.0.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0. - Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.13.0. - Added `ignore_trailing_commas` in version 3.12.x.
!!! warning "Deprecation" !!! warning "Deprecation"
+1 -12
View File
@@ -82,13 +82,7 @@ basic_json(basic_json&& other) noexcept;
4. This is a constructor for existing `basic_json` types. It does not hijack copy/move constructors, since the parameter 4. This is a constructor for existing `basic_json` types. It does not hijack copy/move constructors, since the parameter
has different template arguments than the current ones. has different template arguments than the current ones.
The constructor tries to convert the internal `m_value` of the parameter. Each member value (object, array, string, The constructor tries to convert the internal `m_value` of the parameter.
etc.) is serialized via the corresponding `to_json()` overload. For objects and strings, the conversion requires
that the *target* `basic_json` type's `object_t::key_type` (or `string_t`) be directly constructible from the
*source* type's corresponding member type via `is_constructible`. If this requirement is not met, the conversion
does not fail to compile; instead, it silently falls back to the array-conversion path, which represents objects
as arrays of `[key, value]` pairs and strings as arrays of character codes. This is a known limitation tracked in
[issue #3425](https://github.com/nlohmann/json/issues/3425).
5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is 5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is
`#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init` `#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init`
@@ -153,11 +147,6 @@ basic_json(basic_json&& other) noexcept;
- `BasicJsonType` is a `basic_json` type. - `BasicJsonType` is a `basic_json` type.
- `BasicJsonType` has different template arguments than `basic_json_t`. - `BasicJsonType` has different template arguments than `basic_json_t`.
**Note:** For cross-`basic_json` conversions to produce correct results, the target `basic_json`'s
`object_t::key_type` and `string_t` must be directly constructible from the source `basic_json`'s
corresponding types. See the description of overload (4) above for details on what happens when
this requirement is not met.
`U`: `U`:
: `uncvref_t<CompatibleType>` : `uncvref_t<CompatibleType>`
+1 -1
View File
@@ -92,4 +92,4 @@ std::string format_as(const BasicJsonType& j)
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
-7
View File
@@ -114,13 +114,6 @@ overload (3).
See [Number conversion](../../features/types/number_handling.md#number-conversion) See [Number conversion](../../features/types/number_handling.md#number-conversion)
for more information. for more information.
!!! note "`std::optional` conversions"
Prior to version 3.13.0, `#!cpp get<std::optional<T>>()` (and other conversions to `std::optional<T>`) failed to
compile in every configuration, due to an internal implementation bug that made the `from_json` overload for
`std::optional` unreachable regardless of the [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md)
setting. This has been fixed.
## Examples ## Examples
??? example ??? example
+1 -11
View File
@@ -63,8 +63,7 @@ behavior:
object will agree on the name-value mappings. object will agree on the name-value mappings.
- When the names within an object are not unique, it is unspecified which one of the values for a given key will be - When the names within an object are not unique, it is unspecified which one of the values for a given key will be
chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or
`#!json {"key": 2}`. To reject duplicate keys instead of silently resolving them one way or another, see `#!json {"key": 2}`.
[this parsing recipe](../../features/parsing/parser_callbacks.md#recipe-rejecting-duplicate-object-keys).
- Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see - Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see
[`dump`](dump.md)) in this order. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored [`dump`](dump.md)) in this order. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored
and serialized as `#!json {"a": 2, "b": 1}`. and serialized as `#!json {"a": 2, "b": 1}`.
@@ -94,15 +93,6 @@ alphabetical order as `std::map` with `std::less` is used by default. Please not
[RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON [RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON
objects. objects.
#### Cross-`basic_json` conversion requirements
When converting an object from one `basic_json` specialization to another via the
[converting constructor](basic_json.md#overload-4), the target `object_t`'s `key_type` must be
directly constructible from the source `basic_json`'s `string_t` type (or more generally, from the
source object's key type). If this requirement is not met, the conversion does not fail; instead,
the object is silently converted as an array of key-value pairs, which is incorrect. See
[issue #3425](https://github.com/nlohmann/json/issues/3425) for details and an example.
## Examples ## Examples
??? example ??? example
@@ -251,6 +251,5 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0. 1. Added in version 1.0.0.
2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3) 2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3)
in version 3.11.0. in version 3.11.0.
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as 3. Added in version 3.11.0.
already supported by [`at`](at.md), [`value`](value.md), [`find`](find.md), and other lookup functions.
4. Added in version 2.0.0. 4. Added in version 2.0.0.
+12 -11
View File
@@ -19,8 +19,10 @@ class basic_json {
}; };
``` ```
1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20). 1. Compares two JSON values for inequality according to the following rules:
- This means the comparison is simply the logical negation of `operator==`, including for special values like `NaN` and `discarded`. - The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either operand is `NaN` and
the other operand is either `NaN` or any other number.
- Otherwise, returns the result of `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON 2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON
value and comparing both JSON values according to 1. value and comparing both JSON values according to 1.
@@ -52,12 +54,13 @@ Linear.
## Notes ## Notes
!!! note "Comparing `NaN` and `discarded`" !!! note "Comparing `NaN`"
Since `operator!=` is defined as `!(a == b)`, the behavior for special values follows that of `operator==`: `NaN` values are unordered within the domain of numbers.
The following comparisons all yield `#!cpp false`:
- For `NaN` values: `NaN == NaN` yields `#!cpp false`, so `NaN != NaN` yields `#!cpp true`. 1. Comparing a `NaN` with itself.
- For `discarded` values: `discarded == x` yields `#!cpp false` for any `x`, so `discarded != x` yields `#!cpp true`. 2. Comparing a `NaN` with another `NaN`.
3. Comparing a `NaN` and any other number.
## Examples ## Examples
@@ -91,7 +94,5 @@ Linear.
## Version history ## Version history
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove 1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`. 2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
+1 -1
View File
@@ -235,7 +235,7 @@ Invalid Unicode escapes and unpaired surrogates in the input are reported as
- Overload for contiguous containers (1) added in version 2.0.3. - Overload for contiguous containers (1) added in version 2.0.3.
- Ignoring comments via `ignore_comments` added in version 3.9.0. - Ignoring comments via `ignore_comments` added in version 3.9.0.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0. - Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.13.0. - Added `ignore_trailing_commas` in version 3.12.x.
!!! warning "Deprecation" !!! warning "Deprecation"
+1 -1
View File
@@ -74,4 +74,4 @@ is thrown. In any case, the original value is not changed: the patch is applied
- Added in version 2.0.0. - Added in version 2.0.0.
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's - Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
target location has a non-object/non-array parent in version 3.13.0. target location has a non-object/non-array parent in version 3.12.x.
@@ -71,4 +71,4 @@ function throws an exception.
- Added in version 3.11.0. - Added in version 3.11.0.
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's - Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
target location has a non-object/non-array parent in version 3.13.0. target location has a non-object/non-array parent in version 3.12.x.
+1 -1
View File
@@ -126,7 +126,7 @@ A UTF-8 byte order mark is silently ignored.
- Added in version 3.2.0. - Added in version 3.2.0.
- Ignoring comments via `ignore_comments` added in version 3.9.0. - Ignoring comments via `ignore_comments` added in version 3.9.0.
- Added `ignore_trailing_commas` in version 3.13.0. - Added `ignore_trailing_commas` in version 3.12.x.
!!! warning "Deprecation" !!! warning "Deprecation"
@@ -54,4 +54,4 @@ provides `<format>`, controlled by the [`JSON_HAS_STD_FORMAT`](../macros/json_ha
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
@@ -45,15 +45,6 @@ This implementation is interoperable as it does compare strings code unit by cod
String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type
`string_t*` must be dereferenced. `string_t*` must be dereferenced.
#### Cross-`basic_json` conversion requirements
When converting a string value from one `basic_json` specialization to another via the
[converting constructor](basic_json.md#overload-4), the target `string_t` must be directly
constructible from the source `basic_json`'s `string_t` type. If this requirement is not met, the
conversion does not fail; instead, the string is silently converted as an array of character codes,
which is incorrect. See [issue #3425](https://github.com/nlohmann/json/issues/3425) for details
and an example.
## Examples ## Examples
??? example ??? example
@@ -21,12 +21,6 @@ a string representation of the type ([`value_t`](value_t.md)):
| array | `"array"` | | array | `"array"` |
| binary | `"binary"` | | binary | `"binary"` |
| discarded | `"discarded"` | | discarded | `"discarded"` |
| invalid (corrupted value) | `"invalid"` |
!!! note "The \"invalid\" type"
The `"invalid"` return value indicates a corrupted JSON value — this can occur if an enum value falls outside the
range of valid `value_t` values. This is useful for diagnosing data corruption or internal errors.
## Exception safety ## Exception safety
@@ -58,4 +52,3 @@ Constant.
- Part of the public API version since 2.1.0. - Part of the public API version since 2.1.0.
- Changed return value to `const char*` and added `noexcept` in version 3.0.0. - Changed return value to `const char*` and added `noexcept` in version 3.0.0.
- Added support for binary type in version 3.8.0. - Added support for binary type in version 3.8.0.
- Added `"invalid"` return value for corrupted JSON values in version 3.13.0.
+1 -3
View File
@@ -184,6 +184,4 @@ changes to any JSON value.
1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0. 1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0.
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2. 2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving 3. Added in version 2.0.2. Extended to work with arrays in version 3.12.x.
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
`default_value`, as documented).
+1 -1
View File
@@ -36,4 +36,4 @@ Constant.
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
@@ -32,4 +32,4 @@ Linear in the number of reference tokens in the `json_pointer`.
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
@@ -35,4 +35,4 @@ Linear in the number of reference tokens in the `json_pointer`.
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
@@ -92,4 +92,4 @@ The default value is `0` (disabled — existing behavior is preserved).
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
@@ -44,4 +44,4 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu
- Added in version 3.10.5. - Added in version 3.10.5.
- Added `JSON_HAS_CPP_23` in version 3.12.0. - Added `JSON_HAS_CPP_23` in version 3.12.0.
- Added `JSON_HAS_CPP_26` in version 3.13.0. - Added `JSON_HAS_CPP_26` in version 3.12.x.
@@ -19,20 +19,6 @@ The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_
`#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include(<filesystem>)`, or `#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include(<filesystem>)`, or
`#!cpp __has_include(<experimental/filesystem>)`. `#!cpp __has_include(<experimental/filesystem>)`.
!!! info "Known compiler/stdlib exclusions"
Even when the feature-test macro indicates filesystem support is available, the library disables it on the following broken toolchains:
- **MinGW + GCC 8** — disabled entirely (broken `std::filesystem` implementation; [MinGW-w64 bug 737](https://sourceforge.net/p/mingw-w64/bugs/737/))
- **GCC (non-Clang) < 8** — disabled (no filesystem support)
- **Clang < 7** — disabled (no filesystem support)
- **MSVC < 19.14** — disabled (no filesystem support)
- **iOS < 13** — disabled (no filesystem support)
- **macOS < Catalina (10.15)** — disabled (no filesystem support)
If `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` is `0` despite `__cpp_lib_filesystem` being defined, one
of the exclusions above likely applies to your toolchain.
## Notes ## Notes
- Note that older compilers or older versions of libstdc++ also require the library `stdc++fs` to be linked to for - Note that older compilers or older versions of libstdc++ also require the library `stdc++fs` to be linked to for
@@ -13,20 +13,6 @@ The default value is detected based on the preprocessor macro `#!cpp __cpp_lib_r
When the macro is not defined, the library will define it to its default value. When the macro is not defined, the library will define it to its default value.
!!! info "Known compiler/stdlib exclusions"
Even when the feature-test macro `__cpp_lib_ranges` indicates ranges support is available, the library disables it on
the following incomplete or broken toolchains:
- **GCC 11.1.0** — disabled (the shipped `<ranges>` header has a syntax error; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libstdc++ < 11** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **Clang < 16 with libstdc++** — disabled (incomplete ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **libc++ < 160000** — disabled (incomplete C++20 ranges support; [issue #4440](https://github.com/nlohmann/json/issues/4440))
- **nvcc (CUDA) 12.0.x and 12.1.x** — disabled (the `enable_borrowed_range` variable-template syntax triggers a parse error
under these two toolkit versions; fixed in CUDA 12.2; [issue #3907](https://github.com/nlohmann/json/issues/3907))
If `JSON_HAS_RANGES` is `0` despite `__cpp_lib_ranges` being defined, one of the exclusions above likely applies to your toolchain.
## Examples ## Examples
??? example ??? example
@@ -38,4 +38,4 @@ When the macro is not defined, the library will define it to its default value.
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.12.x.
@@ -75,4 +75,4 @@ For further information please refer to the corresponding macros without `WITH_N
## Version history ## Version history
1. Added in version 3.13.0. 1. Added in version 3.12.x.
@@ -102,4 +102,4 @@ inline void from_json(const BasicJsonType& j, type& e);
## Version history ## Version history
Added in version 3.13.0. Added in version 3.12.x.
@@ -64,4 +64,4 @@ Linear.
- Added in version 1.0.0. - Added in version 1.0.0.
- Moved to namespace `nlohmann::literals::json_literals` in 3.11.0. - Moved to namespace `nlohmann::literals::json_literals` in 3.11.0.
- Added `char8_t*` overload in 3.13.0. - Added `char8_t*` overload in 3.12.x.
@@ -63,4 +63,4 @@ Linear.
- Added in version 2.0.0. - Added in version 2.0.0.
- Moved to namespace `nlohmann::literals::json_literals` in 3.11.0. - Moved to namespace `nlohmann::literals::json_literals` in 3.11.0.
- Added `char8_t*` overload in 3.13.0. - Added `char8_t*` overload in 3.12.x.
@@ -10,10 +10,6 @@ violations will result in a failed build.
Any compiler with complete C++11 support can compile the library without warnings. Any compiler with complete C++11 support can compile the library without warnings.
Note: C++20 modules support may hit compiler-specific issues not covered by the general compiler matrix below. See [Modules](../features/modules.md#known-issues) for known issues and workarounds.
Note: Some modern features (like C++20 ranges or filesystem support) may be disabled on specific broken or incomplete toolchains even when standard feature-test macros indicate support. See [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) and [`JSON_HAS_FILESYSTEM`](../api/macros/json_has_filesystem.md) for details on known exclusions.
- [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms, - [x] The library is compiled with 50+ different C++ compilers with different operating systems and platforms,
including the oldest versions known to compile the library. including the oldest versions known to compile the library.
@@ -66,9 +62,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub | | Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub | | CUDA 11.0.221 (nvcc) | x86_64 | Ubuntu 20.04 LTS | GitHub |
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
| Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Emscripten 4.0.6 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 4.8.5 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
| GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 4.9.3 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
@@ -1,61 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
#include <stdexcept>
#include <string>
#include <unordered_set>
#include <vector>
using json = nlohmann::json;
json parse_strict(const std::string& input)
{
// one key set per nesting depth, reused across sibling objects
std::vector<std::unordered_set<std::string>> keys;
auto reject_duplicate_keys = [&](int depth, json::parse_event_t event, json & parsed)
{
if (event == json::parse_event_t::object_start)
{
// keys of this object are reported at depth+1 (see the event table above)
const auto child_depth = static_cast<std::size_t>(depth) + 1;
if (keys.size() <= child_depth)
{
keys.resize(child_depth + 1);
}
keys[child_depth].clear();
return true;
}
if (event == json::parse_event_t::key)
{
auto& seen = keys[static_cast<std::size_t>(depth)];
const auto& key = parsed.get_ref<const std::string&>();
if (!seen.insert(key).second)
{
throw std::runtime_error("duplicate JSON object key: " + key);
}
return true;
}
return true;
};
return json::parse(input, reject_duplicate_keys);
}
int main()
{
// parsing succeeds when all keys are unique
json j = parse_strict(R"({"one": 1, "two": 2})");
std::cout << j << '\n';
// parsing throws when a key is repeated
try
{
parse_strict(R"({"one": 1, "one": 2})");
}
catch (const std::exception& e)
{
std::cout << e.what() << '\n';
}
}
@@ -1,2 +0,0 @@
{"one":1,"two":2}
duplicate JSON object key: one
@@ -66,15 +66,7 @@ see "binary" cells in the table above.
!!! info "NaN/infinity handling" !!! info "NaN/infinity handling"
`NaN`, `Infinity`, and `-Infinity` are serialized as a CBOR half-precision float (type 0xF9, 3 bytes total): If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
`NaN` as `0xF9 0x7E 0x00`, `Infinity` as `0xF9 0x7C 0x00`, and `-Infinity` as `0xF9 0xFC 0x00`. This behavior
differs from the normal JSON serialization which serializes NaN or Infinity to `null`.
!!! note
Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
9 bytes total), because the check used to select a smaller encoding compared magnitudes with NaN, which is
always `false` and caused the intended half-precision path to be skipped.
!!! info "Unused CBOR types" !!! info "Unused CBOR types"
@@ -168,13 +160,6 @@ The library maps CBOR types to JSON value types as follows:
- simple values (0xE0..0xF3, 0xF8) - simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7) - undefined (0xF7)
!!! warning "Negative integer overflow"
CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the
result to fit into `number_integer_t` (`std::int64_t` by default), parsing fails with a
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) exception rather than overflowing
silently.
!!! warning "Object keys" !!! warning "Object keys"
CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected. CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected.
@@ -67,15 +67,8 @@ specification:
!!! info "NaN/infinity handling" !!! info "NaN/infinity handling"
`NaN`, `Infinity`, and `-Infinity` are serialized as a MessagePack float 32 (type 0xCA, 5 bytes total), If NaN or Infinity are stored inside a JSON number, they are serialized properly in contrast to the
regardless of magnitude, in contrast to the [dump](../../api/basic_json/dump.md) function which serializes NaN [dump](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
or Infinity to `null`.
!!! note
Prior to version 3.13.0, NaN and Infinity were instead serialized as a MessagePack float 64 (type 0xCB, 9 bytes
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
always `false` and caused the float 32 path to be skipped.
??? example ??? example
-18
View File
@@ -66,24 +66,6 @@ which forces the explicit `get` form and can catch unintended conversions at com
floating-point value as an integer truncates it, and narrowing conversions may overflow. See floating-point value as an integer truncates it, and narrowing conversions may overflow. See
[number conversion](types/number_handling.md#number-conversion) for details and how to guard against it. [number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
!!! warning "std::optional direct construction from JSON null throws"
Constructing or assigning `std::optional<T>` directly from a JSON value does not correctly produce
`std::nullopt` for a JSON `null`:
```cpp
json j_null;
std::optional<std::string> opt = j_null; // ❌ throws type_error 302
```
This is due to C++ language rules: `std::optional<T>` has its own converting constructor that is chosen over
`basic_json::operator T()` when both are viable. Use `get<std::optional<T>>()` or `get_to()` instead:
```cpp
auto opt = j_null.get<std::optional<std::string>>(); // ✅ std::nullopt
j_null.get_to(opt); // ✅ std::nullopt
```
## Putting values in ## Putting values in
The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON. The reverse direction works the same way: assigning or constructing a `json` from a C++ value converts it to JSON.
-19
View File
@@ -27,7 +27,6 @@ json data = json::parse(f);
It should be noted that as modules do not export macros, the `nlohmann.json` module will not export any macros. It should be noted that as modules do not export macros, the `nlohmann.json` module will not export any macros.
## Exported symbols ## Exported symbols
Only the following symbols are exported from `nlohmann.json`: Only the following symbols are exported from `nlohmann.json`:
- `nlohmann::adl_serializer` - `nlohmann::adl_serializer`
@@ -39,21 +38,3 @@ Only the following symbols are exported from `nlohmann.json`:
- `nlohmann::to_string` - `nlohmann::to_string`
- `nlohmann::literals::json_literals::operator""_json` - `nlohmann::literals::json_literals::operator""_json`
- `nlohmann::literals::json_literals::operator""_json_pointer` - `nlohmann::literals::json_literals::operator""_json_pointer`
Additionally, the following `nlohmann::detail` symbols are exported, solely to work around an MSVC compilation issue
([#3970](https://github.com/nlohmann/json/issues/3970)). They are implementation details, not part of the public API,
and should not be used directly:
- `nlohmann::detail::json_sax_dom_callback_parser`
- `nlohmann::detail::unknown_size`
## Known issues
C++20 modules support is exercised in CI against current GCC and Clang on Ubuntu, and the default MSVC toolset on Windows Server 2022 — there is no documented minimum compiler version, unlike feature-test-macro-gated features such as [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md).
!!! info "Known compiler issues"
- **GCC** may emit "redefinition" errors when `#include <nlohmann/json.hpp>` appears in a module preamble together with other imports. This is an upstream GCC bug, not yet resolved as of GCC 16. Workarounds: include `nlohmann/json.hpp` before other `#include`s, use `import nlohmann.json;` instead, or upgrade GCC. ([issue #5103](https://github.com/nlohmann/json/issues/5103))
- **MSVC** could fail with `C2039: 'json_sax_dom_callback_parser' is not a member of ... detail`; fixed by exporting the required internal symbols from `json.cppm` (see [Exported symbols](#exported-symbols) above). ([issue #3970](https://github.com/nlohmann/json/issues/3970))
If you hit a different module-related build failure, search [existing issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+modules) before filing a new one.
@@ -81,34 +81,3 @@ was called:
```json ```json
--8<-- "examples/parse__string__parser_callback_t.output" --8<-- "examples/parse__string__parser_callback_t.output"
``` ```
## Recipe: rejecting duplicate object keys
The JSON specification leaves the handling of objects with repeated keys up to the implementation. As described in
[`object_t`](../../api/basic_json/object_t.md#behavior), it is unspecified which value for a repeated key ends up in
the resulting `#!c json` value -- once parsing has produced that value, the duplicate is already gone, because object
storage maps each key to a single value. If duplicate keys should instead be treated as an error, a parser callback
can detect them while the object is still being read, before that ambiguity ever applies.
??? example
```cpp
--8<-- "examples/reject_duplicate_keys.cpp"
```
Output:
```json
--8<-- "examples/reject_duplicate_keys.output"
```
This approach has two limitations:
- The depth-indexed bookkeeping must account for the fact that `object_start` reports the depth of the *parent* of
the object, while the `key` events inside that object are reported one depth deeper (see the event table above);
it is easy to get this off by one for nested objects.
- The thrown exception cannot carry a `parse_error`-style byte offset, because position tracking only exists inside
the parser and lexer, not at the callback layer.
For strict validation with precise error positions, implementing a [SAX interface](sax_interface.md) instead gives
access to the parser's position information directly.
+1 -1
View File
@@ -131,7 +131,7 @@ std::map<
The choice of `object_t` influences the behavior of the JSON class. With the default type, objects have the following behavior: The choice of `object_t` influences the behavior of the JSON class. With the default type, objects have the following behavior:
- When all names are unique, objects will be interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. - When all names are unique, objects will be interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings.
- When the names within an object are not unique, it is unspecified which one of the values for a given key will be chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or `#!json {"key": 2}`. To reject duplicate keys instead of silently resolving them one way or another, see [this parsing recipe](../parsing/parser_callbacks.md#recipe-rejecting-duplicate-object-keys). - When the names within an object are not unique, it is unspecified which one of the values for a given key will be chosen. For instance, `#!json {"key": 2, "key": 1}` could be equal to either `#!json {"key": 1}` or `#!json {"key": 2}`.
- Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see `dump`) in this order. For instance, both `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored and serialized as `#!json {"a": 2, "b": 1}`. - Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see `dump`) in this order. For instance, both `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be stored and serialized as `#!json {"a": 2, "b": 1}`.
- When comparing objects, the order of the name/value pairs is irrelevant. This makes objects interoperable in the sense that they will not be affected by these differences. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be treated as equal. - When comparing objects, the order of the name/value pairs is irrelevant. This makes objects interoperable in the sense that they will not be affected by these differences. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be treated as equal.
@@ -63,10 +63,6 @@ In the default [`json`](../../api/json.md) type, numbers are stored as `#!c std:
number without loss of precision. If this is impossible (e.g., if the number is too large), the number is stored as number without loss of precision. If this is impossible (e.g., if the number is too large), the number is stored as
`#!c double`. `#!c double`.
Positive integers are stored as `#!c std::uint64_t`, while negative integers are stored as `#!c std::int64_t`. This
distinction is determined at parse time: if the JSON number has a leading minus sign, it uses signed integer storage;
otherwise, it uses unsigned integer storage.
!!! info "Notes" !!! info "Notes"
- Numbers with a decimal digit or scientific notation are always stored as `#!c double`. - Numbers with a decimal digit or scientific notation are always stored as `#!c double`.
+1 -4
View File
@@ -326,9 +326,6 @@ An unexpected byte was read in a [binary format](../features/binary_formats/inde
``` ```
[json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1 [json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1
``` ```
```
[json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: negative integer overflow
```
### json.exception.parse_error.113 ### json.exception.parse_error.113
@@ -896,7 +893,7 @@ A JSON Patch `add` operation cannot be applied because the target location's par
!!! note !!! note
This exception was added in version 3.13.0. Before that, this situation hit an internal assertion (aborting the program in debug builds) or was silently ignored when assertions were disabled. This exception was added in version 3.12.x. Before that, this situation hit an internal assertion (aborting the program in debug builds) or was silently ignored when assertions were disabled.
## Further exceptions ## Further exceptions
+1 -1
View File
@@ -178,7 +178,7 @@ See [this section](../features/types/number_handling.md#number-serialization) on
- Can I use `std::format("{}", j)` on a JSON value? - Can I use `std::format("{}", j)` on a JSON value?
- Can I use `fmt::format("{}", j)` or `fmt::print("{}", j)` (the [{fmt}](https://github.com/fmtlib/fmt) library) on a JSON value? - Can I use `fmt::format("{}", j)` or `fmt::print("{}", j)` (the [{fmt}](https://github.com/fmtlib/fmt) library) on a JSON value?
`std::format` works out of the box since version 3.13.0, as long as the standard library provides `std::format` works out of the box since version 3.12.x, as long as the standard library provides
`<format>` (see [`JSON_HAS_STD_FORMAT`](../api/macros/json_has_std_format.md)); see `<format>` (see [`JSON_HAS_STD_FORMAT`](../api/macros/json_has_std_format.md)); see
[`std::formatter<basic_json>`](../api/basic_json/std_formatter.md) for details, including the `#!cpp "{:#}"` [`std::formatter<basic_json>`](../api/basic_json/std_formatter.md) for details, including the `#!cpp "{:#}"`
pretty-print spec, indent widths (`#!cpp "{:2}"`), and custom indent characters (`#!cpp "{:.>#}"`). pretty-print spec, indent widths (`#!cpp "{:2}"`), and custom indent characters (`#!cpp "{:.>#}"`).
-4
View File
@@ -1,4 +0,0 @@
User-agent: *
Allow: /
Sitemap: https://json.nlohmann.me/sitemap.xml
-25
View File
@@ -1,25 +0,0 @@
"""Copy each documentation page's Markdown source into the built site."""
# Creates a `<path>.md` sibling of each HTML output (for example,
# `features/comments/` becomes `features/comments.md`) so agents and tools can
# fetch the raw Markdown directly instead of parsing rendered HTML.
import os
import shutil
_pages = []
def on_files(files, config):
global _pages
_pages = [f for f in files if f.is_documentation_page()]
return files
def on_post_build(config):
site_dir = config["site_dir"]
for file in _pages:
url = file.url.rstrip("/")
target = os.path.join(site_dir, (url or "index") + ".md")
os.makedirs(os.path.dirname(target), exist_ok=True)
shutil.copyfile(file.abs_src_path, target)
-30
View File
@@ -367,9 +367,6 @@ markdown_extensions:
auto_append: auto_append:
- ../includes/glossary.md - ../includes/glossary.md
hooks:
- hooks/copy_markdown_source.py
plugins: plugins:
- search: - search:
separator: '[\s\-\.]' separator: '[\s\-\.]'
@@ -392,33 +389,6 @@ plugins:
- https://nlohmann.github.io/json/* - https://nlohmann.github.io/json/*
- mailto:* - mailto:*
- privacy - privacy
- llmstxt:
markdown_description: >
JSON for Modern C++ is a C++11 header-only library implementing a JSON
value type with an STL-like API, JSON Pointer/Patch, CBOR/MessagePack/
BSON/UBJSON/BJData binary format support, and a SAX-style parser interface.
sections:
Home:
- index.md
- home/*.md
Features:
- features/*.md
- features/binary_formats/*.md
- features/element_access/*.md
- features/parsing/*.md
- features/types/*.md
Integration:
- integration/*.md
API Documentation:
- api/*.md
- api/basic_json/*.md
- api/adl_serializer/*.md
- api/byte_container_with_subtype/*.md
- api/json_pointer/*.md
- api/json_sax/*.md
- api/macros/*.md
Community:
- community/*.md
extra_css: extra_css:
- css/custom.css - css/custom.css
-1
View File
@@ -7,6 +7,5 @@ mkdocs-material-extensions==1.3.1 # extensions
mkdocs-minify-plugin==0.8.0 # plugin "minify" mkdocs-minify-plugin==0.8.0 # plugin "minify"
mkdocs-redirects==1.2.3 # plugin "redirects" mkdocs-redirects==1.2.3 # plugin "redirects"
mkdocs-htmlproofer-plugin==1.5.0 # plugin "htmlproofer" mkdocs-htmlproofer-plugin==1.5.0 # plugin "htmlproofer"
mkdocs-llmstxt==0.5.0 # plugin "llmstxt"
PyYAML==6.0.3 # linter PyYAML==6.0.3 # linter
@@ -430,7 +430,7 @@ class wide_string_input_adapter
// parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here // parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here
template<class T> template<class T>
JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)
{ {
JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr));
} }
-5
View File
@@ -146,11 +146,6 @@
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000 #elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
// syntax when compiling as CUDA source; fixed in CUDA 12.2 (issue #3907)
#elif defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ == 12 \
&& defined(__CUDACC_VER_MINOR__) && (__CUDACC_VER_MINOR__ == 0 || __CUDACC_VER_MINOR__ == 1)
#define JSON_HAS_RANGES 0
#elif defined(__cpp_lib_ranges) #elif defined(__cpp_lib_ranges)
#define JSON_HAS_RANGES 1 #define JSON_HAS_RANGES 1
#else #else
+9 -29
View File
@@ -465,12 +465,18 @@ class serializer
{ {
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint)); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<std::uint16_t>(codepoint)));
bytes += 6;
} }
else else
{ {
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u))); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))); static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
bytes += 12;
} }
} }
else else
@@ -677,32 +683,6 @@ class serializer
return result; return result;
} }
/*!
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
*
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
* four hex digits) at position @a pos of @a string_buffer via a nibble
* lookup table, avoiding the format-string parsing and locale machinery of
* `snprintf`. Advances @a pos by the number of bytes written (6).
*
* @param[in] pos position in @a string_buffer to write at; there must
* be at least 6 bytes of headroom
* @param[in] codeunit 16-bit value to encode
*/
void write_u_escape(std::size_t& pos, std::uint16_t codeunit) noexcept
{
JSON_ASSERT(string_buffer.size() - pos >= 6);
constexpr const char* nibble_to_hex = "0123456789abcdef";
string_buffer[pos + 0] = '\\';
string_buffer[pos + 1] = 'u';
string_buffer[pos + 2] = nibble_to_hex[(codeunit >> 12u) & 0x0Fu];
string_buffer[pos + 3] = nibble_to_hex[(codeunit >> 8u) & 0x0Fu];
string_buffer[pos + 4] = nibble_to_hex[(codeunit >> 4u) & 0x0Fu];
string_buffer[pos + 5] = nibble_to_hex[codeunit & 0x0Fu];
pos += 6;
}
// templates to avoid warnings about useless casts // templates to avoid warnings about useless casts
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0> template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
bool is_negative_number(NumberType x) bool is_negative_number(NumberType x)
+15
View File
@@ -3776,6 +3776,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return *this == basic_json(rhs); return *this == basic_json(rhs);
} }
/// @brief comparison: not equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
bool operator!=(const_reference rhs) const noexcept
{
if (compares_unordered(rhs, true))
{
return false;
}
return !operator==(rhs);
}
/// @brief comparison: 3-way /// @brief comparison: 3-way
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD* std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
@@ -3881,6 +3892,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
{ {
if (compares_unordered(lhs, rhs, true))
{
return false;
}
return !(lhs == rhs); return !(lhs == rhs);
} }
+25 -35
View File
@@ -2520,11 +2520,6 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000 #elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0 #define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
// syntax when compiling as CUDA source; fixed in CUDA 12.2 (issue #3907)
#elif defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ == 12 \
&& defined(__CUDACC_VER_MINOR__) && (__CUDACC_VER_MINOR__ == 0 || __CUDACC_VER_MINOR__ == 1)
#define JSON_HAS_RANGES 0
#elif defined(__cpp_lib_ranges) #elif defined(__cpp_lib_ranges)
#define JSON_HAS_RANGES 1 #define JSON_HAS_RANGES 1
#else #else
@@ -7267,7 +7262,7 @@ class wide_string_input_adapter
// parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here // parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here
template<class T> template<class T>
JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)
{ {
JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr));
} }
@@ -19967,12 +19962,18 @@ class serializer
{ {
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint)); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<std::uint16_t>(codepoint)));
bytes += 6;
} }
else else
{ {
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u))); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))); static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
bytes += 12;
} }
} }
else else
@@ -20179,32 +20180,6 @@ class serializer
return result; return result;
} }
/*!
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
*
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
* four hex digits) at position @a pos of @a string_buffer via a nibble
* lookup table, avoiding the format-string parsing and locale machinery of
* `snprintf`. Advances @a pos by the number of bytes written (6).
*
* @param[in] pos position in @a string_buffer to write at; there must
* be at least 6 bytes of headroom
* @param[in] codeunit 16-bit value to encode
*/
void write_u_escape(std::size_t& pos, std::uint16_t codeunit) noexcept
{
JSON_ASSERT(string_buffer.size() - pos >= 6);
constexpr const char* nibble_to_hex = "0123456789abcdef";
string_buffer[pos + 0] = '\\';
string_buffer[pos + 1] = 'u';
string_buffer[pos + 2] = nibble_to_hex[(codeunit >> 12u) & 0x0Fu];
string_buffer[pos + 3] = nibble_to_hex[(codeunit >> 8u) & 0x0Fu];
string_buffer[pos + 4] = nibble_to_hex[(codeunit >> 4u) & 0x0Fu];
string_buffer[pos + 5] = nibble_to_hex[codeunit & 0x0Fu];
pos += 6;
}
// templates to avoid warnings about useless casts // templates to avoid warnings about useless casts
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0> template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
bool is_negative_number(NumberType x) bool is_negative_number(NumberType x)
@@ -24627,6 +24602,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return *this == basic_json(rhs); return *this == basic_json(rhs);
} }
/// @brief comparison: not equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
bool operator!=(const_reference rhs) const noexcept
{
if (compares_unordered(rhs, true))
{
return false;
}
return !operator==(rhs);
}
/// @brief comparison: 3-way /// @brief comparison: 3-way
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD* std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
@@ -24732,6 +24718,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
{ {
if (compares_unordered(lhs, rhs, true))
{
return false;
}
return !(lhs == rhs); return !(lhs == rhs);
} }
+1 -5
View File
@@ -68,11 +68,7 @@ target_compile_options(test_main PUBLIC
# Disable warning C4566: character represented by universal-character-name '\uFF01' # Disable warning C4566: character represented by universal-character-name '\uFF01'
# cannot be represented in the current code page (1252) # cannot be represented in the current code page (1252)
# Disable warning C4996: 'nlohmann::basic_json<...>::operator <<': was declared deprecated # Disable warning C4996: 'nlohmann::basic_json<...>::operator <<': was declared deprecated
# Disable warning C4702: unreachable code; wide_string_input_adapter::get_elements() $<$<CXX_COMPILER_ID:MSVC>:/W4;/wd4566;/wd4996;$<$<CONFIG:Release>:/wd4702>>
# is annotated JSON_HEDLEY_NO_RETURN (it always throws), which
# makes MSVC flag the code following its call in binary_reader.hpp
# as unreachable for that instantiation, in both Debug and Release
$<$<CXX_COMPILER_ID:MSVC>:/W4;/wd4566;/wd4996;/wd4702>
# https://github.com/nlohmann/json/issues/1114 # https://github.com/nlohmann/json/issues/1114
$<$<CXX_COMPILER_ID:MSVC>:/bigobj> $<$<BOOL:${MINGW}>:-Wa,-mbig-obj> $<$<CXX_COMPILER_ID:MSVC>:/bigobj> $<$<BOOL:${MINGW}>:-Wa,-mbig-obj>
+1 -12
View File
@@ -3,18 +3,7 @@ project(json_cuda LANGUAGES CUDA)
add_executable(json_cuda json_cuda.cu) add_executable(json_cuda json_cuda.cu)
target_include_directories(json_cuda PRIVATE ../../include) target_include_directories(json_cuda PRIVATE ../../include)
target_compile_features(json_cuda PUBLIC cuda_std_11)
# nvcc added C++20 support in CUDA 12.0 and C++17 in CUDA 11.0; pick the
# newest standard the detected compiler actually supports (see #3907)
# instead of hard-requiring one standard for every CUDA version.
if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)
set(json_cuda_std 20)
elseif(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0)
set(json_cuda_std 17)
else()
set(json_cuda_std 11)
endif()
target_compile_features(json_cuda PUBLIC cuda_std_${json_cuda_std})
set_target_properties(json_cuda PROPERTIES set_target_properties(json_cuda PROPERTIES
CUDA_EXTENSIONS OFF CUDA_EXTENSIONS OFF
CUDA_STANDARD_REQUIRED ON CUDA_STANDARD_REQUIRED ON
-16
View File
@@ -16,20 +16,4 @@ int main()
// regression for #3013 (ordered_json::reset() compile error with nvcc) // regression for #3013 (ordered_json::reset() compile error with nvcc)
nlohmann::ordered_json metadata; nlohmann::ordered_json metadata;
metadata.erase("key"); metadata.erase("key");
// exercise comparisons (operator==/operator<=>, gated by
// JSON_HAS_THREE_WAY_COMPARISON, independent of JSON_HAS_RANGES) and
// range-based iteration (exercises iteration_proxy/ranges machinery
// beyond just the enable_borrowed_range specialization) — see #3907
nlohmann::json a = {1, 2, 3};
nlohmann::json b = {1, 2, 3};
static_cast<void>(a == b);
#if JSON_HAS_THREE_WAY_COMPARISON
static_cast<void>(a <=> b); // *NOPAD*
static_cast<void>(a <=> 1); // *NOPAD*
#endif
for (const auto& element : a)
{
static_cast<void>(element);
}
} }
-3
View File
@@ -232,9 +232,6 @@ TEST_CASE("algorithms")
// only the first four elements are expected to be sorted, the rest are // only the first four elements are expected to be sorted, the rest are
// unspecified by the standard // unspecified by the standard
const json expected({nullptr, false, true, 3}); const json expected({nullptr, false, true, 3});
// std::equal below only bounds-checks the first range; assert the
// second range is at least as long to rule out an over-read (CWE-126)
CHECK(std::distance(begin(expected), end(expected)) >= 4);
CHECK(std::equal(j.begin(), j.begin() + 4, begin(expected))); CHECK(std::equal(j.begin(), j.begin() + 4, begin(expected)));
} }
} }
+1 -1
View File
@@ -24,7 +24,7 @@ struct bad_allocator : std::allocator<T>
template<class U> bad_allocator(const bad_allocator<U>& /*unused*/) { } template<class U> bad_allocator(const bad_allocator<U>& /*unused*/) { }
template<class... Args> template<class... Args>
[[noreturn]] void construct(T* /*unused*/, Args&& ... /*unused*/) // NOLINT(cppcoreguidelines-missing-std-forward) void construct(T* /*unused*/, Args&& ... /*unused*/) // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
throw std::bad_alloc(); throw std::bad_alloc();
} }
+8 -6
View File
@@ -322,12 +322,14 @@ TEST_CASE("alternative string type")
SECTION("JSON pointer") SECTION("JSON pointer")
{ {
// Direct conversion from a json literal to alt_json is not supported due to issue #3425: // conversion from json to alt_json fails to compile (see #3425);
// alt_json's string_t (alt_string) is not directly constructible from std::string, so the // attempted fix(*) produces: [[['b','a','r'],['b','a','z']]] (with each char being an integer)
// cross-basic_json conversion falls back to the array-conversion path, incorrectly representing // (*) disable implicit conversion for json_refs of any basic_json type
// objects as arrays of [key, value] pairs and strings as arrays of character codes. // alt_json j = R"(
// See https://github.com/nlohmann/json/issues/3425 for details. // {
// Workaround: use alt_json::parse() instead of implicit conversion. // "foo": ["bar", "baz"]
// }
// )"_json;
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})"); auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]); CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
+13 -32
View File
@@ -369,7 +369,6 @@ TEST_CASE("lexicographical comparison operators")
SECTION("comparison: not equal") SECTION("comparison: not equal")
{ {
// check that two values compare unequal as expected // check that two values compare unequal as expected
// operator!= now means exactly !(a==b) without special cases for NaN/discarded
for (size_t i = 0; i < j_values.size(); ++i) for (size_t i = 0; i < j_values.size(); ++i)
{ {
for (size_t j = 0; j < j_values.size(); ++j) for (size_t j = 0; j < j_values.size(); ++j)
@@ -377,12 +376,25 @@ TEST_CASE("lexicographical comparison operators")
CAPTURE(i) CAPTURE(i)
CAPTURE(j) CAPTURE(j)
if (json::compares_unordered(j_values[i], j_values[j], true))
{
// if two values compare unordered,
// check that the boolean comparison result is always false
CHECK_FALSE(j_values[i] != j_values[j]);
}
else
{
// otherwise, check that they compare according to their definition
// as the inverse of equal
CHECK((j_values[i] != j_values[j]) == !(j_values[i] == j_values[j])); CHECK((j_values[i] != j_values[j]) == !(j_values[i] == j_values[j]));
} }
} }
}
// compare with null pointer // compare with null pointer
const json j_null; const json j_null;
CHECK((j_null != nullptr) == false);
CHECK((nullptr != j_null) == false);
CHECK((j_null != nullptr) == !(j_null == nullptr)); CHECK((j_null != nullptr) == !(j_null == nullptr));
CHECK((nullptr != j_null) == !(nullptr == j_null)); CHECK((nullptr != j_null) == !(nullptr == j_null));
} }
@@ -582,34 +594,3 @@ TEST_CASE("lexicographical comparison operators")
} }
#endif #endif
} }
#if JSON_HAS_THREE_WAY_COMPARISON
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
TEST_CASE("regression #3868 - heterogeneous comparisons compile under C++20 (P2468R2)")
{
// Issue #3868: operator!= was preventing compiler from synthesizing reversed
// operator== candidates under C++20's P2468R2 rewritten candidate rules.
// Verify that heterogeneous comparisons now work.
SECTION("string vs json")
{
std::string s = "string";
json j = "string";
CHECK(s == j);
CHECK(j == s);
CHECK_FALSE(s != j);
CHECK_FALSE(j != s);
}
SECTION("other heterogeneous types")
{
int i = 42;
json j = 42;
CHECK(i == j);
CHECK(j == i);
CHECK_FALSE(i != j);
CHECK_FALSE(j != i);
}
}
#endif
+1 -1
View File
@@ -278,7 +278,7 @@ TEST_CASE("constructors")
const auto t = j.get<std::tuple<int, float, std::string>>(); const auto t = j.get<std::tuple<int, float, std::string>>();
CHECK(std::get<0>(t) == j[0]); CHECK(std::get<0>(t) == j[0]);
CHECK(std::get<1>(t) == j[1]); CHECK(std::get<1>(t) == j[1]);
CHECK(std::get<2>(t) == j[2]); // CHECK(std::get<2>(t) == j[2]); // commented out due to CI issue, see https://github.com/nlohmann/json/pull/3985 and https://github.com/nlohmann/json/issues/4025
} }
SECTION("std::tuple tie") SECTION("std::tuple tie")
-26
View File
@@ -168,32 +168,6 @@ TEST_CASE("convenience functions")
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&); CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
} }
SECTION("string escape with ensure_ascii")
{
// control characters are escaped regardless of ensure_ascii
check_escaped("\x01", "\\u0001", true);
check_escaped("\x1f", "\\u001f", true);
// non-ASCII code points in the Basic Multilingual Plane are emitted as
// a single lowercase \uXXXX escape (exercises every nibble position)
check_escaped("\xC2\x80", "\\u0080", true); // U+0080
check_escaped("\xC3\xBF", "\\u00ff", true); // U+00FF (ÿ)
check_escaped("\xDF\xBF", "\\u07ff", true); // U+07FF
check_escaped("\xE4\xBD\xA0", "\\u4f60", true); // U+4F60 (你)
check_escaped("\xEA\xAF\x8D", "\\uabcd", true); // U+ABCD
check_escaped("\xEF\xBF\xBD", "\\ufffd", true); // U+FFFD (replacement char, all-f nibbles)
// code points outside the BMP are emitted as a UTF-16 surrogate pair
// of two lowercase \uXXXX escapes
check_escaped("\xF0\x90\x80\x80", "\\ud800\\udc00", true); // U+10000 (lowest astral)
check_escaped("\xF0\x9F\x98\x80", "\\ud83d\\ude00", true); // U+1F600 (😀)
check_escaped("\xF4\x8F\xBF\xBF", "\\udbff\\udfff", true); // U+10FFFF (highest code point)
// with ensure_ascii disabled, non-ASCII input is passed through verbatim
check_escaped("\xE4\xBD\xA0", "\xE4\xBD\xA0", false);
check_escaped("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", false);
}
SECTION("string concat") SECTION("string concat")
{ {
using nlohmann::detail::concat; using nlohmann::detail::concat;
+4 -14
View File
@@ -1761,27 +1761,16 @@ TEST_CASE("std::filesystem::path")
} }
#endif #endif
#if !JSON_USE_IMPLICIT_CONVERSIONS
TEST_CASE("std::optional") TEST_CASE("std::optional")
{ {
SECTION("null") SECTION("null")
{ {
const json j_null; json j_null;
const std::optional<std::string> opt_null; std::optional<std::string> opt_null;
CHECK(json(opt_null) == j_null); CHECK(json(opt_null) == j_null);
CHECK(j_null.get<std::optional<std::string>>() == std::nullopt); CHECK(j_null.get<std::optional<std::string>>() == std::nullopt);
// Constructing std::optional<T> directly from JSON null throws because
// std::optional's own converting constructor is chosen over basic_json's
// operator T(). This is a language-level limitation (std::optional<T> is
// constructible from T, and T is constructible from basic_json via the
// operator); there is no SFINAE path that distinguishes "call from inside
// std::optional's constructor" from "direct call". Use get<std::optional<T>>()
// or get_to() instead for correct null handling. See #4864 and #5246.
CHECK_THROWS_WITH_AS(std::optional<std::string>(j_null),
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
} }
SECTION("string") SECTION("string")
@@ -1830,6 +1819,7 @@ TEST_CASE("std::optional")
} }
} }
#endif #endif
#endif
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
#undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_17
+1 -1
View File
@@ -942,7 +942,7 @@ TEST_CASE("iterators 2")
json j_expected{5, 4, 3, 2, 1}; json j_expected{5, 4, 3, 2, 1};
auto reversed = j | std::views::reverse; auto reversed = j | std::views::reverse;
CHECK(reversed == j_expected); CHECK(std::ranges::equal(reversed, j_expected));
} }
SECTION("transform") SECTION("transform")
+6465 -4452
View File
File diff suppressed because it is too large Load Diff