Compare commits

..
Author SHA1 Message Date
Niels Lohmann 2234cd2d40 Fix std::terminate when converting std::optional with MSVC 2017
MSVC 2017 evaluates std::is_nothrow_assignable<json&, const T&> as true
even if T's to_json throws, so to_json(json&, const std::optional<T>&)
was noexcept there and the exception from #5642's test called
std::terminate instead of propagating. Make that conversion never
noexcept on MSVC 2017; all other compilers keep the exact condition.
The static_asserts on the condition are skipped for MSVC 2017; the
runtime check that the exception propagates still runs there.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 20:08:17 +02:00
Niels Lohmann 8c05e40cae Split the Visual Studio 2017 AppVeyor jobs in two
The VS 2017 jobs hit AppVeyor's 60-minute limit per job while still
compiling the tests (77 of about 108 test targets after 58 minutes).
They pass /std:c++17 for everything anyway, so build only the C++17
variant of each test (JSON_TestStandards=17), and split the unit test
files across two jobs each with the new JSON_TestShard=<index>/<count>
option, which keeps every <count>-th test file starting at <index>.
The extra variants of single test files are built in shard 0 only.

CMAKE_OPTIONS is no longer quoted in appveyor.yml, so that it can hold
more than one option.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 17:44:51 +02:00
Niels Lohmann 1f086dec2b Skip deleted-function detection checks on MSVC 2015
MSVC 2015 does not treat selecting a deleted function in decltype as a
substitution failure, so the detection traits in
unit-delete_deprecated_functions (#5755) and the integral-key checks in
unit-element_access2 (#5657) report deleted overloads as callable there.
Calling them still fails to compile. Skip those checks for
_MSC_VER < 1910, and use the stream operators for real in the runtime
section, so MSVC 2015 still compiles them with the macro set.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 14:58:12 +02:00
Niels Lohmann 336c808485 Skip the #5650 allocator test on MSVC 2015 debug builds
MSVC 2015's debug STL constructs the containers' debug proxies through
the allocator in noexcept constructors, so countdown_allocator's failing
construction crashes test-allocator (SIGSEGV) instead of throwing
std::bad_alloc. Use the guard #5585 uses for the same reason.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 13:49:28 +02:00
Niels Lohmann 556027f109 Avoid MSVC 2015's C4800 for enums with underlying type bool
MSVC 2015 warns about any conversion to bool (C4800), even with an
explicit cast, so the enum conversions from #5754 (#5671) failed the
AppVeyor build with /WX. Convert to bool by comparing with zero via the
new detail::bool_aware_static_cast, and keep doctest from printing the
enum in the test.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 13:29:32 +02:00
Niels Lohmann 413dd2d2c9 Re-amalgamate
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 13:00:09 +02:00
Niels Lohmann 98eff63537 Fix the AppVeyor (MSVC 2015-2019) build
- binary_reader: emit_signed/emit_unsigned pass integers that do not fit
  the number types to emit_float as long double, because MSVC's <cmath>
  has no integer overloads of std::isfinite (C2668 'fpclassify'), from #5607
- scalar comparisons: the friend operators take the JSON type for their
  noexcept from their parameter, because MSVC 2015/2017 take basic_json as
  the class template there (C3203) and MSVC 2019 16.0 does not see member
  types or template parameters, from #5751
- unit-conversions2: skip the !is_nothrow_constructible static_assert for
  std::optional on MSVC 2017, which evaluates the conditional noexcept as
  true (C2607), from #5754

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 12:57:44 +02:00
Niels Lohmann f88e209ea9 Ignore libstdc++'s <format> sign change in the sanitizer job
libstdc++ 14's <format> initializes a size_t parameter with -1 (GCC bug
119429), so every std::format call fails ci_test_clang_sanitizer under
-fsanitize=integer (test-std-format_cpp20). Exclude only the
implicit-integer-sign-change check and only that header via
-fsanitize-ignorelist.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 12:36:10 +02:00
Niels Lohmann d5a1c5d149 Fix CI on develop after #5600, #5607, and #5755
- binary_reader: cast the result of -1 - number back to number_integer_t,
  because a number_integer_t narrower than int is promoted to int, which
  GCC's -Warith-conversion rejects (ci_test_gcc, ci_test_standards_gcc)
- JSON_DELETE_DEPRECATED_FUNCTIONS: declare the deleted stream operators
  as function templates at namespace scope, because GCC < 5 rejects deleted
  friend functions ("can't initialize friend function") and Clang 7-9 report
  a redefinition when a class template has a deleted friend function
- docs: give the examples of JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS "Example:"
  titles and add the page to the docset (style_check)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 10:37:17 +02:00
Niels Lohmann 23d3b373e1 Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions (#5755)
* Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions

Defining JSON_DELETE_DEPRECATED_FUNCTIONS to 1 (or the CMake option
JSON_DeleteDeprecatedFunctions) declares every deprecated function as
deleted instead of deprecated, so that code that is not ready for 4.0.0
no longer compiles. A deleted function still takes part in overload
resolution, so from_*(ptr, len) cannot silently bind len to the strict
parameter of from_*(InputType&&, bool); the roadmap now plans to keep
these overloads deleted in 4.0.0 instead of removing them.

The legacy discarded-value comparison is left to its own macro.

Also update the 4.0 roadmap: add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
and JSON_DELETE_DEPRECATED_FUNCTIONS to the macro table, add the
from_bjdata/from_bon8 (ptr, len) overloads to the deprecated functions,
document the macro in the migration guide, and fix the docs style check
findings (example titles, missing docset entry for JSON_STRICT_BINARY_UTF8).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Declare each deprecated function once and guard only its body

Instead of repeating every deprecated declaration in an
#if JSON_DELETE_DEPRECATED_FUNCTIONS branch, keep one declaration
(with its deprecation attribute) and switch only between "= delete;"
and the function body. Suggested by @gregmarr in the review.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-04 22:11:34 +02:00
Niels Lohmann c5a7a4b46d Add deprecated from_bon8/from_bjdata(ptr, len) overloads (#5688)
from_bon8(ptr, len) and from_bjdata(ptr, len) had no overload for a
pointer and a length, unlike from_cbor/from_msgpack/from_ubjson/
from_bson. The call instead bound to from_*(InputType&&, bool strict),
which read ptr as a NUL-terminated C string via strlen and silently
converted len to the strict flag. Data containing a 0x00 byte was cut
off there; data without one was read past the end of the buffer.

Add a deprecated (ptr, len, strict, allow_exceptions) overload for
each function that forwards to (ptr, ptr + len, ...), matching the
existing deprecated overloads of the other four binary readers. Since
neither function ever had this overload, the deprecation is declared
as of version 3.13.0, the next unreleased version, rather than the
version each function was originally added in.

Fixes #5648.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-04 22:11:34 +02:00
Niels Lohmann 4f69be80d6 Clarify wording in diff documentation (#5759)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-04 18:20:20 +02:00
44 changed files with 1252 additions and 801 deletions
+18 -3
View File
@@ -16,6 +16,9 @@ only_commits:
environment: environment:
matrix: matrix:
# The Visual Studio 2017 jobs compile everything with /std:c++17, so they
# only build the C++17 variant of each test, split into two jobs each to
# stay below AppVeyor's 60-minute limit per job.
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Debug configuration: Debug
platform: x86 platform: x86
@@ -34,7 +37,13 @@ environment:
configuration: Release configuration: Release
platform: x86 platform: x86
CXX_FLAGS: "/permissive- /std:c++17 /utf-8 /W4 /WX" CXX_FLAGS: "/permissive- /std:c++17 /utf-8 /W4 /WX"
CMAKE_OPTIONS: "" CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=0/2"
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x86
CXX_FLAGS: "/permissive- /std:c++17 /utf-8 /W4 /WX"
CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=1/2"
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
@@ -55,7 +64,13 @@ environment:
configuration: Release configuration: Release
platform: x64 platform: x64
CXX_FLAGS: "/permissive- /std:c++17 /Zc:__cplusplus /utf-8 /W4 /WX" CXX_FLAGS: "/permissive- /std:c++17 /Zc:__cplusplus /utf-8 /W4 /WX"
CMAKE_OPTIONS: "" CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=0/2"
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x64
CXX_FLAGS: "/permissive- /std:c++17 /Zc:__cplusplus /utf-8 /W4 /WX"
CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=1/2"
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 15 2017
init: init:
@@ -66,7 +81,7 @@ install:
- if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32 - if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32
before_build: before_build:
- cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%" - cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On %CMAKE_OPTIONS%
build_script: build_script:
- cmake --build . --config "%configuration%" --parallel 2 - cmake --build . --config "%configuration%" --parallel 2
+1 -1
View File
@@ -107,7 +107,7 @@ jobs:
container: ubuntu:24.04 container: ubuntu:24.04
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_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_delete_deprecated_functions, 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 run: apt-get update ; apt-get install -y build-essential unzip wget git
+6
View File
@@ -62,6 +62,7 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the l
option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF) option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF)
option(JSON_StrictNulHandling "Build with strict NUL-byte handling enabled." OFF) option(JSON_StrictNulHandling "Build with strict NUL-byte handling enabled." OFF)
option(JSON_StrictBinaryUTF8 "Build with UTF-8 checks in the CBOR, UBJSON, BJData, and BSON writers enabled." OFF) option(JSON_StrictBinaryUTF8 "Build with UTF-8 checks in the CBOR, UBJSON, BJData, and BSON writers enabled." OFF)
option(JSON_DeleteDeprecatedFunctions "Delete the deprecated functions instead of only deprecating them." OFF)
if (JSON_CI) if (JSON_CI)
include(ci) include(ci)
@@ -123,6 +124,10 @@ if (JSON_StrictBinaryUTF8)
message(STATUS "Strict UTF-8 checks in binary writers enabled (JSON_STRICT_BINARY_UTF8=1)") message(STATUS "Strict UTF-8 checks in binary writers enabled (JSON_STRICT_BINARY_UTF8=1)")
endif() endif()
if (JSON_DeleteDeprecatedFunctions)
message(STATUS "Deprecated functions are deleted (JSON_DELETE_DEPRECATED_FUNCTIONS=1)")
endif()
if (JSON_Diagnostic_Positions) if (JSON_Diagnostic_Positions)
message(STATUS "Diagnostic positions enabled (JSON_DIAGNOSTIC_POSITIONS=1)") message(STATUS "Diagnostic positions enabled (JSON_DIAGNOSTIC_POSITIONS=1)")
endif() endif()
@@ -159,6 +164,7 @@ target_compile_definitions(
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1> $<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
$<$<BOOL:${JSON_StrictNulHandling}>:JSON_STRICT_NUL_HANDLING=1> $<$<BOOL:${JSON_StrictNulHandling}>:JSON_STRICT_NUL_HANDLING=1>
$<$<BOOL:${JSON_StrictBinaryUTF8}>:JSON_STRICT_BINARY_UTF8=1> $<$<BOOL:${JSON_StrictBinaryUTF8}>:JSON_STRICT_BINARY_UTF8=1>
$<$<BOOL:${JSON_DeleteDeprecatedFunctions}>:JSON_DELETE_DEPRECATED_FUNCTIONS=1>
) )
target_include_directories( target_include_directories(
+16 -2
View File
@@ -249,6 +249,20 @@ add_custom_target(ci_test_strict_nul_handling
COMMENT "Compile and test with strict NUL-byte handling enabled" COMMENT "Compile and test with strict NUL-byte handling enabled"
) )
###############################################################################
# Delete the deprecated functions.
###############################################################################
add_custom_target(ci_test_delete_deprecated_functions
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DeleteDeprecatedFunctions=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_delete_deprecated_functions
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_delete_deprecated_functions
COMMAND cd ${PROJECT_BINARY_DIR}/build_delete_deprecated_functions && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
COMMENT "Compile and test with the deprecated functions deleted"
)
############################################################################### ###############################################################################
# Disable global UDLs. # Disable global UDLs.
############################################################################### ###############################################################################
@@ -362,7 +376,7 @@ add_custom_target(ci_test_coverage
# Sanitizers. # Sanitizers.
############################################################################### ###############################################################################
set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base") set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base -fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/cmake/clang_sanitizer_ignorelist.txt")
add_custom_target(ci_test_clang_sanitizer add_custom_target(ci_test_clang_sanitizer
COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXX_FLAGS_SANITIZER} ${CMAKE_COMMAND} COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXX_FLAGS_SANITIZER} ${CMAKE_COMMAND}
@@ -705,7 +719,7 @@ ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY)
# the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0 # the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0
set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization
JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind
JSON_StrictNulHandling JSON_StrictBinaryUTF8) JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions)
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
+8
View File
@@ -0,0 +1,8 @@
# Sanitizer ignore list for ci_test_clang_sanitizer (-fsanitize-ignorelist).
#
# libstdc++ 14's <format> declares `_Scanner(basic_string_view<_CharT>, size_t __nargs = -1)`, so every std::format
# call converts -1 to size_t, which -fsanitize=integer reports as implicit-integer-sign-change. This is
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119429, not a bug in this library. Only that check and only <format> are
# excluded, so implicit sign changes in the library and the tests are still reported.
[implicit-integer-sign-change]
src:*/include/c++/*/format
+2
View File
@@ -219,6 +219,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', '
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DELETE_DEPRECATED_FUNCTIONS', 'Macro', 'api/macros/json_delete_deprecated_functions/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_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');
@@ -249,6 +250,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_TRY_USER', 'Macro', 'api
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS', 'Macro', 'api/macros/json_use_objects_for_enum_keyed_maps/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
+2 -2
View File
@@ -8,7 +8,7 @@ static basic_json diff(const basic_json& source,
Creates a [JSON Patch](http://jsonpatch.com) so that value `source` can be changed into the value `target` by calling Creates a [JSON Patch](http://jsonpatch.com) so that value `source` can be changed into the value `target` by calling
[`patch`](patch.md) function. [`patch`](patch.md) function.
For two JSON values `source` and `target`, the following code yields always `#!cpp true`: For two JSON values `source` and `target`, the following code always yields `#!cpp true`:
```cpp ```cpp
source.patch(diff(source, target)) == target; source.patch(diff(source, target)) == target;
``` ```
@@ -27,7 +27,7 @@ a JSON patch to convert the `source` to `target`
## Exception safety ## Exception safety
Strong guarantee: if an exception is thrown, there are no changes in the JSON value. Strong guarantee: `source` and `target` are never modified.
## Complexity ## Complexity
@@ -120,3 +120,12 @@ Linear in the size of the input.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0. - Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
- Added `error_handler` parameter in version 3.13.0. - Added `error_handler` parameter in version 3.13.0.
!!! warning "Deprecation"
- Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like
`#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`.
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
function.
@@ -106,3 +106,12 @@ Linear in the size of the input.
## Version history ## Version history
- Added in version 3.13.0. - Added in version 3.13.0.
!!! warning "Deprecation"
- Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like
`#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`.
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
function.
+5
View File
@@ -61,6 +61,11 @@ header. See also the [macro overview page](../../features/macros.md).
- [**JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS**](json_use_objects_for_enum_keyed_maps.md) - opt in to storing maps with enum - [**JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS**](json_use_objects_for_enum_keyed_maps.md) - opt in to storing maps with enum
keys as objects keys as objects
## Deprecated functions
- [**JSON_DELETE_DEPRECATED_FUNCTIONS**](json_delete_deprecated_functions.md) - opt in to deleting the deprecated
functions ahead of their removal in version 4.0.0
## Comparison behavior ## Comparison behavior
- [**JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON**](json_use_legacy_discarded_value_comparison.md) - - [**JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON**](json_use_legacy_discarded_value_comparison.md) -
@@ -0,0 +1,96 @@
# JSON_DELETE_DEPRECATED_FUNCTIONS
```cpp
#define JSON_DELETE_DEPRECATED_FUNCTIONS /* value */
```
When defined to `1`, all [deprecated functions](../../community/roadmap.md#removal-of-deprecated-functions) of the
library are declared as deleted (`= delete`) instead of only being marked as deprecated. Code that still calls one of
them no longer compiles. This way, you can find all calls that need to be replaced before version 4.0.0 removes these
functions; the [migration guide](../../integration/migration_guide.md#replace-deprecated-functions) describes how.
A deleted function, unlike a removed one, still takes part in overload resolution. A call that would select it
therefore fails to compile instead of silently selecting another overload. This matters for the deprecated
`from_*(ptr, len)` overloads of [`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md),
[`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md),
[`from_bon8`](../basic_json/from_bon8.md), and [`from_bson`](../basic_json/from_bson.md): without them, a call like
`from_cbor(ptr, len)` would compile, read `ptr` as a NUL-terminated string, and convert `len` to the `strict` parameter.
The macro does not affect the deprecated legacy comparison of discarded values, which is controlled by
[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](json_use_legacy_discarded_value_comparison.md).
## Default definition
The default value is `0` (disabled, the deprecated functions can still be called, and the compiler warns about it).
```cpp
#define JSON_DELETE_DEPRECATED_FUNCTIONS 0
```
## Notes
!!! info "CMake option"
The macro can also be set with the CMake option
[`JSON_DeleteDeprecatedFunctions`](../../integration/cmake.md#json_deletedeprecatedfunctions) (`OFF` by default).
!!! warning "Opt-in only"
This macro must be defined **before** including `<nlohmann/json.hpp>`. Defining it after the include has no
effect. Define it for the whole project to avoid different declarations of the same class in different
translation units.
!!! note "ABI compatibility"
The macro only turns calls that compile into calls that do not; it does not change the layout or the behavior of
any type. Its value is therefore not encoded in the [namespace](../../features/namespace.md).
## Examples
??? example "Example: default behavior (macro not defined)"
Without the macro, the deprecated overload is called, and the compiler warns about it:
```cpp
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
const std::vector<std::uint8_t> v = {0x82, 0x01, 0x02};
auto j = json::from_cbor(v.data(), v.size());
// warning: 'from_cbor' is deprecated: Since 3.8.0; use from_cbor(ptr, ptr + len)
}
```
??? example "Example: deleted deprecated functions (macro defined to 1)"
With the macro, the call does not compile:
```cpp
#define JSON_DELETE_DEPRECATED_FUNCTIONS 1
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
const std::vector<std::uint8_t> v = {0x82, 0x01, 0x02};
auto j = json::from_cbor(v.data(), v.size());
// error: call to deleted function 'from_cbor'
}
```
## See also
- [Roadmap: removal of deprecated functions](../../community/roadmap.md#removal-of-deprecated-functions) - the
deprecated functions and the version they were deprecated in
- [Migration guide: replace deprecated functions](../../integration/migration_guide.md#replace-deprecated-functions) -
how to replace each deprecated function
## Version history
- Added in version 3.13.0.
- Planned to be removed in version 4.0.0, which removes the deprecated functions. The deprecated `from_*(ptr, len)`
overloads stay deleted in version 4.0.0.
@@ -112,3 +112,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.13.0.
- Planned to become the default (with the macro removed) in version 4.0.0.
@@ -44,7 +44,7 @@ By default, implicit conversions are enabled.
## Examples ## Examples
??? example "Example: implicit conversion" ??? example "Example: implicit and explicit conversions"
This is an example for an implicit conversion: This is an example for an implicit conversion:
@@ -69,7 +69,7 @@ The default value is `0` (disabled — existing behavior is preserved).
## Examples ## Examples
??? example "Default behavior (macro not defined)" ??? example "Example: default behavior (macro not defined)"
Without the macro, a map with enum keys is stored as an array of pairs: Without the macro, a map with enum keys is stored as an array of pairs:
@@ -96,7 +96,7 @@ The default value is `0` (disabled — existing behavior is preserved).
} }
``` ```
??? example "Objects for enum-keyed maps (macro defined to 1)" ??? example "Example: objects for enum-keyed maps (macro defined to 1)"
With the macro, the same map is stored as an object: With the macro, the same map is stored as an object:
+12 -2
View File
@@ -64,6 +64,8 @@ The following macros guard changes that are planned to become the default in ver
| [`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md) | `0` | `1`: reading from a stream does not consume the character after a number | – | 3.13.0 | | [`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md) | `0` | `1`: reading from a stream does not consume the character after a number | – | 3.13.0 |
| [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) | `0` | `1`: a NUL byte in the input is a parse error instead of the end of input | [`JSON_StrictNulHandling`](../integration/cmake.md#json_strictnulhandling) | 3.13.0 | | [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) | `0` | `1`: a NUL byte in the input is a parse error instead of the end of input | [`JSON_StrictNulHandling`](../integration/cmake.md#json_strictnulhandling) | 3.13.0 |
| [`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) | `0` | `1`: `to_cbor`, `to_ubjson`, `to_bjdata`, and `to_bson` throw for strings that are not valid UTF-8 by default | [`JSON_StrictBinaryUTF8`](../integration/cmake.md#json_strictbinaryutf8) | 3.13.0 | | [`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) | `0` | `1`: `to_cbor`, `to_ubjson`, `to_bjdata`, and `to_bson` throw for strings that are not valid UTF-8 by default | [`JSON_StrictBinaryUTF8`](../integration/cmake.md#json_strictbinaryutf8) | 3.13.0 |
| [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md) | `0` | `1`: a `basic_json` value can no longer be created from a one-element tuple of a reference to it, such as `std::forward_as_tuple(j)`| [`JSON_DisableTupleReferenceConversion`](../integration/cmake.md#json_disabletuplereferenceconversion) | 3.13.0 |
| [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) | `0` | removed: the deprecated functions are removed (see below); the `from_*(ptr, len)` overloads stay deleted | [`JSON_DeleteDeprecatedFunctions`](../integration/cmake.md#json_deletedeprecatedfunctions) | 3.13.0 |
For example, the following makes a 3.x release behave like version 4.0 with respect to these changes: For example, the following makes a 3.x release behave like version 4.0 with respect to these changes:
@@ -75,6 +77,8 @@ For example, the following makes a 3.x release behave like version 4.0 with resp
#define JSON_PRECISE_STREAM_POSITION 1 #define JSON_PRECISE_STREAM_POSITION 1
#define JSON_STRICT_NUL_HANDLING 1 #define JSON_STRICT_NUL_HANDLING 1
#define JSON_STRICT_BINARY_UTF8 1 #define JSON_STRICT_BINARY_UTF8 1
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1
#define JSON_DELETE_DEPRECATED_FUNCTIONS 1
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
``` ```
@@ -84,8 +88,13 @@ way to achieve this.
### Removal of deprecated functions ### Removal of deprecated functions
Version 4.0 will remove all deprecated functions. Compiling with deprecation warnings enabled shows which of them your Version 4.0 will remove all deprecated functions. Compiling with deprecation warnings enabled shows which of them your
code still uses. The [migration guide](../integration/migration_guide.md#replace-deprecated-functions) shows how to code still uses. Defining [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) to
replace each of them. `1` turns these warnings into errors, as the deprecated functions are then deleted. The
[migration guide](../integration/migration_guide.md#replace-deprecated-functions) shows how to replace each of them.
The `from_*` overloads taking a pointer and a length are not removed in version 4.0, but stay deleted. Without them, a
call like `from_cbor(ptr, len)` would still compile: it would read `ptr` as a NUL-terminated string and convert `len`
to the `strict` parameter.
| Deprecated | Since | Migration | | Deprecated | Since | Migration |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|----------------------------------------------------------------------------------| |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|----------------------------------------------------------------------------------|
@@ -97,6 +106,7 @@ replace each of them.
| [`json_pointer::operator string_t`](../api/json_pointer/operator_string_t.md) | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) | | [`json_pointer::operator string_t`](../api/json_pointer/operator_string_t.md) | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) |
| [`json_pointer`](../api/json_pointer/index.md) with a `basic_json` type as template argument, and the overloads of `value`, `contains`, `operator[]`, and `at` accepting such a pointer | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) | | [`json_pointer`](../api/json_pointer/index.md) with a `basic_json` type as template argument, and the overloads of `value`, `contains`, `operator[]`, and `at` accepting such a pointer | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) |
| Comparing a [`json_pointer`](../api/json_pointer/index.md) with a string via [`operator==`](../api/json_pointer/operator_eq.md) or [`operator!=`](../api/json_pointer/operator_ne.md) | 3.11.2 | [JSON Pointers](../integration/migration_guide.md#json-pointers) | | Comparing a [`json_pointer`](../api/json_pointer/index.md) with a string via [`operator==`](../api/json_pointer/operator_eq.md) or [`operator!=`](../api/json_pointer/operator_ne.md) | 3.11.2 | [JSON Pointers](../integration/migration_guide.md#json-pointers) |
| [`from_bjdata`](../api/basic_json/from_bjdata.md) and [`from_bon8`](../api/basic_json/from_bon8.md) with `(ptr, len)` | 3.13.0 | [Parsing](../integration/migration_guide.md#parsing) |
The deprecated legacy comparison of discarded values is controlled by a macro and therefore listed in the table above. The deprecated legacy comparison of discarded values is controlled by a macro and therefore listed in the table above.
+13 -1
View File
@@ -23,6 +23,17 @@ This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/
See [full documentation of `JSON_CATCH_USER(exception)`](../api/macros/json_throw_user.md). See [full documentation of `JSON_CATCH_USER(exception)`](../api/macros/json_throw_user.md).
## `JSON_DELETE_DEPRECATED_FUNCTIONS`
When defined to `1`, all deprecated functions are declared as deleted instead of only being marked as deprecated, so
code that still calls them no longer compiles. This way, you can find all calls that need to be replaced before version
4.0.0 removes these functions.
The macro can also be set with the CMake option
[`JSON_DeleteDeprecatedFunctions`](../integration/cmake.md#json_deletedeprecatedfunctions) (`OFF` by default).
See [full documentation of `JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md).
## `JSON_DIAGNOSTICS` ## `JSON_DIAGNOSTICS`
This macro enables extended diagnostics for exception messages. Possible values are `1` to enable or `0` to disable This macro enables extended diagnostics for exception messages. Possible values are `1` to enable or `0` to disable
@@ -86,7 +97,8 @@ See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json
## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION` ## `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 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. value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise. This
is planned to become the default in version 4.0.0.
See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md). See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md).
+6
View File
@@ -132,6 +132,12 @@ Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/
Enable CI build targets. The exact targets are used during the several CI steps and are subject to change without notice. This option is `OFF` by default. Enable CI build targets. The exact targets are used during the several CI steps and are subject to change without notice. This option is `OFF` by default.
### `JSON_DeleteDeprecatedFunctions`
Delete the deprecated functions instead of only deprecating them by defining the macro
[`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md). This option is `OFF` by
default.
### `JSON_Diagnostics` ### `JSON_Diagnostics`
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default. Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.
@@ -14,6 +14,13 @@ deprecations are annotated with
[`HEDLEY_DEPRECATED_FOR`](https://nemequ.github.io/hedley/api-reference.html#HEDLEY_DEPRECATED_FOR) to report which [`HEDLEY_DEPRECATED_FOR`](https://nemequ.github.io/hedley/api-reference.html#HEDLEY_DEPRECATED_FOR) to report which
function to use instead. function to use instead.
!!! tip "Find all calls of deprecated functions"
Define [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) to `1` (or set the
CMake option [`JSON_DeleteDeprecatedFunctions`](cmake.md#json_deletedeprecatedfunctions)) to delete all deprecated
functions. Every remaining call then fails to compile, even if deprecation warnings are disabled, so your code is
ready for version 4.0.0 once it compiles with the macro.
### Parsing ### Parsing
- Function `friend std::istream& operator<<(basic_json&, std::istream&)` is deprecated since 3.0.0. Please use - Function `friend std::istream& operator<<(basic_json&, std::istream&)` is deprecated since 3.0.0. Please use
@@ -41,8 +48,10 @@ function to use instead.
[`from_ubjson`](../api/basic_json/from_ubjson.md), and [`from_bson`](../api/basic_json/from_bson.md)) via initializer [`from_ubjson`](../api/basic_json/from_ubjson.md), and [`from_bson`](../api/basic_json/from_bson.md)) via initializer
lists is deprecated since 3.8.0. Instead, pass two iterators; for instance, call `from_cbor(ptr, ptr+len)` instead of lists is deprecated since 3.8.0. Instead, pass two iterators; for instance, call `from_cbor(ptr, ptr+len)` instead of
`from_cbor({ptr, len})`. Likewise, passing a pointer and a length as two separate arguments to `from_cbor`, `from_cbor({ptr, len})`. Likewise, passing a pointer and a length as two separate arguments to `from_cbor`,
`from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0; call `from_cbor(ptr, ptr+len)` instead of `from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0, and to
`from_cbor(ptr, len)`. [`from_bjdata`](../api/basic_json/from_bjdata.md) and [`from_bon8`](../api/basic_json/from_bon8.md) since 3.13.0; call
`from_cbor(ptr, ptr+len)` instead of `from_cbor(ptr, len)`. These overloads will not be removed in version 4.0.0, but
deleted, so a call like `from_cbor(ptr, len)` cannot compile and convert `len` to the `strict` parameter.
=== "Deprecated" === "Deprecated"
+1
View File
@@ -292,6 +292,7 @@ nav:
- 'JSON_BRACE_INIT_COPY_SEMANTICS': api/macros/json_brace_init_copy_semantics.md - 'JSON_BRACE_INIT_COPY_SEMANTICS': api/macros/json_brace_init_copy_semantics.md
- 'JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER': api/macros/json_throw_user.md - 'JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER': api/macros/json_throw_user.md
- 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md
- 'JSON_DELETE_DEPRECATED_FUNCTIONS': api/macros/json_delete_deprecated_functions.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_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
@@ -172,7 +172,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
typename BasicJsonType::number_unsigned_t, underlying_type>::type; typename BasicJsonType::number_unsigned_t, underlying_type>::type;
value_type val; value_type val;
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
e = static_cast<EnumType>(static_cast<underlying_type>(val)); e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -287,9 +287,20 @@ struct external_constructor<value_t::object>
///////////// /////////////
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
// whether storing the value of a std::optional<T> cannot throw; MSVC 2017
// evaluates std::is_nothrow_assignable as true even if T's to_json throws, so
// the exception would call std::terminate (#5642)
#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
template<typename BasicJsonType, typename T>
using is_nothrow_optional_to_json = std::false_type;
#else
template<typename BasicJsonType, typename T>
using is_nothrow_optional_to_json = std::is_nothrow_assignable<BasicJsonType&, const T&>;
#endif
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T,
enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0>
void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(std::is_nothrow_assignable<BasicJsonType&, const T&>::value) void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(is_nothrow_optional_to_json<BasicJsonType, T>::value)
{ {
if (opt.has_value()) if (opt.has_value())
{ {
@@ -365,7 +376,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept
{ {
using underlying_type = typename std::underlying_type<EnumType>::type; using underlying_type = typename std::underlying_type<EnumType>::type;
static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer; static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;
external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e)); external_constructor<integral_value_t>::construct(j, bool_aware_static_cast<underlying_type>(e));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -662,10 +662,11 @@ class binary_reader
} }
// the value is -1 - number, which fits into number_integer_t // the value is -1 - number, which fits into number_integer_t
// whenever number does // whenever number does; the outer cast undoes the integral promotion
// for number_integer_t types narrower than int
if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number))) if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number)))
{ {
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)); return sax->number_integer(conditional_static_cast<number_integer_t>(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)));
} }
// like the lexer does for JSON text, store a value too small for // like the lexer does for JSON text, store a value too small for
@@ -4003,7 +4004,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -4026,7 +4028,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -4037,7 +4040,8 @@ class binary_reader
and NaN in the input are passed on unchanged. Integers only overflow if and NaN in the input are passed on unchanged. Integers only overflow if
number_float_t cannot represent 2^64, e.g., a half-precision type. number_float_t cannot represent 2^64, e.g., a half-precision type.
@tparam NumberType a floating-point or integer type @tparam NumberType a floating-point type (emit_signed and emit_unsigned
convert integers to long double first)
@param[in] number the number @param[in] number the number
@return whether the SAX parser accepted the value @return whether the SAX parser accepted the value
+24
View File
@@ -81,9 +81,13 @@ class json_pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/ /// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
operator string_t() const operator string_t() const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return to_string(); return to_string();
} }
#endif
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
/// @brief write string representation of the JSON pointer to stream /// @brief write string representation of the JSON pointer to stream
@@ -1022,9 +1026,13 @@ class json_pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
bool operator==(const string_t& rhs) const bool operator==(const string_t& rhs) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return *this == json_pointer(rhs); return *this == json_pointer(rhs);
} }
#endif
/// @brief 3-way compares two JSON pointers /// @brief 3-way compares two JSON pointers
template<typename RefStringTypeRhs> template<typename RefStringTypeRhs>
@@ -1102,18 +1110,26 @@ template<typename RefStringTypeLhs,
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
const StringType& rhs) const StringType& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return lhs == json_pointer<RefStringTypeLhs>(rhs); return lhs == json_pointer<RefStringTypeLhs>(rhs);
} }
#endif
template<typename RefStringTypeRhs, template<typename RefStringTypeRhs,
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
inline bool operator==(const StringType& lhs, inline bool operator==(const StringType& lhs,
const json_pointer<RefStringTypeRhs>& rhs) const json_pointer<RefStringTypeRhs>& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return json_pointer<RefStringTypeRhs>(lhs) == rhs; return json_pointer<RefStringTypeRhs>(lhs) == rhs;
} }
#endif
template<typename RefStringTypeLhs, typename RefStringTypeRhs> template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
@@ -1127,18 +1143,26 @@ template<typename RefStringTypeLhs,
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
const StringType& rhs) const StringType& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
#endif
template<typename RefStringTypeRhs, template<typename RefStringTypeRhs,
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
inline bool operator!=(const StringType& lhs, inline bool operator!=(const StringType& lhs,
const json_pointer<RefStringTypeRhs>& rhs) const json_pointer<RefStringTypeRhs>& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
#endif
template<typename RefStringTypeLhs, typename RefStringTypeRhs> template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
+4
View File
@@ -888,6 +888,10 @@
#define JSON_DISABLE_ENUM_SERIALIZATION 0 #define JSON_DISABLE_ENUM_SERIALIZATION 0
#endif #endif
#ifndef JSON_DELETE_DEPRECATED_FUNCTIONS
#define JSON_DELETE_DEPRECATED_FUNCTIONS 0
#endif
#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION #ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
#endif #endif
@@ -43,6 +43,7 @@
#undef JSON_PRECISE_STREAM_POSITION #undef JSON_PRECISE_STREAM_POSITION
#undef JSON_STRICT_NUL_HANDLING #undef JSON_STRICT_NUL_HANDLING
#undef JSON_STRICT_BINARY_UTF8 #undef JSON_STRICT_BINARY_UTF8
#undef JSON_DELETE_DEPRECATED_FUNCTIONS
#undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS #undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif #endif
@@ -906,6 +906,21 @@ T conditional_static_cast(U value)
return value; return value;
} }
// like conditional_static_cast, but converts to bool by comparing with zero,
// because MSVC 2015 warns about any conversion to bool (C4800), even with an
// explicit cast; used for enums whose underlying type is bool
template < typename T, typename U, enable_if_t < !std::is_same<T, bool>::value, int > = 0 >
T bool_aware_static_cast(U value)
{
return conditional_static_cast<T>(value);
}
template<typename T, typename U, enable_if_t<std::is_same<T, bool>::value, int> = 0>
bool bool_aware_static_cast(U value)
{
return value != U();
}
template<typename... Types> template<typename... Types>
using all_integral = conjunction<std::is_integral<Types>...>; using all_integral = conjunction<std::is_integral<Types>...>;
+221 -194
View File
@@ -612,208 +612,100 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// constructor for rvalue binary arrays (internal type) /// constructor for rvalue binary arrays (internal type)
json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {} json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
// raw, allocation-free transfer of m_data from src to dst: no void destroy(value_t t)
// set_parents()/assert_invariant() (the former is O(#children) per
// call under JSON_DIAGNOSTICS, which would make the walk below
// quadratic); dst takes ownership, src is left as value_t::null.
static void take(basic_json& dst, basic_json& src) noexcept
{
dst.m_data.m_type = src.m_data.m_type;
dst.m_data.m_value = src.m_data.m_value;
src.m_data.m_type = value_t::null;
}
// true if v is not an array/object, or is an already-empty one
static bool has_no_children(const basic_json& v) noexcept
{
switch (v.m_data.m_type)
{
case value_t::array:
return v.m_data.m_value.array->empty();
case value_t::object:
return v.m_data.m_value.object->empty();
default:
return true;
}
}
static basic_json& last_child(basic_json& v)
{
if (v.m_data.m_type == value_t::array)
{
return v.m_data.m_value.array->back();
}
JSON_ASSERT(v.m_data.m_type == value_t::object);
return v.m_data.m_value.object->rbegin()->second;
}
// removes the last child of a non-empty array/object v; this never
// allocates, and since it is only ever called when that child is a
// scalar or an already-empty array/object, destroying it never
// recurses more than one level deep (see destroy() below)
static void pop_last_child(basic_json& v)
{
if (v.m_data.m_type == value_t::array)
{
v.m_data.m_value.array->pop_back();
}
else
{
JSON_ASSERT(v.m_data.m_type == value_t::object);
// erase() needs a forward iterator, so std::prev(end()) is
// used here rather than rbegin() (see last_child() above)
v.m_data.m_value.object->erase(std::prev(v.m_data.m_value.object->end()));
}
}
// deallocates the (already empty) array/object held by v; this is
// the same allocator-based free the old recursive implementation
// used, just factored out so every level of the walk in destroy()
// can share it
static void free_container(basic_json& v) noexcept
{
if (v.m_data.m_type == value_t::array)
{
JSON_ASSERT(v.m_data.m_value.array->empty());
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, v.m_data.m_value.array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, v.m_data.m_value.array, 1);
}
else
{
JSON_ASSERT(v.m_data.m_type == value_t::object);
JSON_ASSERT(v.m_data.m_value.object->empty());
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, v.m_data.m_value.object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, v.m_data.m_value.object, 1);
}
v.m_data.m_type = value_t::null; // avoid a double free if v is later destructed
}
void destroy_string() noexcept
{
if (string == nullptr)
{
// not initialized (e.g., due to exception in the ctor)
return;
}
AllocatorType<string_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
}
void destroy_binary() noexcept
{
if (binary == nullptr)
{
// not initialized (e.g., due to exception in the ctor)
return;
}
AllocatorType<binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
}
// t must be value_t::array or value_t::object
void destroy_container(value_t t) noexcept
{ {
if ( if (
(t == value_t::object && object == nullptr) || (t == value_t::object && object == nullptr) ||
(t == value_t::array && array == nullptr) (t == value_t::array && array == nullptr) ||
(t == value_t::string && string == nullptr) ||
(t == value_t::binary && binary == nullptr)
) )
{ {
// not initialized (e.g., due to exception in the ctor) // not initialized (e.g., due to exception in the ctor)
return; return;
} }
if (t == value_t::array || t == value_t::object)
// Destroy the tree without recursing per nesting level and
// without any heap allocation: a heap-allocated flattening
// stack (the previous implementation) can itself throw
// bad_alloc, which would escape this noexcept destructor and
// terminate the program (#5135).
//
// Instead, walk down the "last child" chain, reversing links
// as we go: cur is the container currently being emptied,
// and prev is its parent (value_t::null when there is none).
// Each parent's last child slot doubles as storage for that
// parent's own parent link while we are below it, so no
// extra memory is needed. We only ever remove a child once
// it is a scalar or an empty array/object, which neither
// allocates nor recurses more than one level deep.
//
// This json_value is not itself a basic_json, so the
// top-level container is first moved into a local stand-in
// ("cur"); a default-constructed basic_json has a null
// pointer in its m_value (see data::m_value's initializer),
// so swapping it with *this leaves this union's own pointer
// null, and it is never looked at or freed a second time.
basic_json cur;
cur.m_data.m_type = t;
using std::swap;
swap(cur.m_data.m_value, *this);
basic_json prev; // value_t::null: no parent
while (true)
{ {
if (has_no_children(cur)) // flatten the current json_value to a heap-allocated stack
std::vector<basic_json> stack;
// move the top-level items to stack
if (t == value_t::array)
{ {
if (prev.m_data.m_type == value_t::null) stack.reserve(array->size());
{ std::move(array->begin(), array->end(), std::back_inserter(stack));
free_container(cur);
return; // back at the top with nothing left to do
} }
else
// ascend: detach the grandparent link from prev's
// last slot, drop that (now null) slot, free cur
// (it is empty), then move up one level
basic_json gp;
take(gp, last_child(prev));
pop_last_child(prev);
free_container(cur);
take(cur, prev);
take(prev, gp);
continue;
}
basic_json& cur_last_ref = last_child(cur);
if (has_no_children(cur_last_ref))
{ {
// scalar, or already-empty array/object stack.reserve(object->size());
pop_last_child(cur); for (auto&& it : *object)
continue; {
} stack.push_back(std::move(it.second));
// descend into the non-empty last child, reversing the
// link: its slot takes over prev, and the child becomes
// the new cur
basic_json tmp;
take(tmp, cur_last_ref);
take(cur_last_ref, prev);
take(prev, cur);
take(cur, tmp);
} }
} }
void destroy(value_t t) while (!stack.empty())
{ {
// move the last item to a local variable to be processed
basic_json current_item(std::move(stack.back()));
stack.pop_back();
// if current_item is array/object, move
// its children to the stack to be processed later
if (current_item.is_array())
{
std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
current_item.m_data.m_value.array->clear();
}
else if (current_item.is_object())
{
for (auto&& it : *current_item.m_data.m_value.object)
{
stack.push_back(std::move(it.second));
}
current_item.m_data.m_value.object->clear();
}
// it's now safe that current_item gets destructed
// since it doesn't have any children
}
}
switch (t) switch (t)
{ {
case value_t::string: case value_t::object:
destroy_string(); {
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
break; break;
}
case value_t::array:
{
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
break;
}
case value_t::string:
{
AllocatorType<string_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
break;
}
case value_t::binary: case value_t::binary:
destroy_binary(); {
break; AllocatorType<binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
case value_t::object: std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
case value_t::array:
destroy_container(t);
break; break;
}
case value_t::null: case value_t::null:
case value_t::boolean: case value_t::boolean:
@@ -822,9 +714,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::number_float: case value_t::number_float:
case value_t::discarded: case value_t::discarded:
default: default:
{
break; break;
} }
} }
}
}; };
private: private:
@@ -3598,9 +3492,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return value(ptr.convert(), default_value); return value(ptr.convert(), default_value);
} }
#endif
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type, template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t < detail::enable_if_t <
@@ -3609,9 +3507,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return value(ptr.convert(), std::forward<ValueType>(default_value)); return value(ptr.convert(), std::forward<ValueType>(default_value));
} }
#endif
/// @brief access the first element /// @brief access the first element
/// @sa https://json.nlohmann.me/api/basic_json/front/ /// @sa https://json.nlohmann.me/api/basic_json/front/
@@ -3969,9 +3871,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.contains(this); return ptr.contains(this);
} }
#endif
/// @} /// @}
@@ -4082,9 +3988,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`. /// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ref.items(); return ref.items();
} }
#endif
/// @brief wrapper to access iterator member functions in range-based for /// @brief wrapper to access iterator member functions in range-based for
/// @sa https://json.nlohmann.me/api/basic_json/items/ /// @sa https://json.nlohmann.me/api/basic_json/items/
@@ -4093,9 +4003,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`. /// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ref.items(); return ref.items();
} }
#endif
/// @brief helper to access iterator member functions in range-based for /// @brief helper to access iterator member functions in range-based for
/// @sa https://json.nlohmann.me/api/basic_json/items/ /// @sa https://json.nlohmann.me/api/basic_json/items/
@@ -5184,7 +5098,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -5193,7 +5107,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -5214,11 +5128,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif #endif
} }
// The friend comparisons with a scalar name the JSON type via decltype of
// their parameter in noexcept, because older MSVC versions do not see the
// class scope there: MSVC 2015 and 2017 take basic_json as the template,
// and MSVC 2019 16.0 rejects member types and template parameters.
/// @brief comparison: equal /// @brief comparison: equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs == basic_json(rhs); return lhs == basic_json(rhs);
} }
@@ -5227,7 +5146,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) == rhs; return basic_json(lhs) == rhs;
} }
@@ -5243,7 +5162,7 @@ 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/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs != basic_json(rhs); return lhs != basic_json(rhs);
} }
@@ -5252,7 +5171,7 @@ 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/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) != rhs; return basic_json(lhs) != rhs;
} }
@@ -5272,7 +5191,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs < basic_json(rhs); return lhs < basic_json(rhs);
} }
@@ -5281,7 +5200,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) < rhs; return basic_json(lhs) < rhs;
} }
@@ -5301,7 +5220,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs <= basic_json(rhs); return lhs <= basic_json(rhs);
} }
@@ -5310,7 +5229,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -5331,7 +5250,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs > basic_json(rhs); return lhs > basic_json(rhs);
} }
@@ -5340,7 +5259,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) > rhs; return basic_json(lhs) > rhs;
} }
@@ -5360,7 +5279,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs >= basic_json(rhs); return lhs >= basic_json(rhs);
} }
@@ -5369,7 +5288,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -5405,6 +5324,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return o; return o;
} }
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief serialize to stream /// @brief serialize to stream
/// @sa https://json.nlohmann.me/api/operator_ltlt/ /// @sa https://json.nlohmann.me/api/operator_ltlt/
/// @deprecated This function is deprecated since 3.0.0 and will be removed in /// @deprecated This function is deprecated since 3.0.0 and will be removed in
@@ -5416,6 +5338,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{ {
return o << j; return o << j;
} }
#endif
#endif // JSON_NO_IO #endif // JSON_NO_IO
/// @} /// @}
@@ -5467,12 +5390,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool allow_exceptions = true, const bool allow_exceptions = true,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
basic_json result; basic_json result;
auto p = parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas); auto p = parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
p.parse(true, result); p.parse(true, result);
return result; return result;
} }
#endif
/// @brief check if the input is valid JSON /// @brief check if the input is valid JSON
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
@@ -5502,9 +5429,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static bool accept(detail::span_input_adapter&& i, static bool accept(detail::span_input_adapter&& i,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true); return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
} }
#endif
/// @brief generate SAX events /// @brief generate SAX events
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
@@ -5565,6 +5496,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool strict = true, const bool strict = true,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
auto ia = i.get(); auto ia = i.get();
return format == input_format_t::json return format == input_format_t::json
@@ -5573,10 +5507,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
} }
#endif
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief deserialize from stream /// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @sa https://json.nlohmann.me/api/operator_gtgt/
/// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
@@ -5588,6 +5526,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{ {
return operator>>(i, j); return operator>>(i, j);
} }
#endif
/// @brief deserialize from stream /// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @sa https://json.nlohmann.me/api/operator_gtgt/
@@ -5935,9 +5874,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
@@ -5945,9 +5888,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler); return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler);
} }
#endif
/// @brief create a JSON value from an input in MessagePack format /// @brief create a JSON value from an input in MessagePack format
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
@@ -5980,18 +5927,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static basic_json from_msgpack(const T* ptr, std::size_t len, static basic_json from_msgpack(const T* ptr, std::size_t len,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_msgpack(ptr, ptr + len, strict, allow_exceptions); return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
static basic_json from_msgpack(detail::span_input_adapter&& i, static basic_json from_msgpack(detail::span_input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions); return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions);
} }
#endif
/// @brief create a JSON value from an input in UBJSON format /// @brief create a JSON value from an input in UBJSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
@@ -6024,18 +5979,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static basic_json from_ubjson(const T* ptr, std::size_t len, static basic_json from_ubjson(const T* ptr, std::size_t len,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_ubjson(ptr, ptr + len, strict, allow_exceptions); return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
static basic_json from_ubjson(detail::span_input_adapter&& i, static basic_json from_ubjson(detail::span_input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions); return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions);
} }
#endif
/// @brief create a JSON value from an input in BJData format /// @brief create a JSON value from an input in BJData format
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
@@ -6062,6 +6025,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler);
} }
template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len))
static basic_json from_bjdata(const T* ptr, std::size_t len,
const bool strict = true,
const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{
return from_bjdata(ptr, ptr + len, strict, allow_exceptions);
}
#endif
/// @brief create a JSON value from an input in BON8 format /// @brief create a JSON value from an input in BON8 format
/// @sa https://json.nlohmann.me/api/basic_json/from_bon8/ /// @sa https://json.nlohmann.me/api/basic_json/from_bon8/
template<typename InputType> template<typename InputType>
@@ -6085,6 +6062,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions);
} }
template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len))
static basic_json from_bon8(const T* ptr, std::size_t len,
const bool strict = true,
const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{
return from_bon8(ptr, ptr + len, strict, allow_exceptions);
}
#endif
/// @brief create a JSON value from an input in BSON format /// @brief create a JSON value from an input in BSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/ /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
template<typename InputType> template<typename InputType>
@@ -6116,18 +6107,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static basic_json from_bson(const T* ptr, std::size_t len, static basic_json from_bson(const T* ptr, std::size_t len,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_bson(ptr, ptr + len, strict, allow_exceptions); return from_bson(ptr, ptr + len, strict, allow_exceptions);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
static basic_json from_bson(detail::span_input_adapter&& i, static basic_json from_bson(detail::span_input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions); return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions);
} }
#endif
/// @} /// @}
////////////////////////// //////////////////////////
@@ -6147,9 +6146,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
#endif
/// @brief access specified element via JSON Pointer /// @brief access specified element via JSON Pointer
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
@@ -6161,9 +6164,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
#endif
/// @brief access specified element via JSON Pointer /// @brief access specified element via JSON Pointer
/// @sa https://json.nlohmann.me/api/basic_json/at/ /// @sa https://json.nlohmann.me/api/basic_json/at/
@@ -6175,9 +6182,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_checked(this); return ptr.get_checked(this);
} }
#endif
/// @brief access specified element via JSON Pointer /// @brief access specified element via JSON Pointer
/// @sa https://json.nlohmann.me/api/basic_json/at/ /// @sa https://json.nlohmann.me/api/basic_json/at/
@@ -6189,9 +6200,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_checked(this); return ptr.get_checked(this);
} }
#endif
/// @brief return flattened JSON value /// @brief return flattened JSON value
/// @sa https://json.nlohmann.me/api/basic_json/flatten/ /// @sa https://json.nlohmann.me/api/basic_json/flatten/
@@ -7168,6 +7183,18 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j)
return j.dump(); return j.dump();
} }
#if JSON_DELETE_DEPRECATED_FUNCTIONS && !defined(JSON_NO_IO)
/// @brief serialize to stream (deleted; use operator<<(std::ostream&, const basic_json&))
/// @sa https://json.nlohmann.me/api/operator_ltlt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::ostream& operator>>(const NLOHMANN_BASIC_JSON_TPL& j, std::ostream& o) = delete;
/// @brief deserialize from stream (deleted; use operator>>(std::istream&, basic_json&))
/// @sa https://json.nlohmann.me/api/operator_gtgt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::istream& operator<<(NLOHMANN_BASIC_JSON_TPL& j, std::istream& i) = delete;
#endif
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
/////////////////////// ///////////////////////
+288 -202
View File
@@ -3225,6 +3225,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP
#define JSON_DISABLE_ENUM_SERIALIZATION 0 #define JSON_DISABLE_ENUM_SERIALIZATION 0
#endif #endif
#ifndef JSON_DELETE_DEPRECATED_FUNCTIONS
#define JSON_DELETE_DEPRECATED_FUNCTIONS 0
#endif
#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION #ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
#endif #endif
@@ -4901,6 +4905,21 @@ T conditional_static_cast(U value)
return value; return value;
} }
// like conditional_static_cast, but converts to bool by comparing with zero,
// because MSVC 2015 warns about any conversion to bool (C4800), even with an
// explicit cast; used for enums whose underlying type is bool
template < typename T, typename U, enable_if_t < !std::is_same<T, bool>::value, int > = 0 >
T bool_aware_static_cast(U value)
{
return conditional_static_cast<T>(value);
}
template<typename T, typename U, enable_if_t<std::is_same<T, bool>::value, int> = 0>
bool bool_aware_static_cast(U value)
{
return value != U();
}
template<typename... Types> template<typename... Types>
using all_integral = conjunction<std::is_integral<Types>...>; using all_integral = conjunction<std::is_integral<Types>...>;
@@ -5696,7 +5715,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
typename BasicJsonType::number_unsigned_t, underlying_type>::type; typename BasicJsonType::number_unsigned_t, underlying_type>::type;
value_type val; value_type val;
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
e = static_cast<EnumType>(static_cast<underlying_type>(val)); e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -7062,9 +7081,20 @@ struct external_constructor<value_t::object>
///////////// /////////////
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
// whether storing the value of a std::optional<T> cannot throw; MSVC 2017
// evaluates std::is_nothrow_assignable as true even if T's to_json throws, so
// the exception would call std::terminate (#5642)
#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
template<typename BasicJsonType, typename T>
using is_nothrow_optional_to_json = std::false_type;
#else
template<typename BasicJsonType, typename T>
using is_nothrow_optional_to_json = std::is_nothrow_assignable<BasicJsonType&, const T&>;
#endif
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T,
enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0>
void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(std::is_nothrow_assignable<BasicJsonType&, const T&>::value) void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(is_nothrow_optional_to_json<BasicJsonType, T>::value)
{ {
if (opt.has_value()) if (opt.has_value())
{ {
@@ -7140,7 +7170,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept
{ {
using underlying_type = typename std::underlying_type<EnumType>::type; using underlying_type = typename std::underlying_type<EnumType>::type;
static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer; static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;
external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e)); external_constructor<integral_value_t>::construct(j, bool_aware_static_cast<underlying_type>(e));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -14349,10 +14379,11 @@ class binary_reader
} }
// the value is -1 - number, which fits into number_integer_t // the value is -1 - number, which fits into number_integer_t
// whenever number does // whenever number does; the outer cast undoes the integral promotion
// for number_integer_t types narrower than int
if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number))) if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number)))
{ {
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)); return sax->number_integer(conditional_static_cast<number_integer_t>(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)));
} }
// like the lexer does for JSON text, store a value too small for // like the lexer does for JSON text, store a value too small for
@@ -17690,7 +17721,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -17713,7 +17745,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -17724,7 +17757,8 @@ class binary_reader
and NaN in the input are passed on unchanged. Integers only overflow if and NaN in the input are passed on unchanged. Integers only overflow if
number_float_t cannot represent 2^64, e.g., a half-precision type. number_float_t cannot represent 2^64, e.g., a half-precision type.
@tparam NumberType a floating-point or integer type @tparam NumberType a floating-point type (emit_signed and emit_unsigned
convert integers to long double first)
@param[in] number the number @param[in] number the number
@return whether the SAX parser accepted the value @return whether the SAX parser accepted the value
@@ -19930,9 +19964,13 @@ class json_pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/ /// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
operator string_t() const operator string_t() const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return to_string(); return to_string();
} }
#endif
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
/// @brief write string representation of the JSON pointer to stream /// @brief write string representation of the JSON pointer to stream
@@ -20871,9 +20909,13 @@ class json_pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
bool operator==(const string_t& rhs) const bool operator==(const string_t& rhs) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return *this == json_pointer(rhs); return *this == json_pointer(rhs);
} }
#endif
/// @brief 3-way compares two JSON pointers /// @brief 3-way compares two JSON pointers
template<typename RefStringTypeRhs> template<typename RefStringTypeRhs>
@@ -20951,18 +20993,26 @@ template<typename RefStringTypeLhs,
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
const StringType& rhs) const StringType& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return lhs == json_pointer<RefStringTypeLhs>(rhs); return lhs == json_pointer<RefStringTypeLhs>(rhs);
} }
#endif
template<typename RefStringTypeRhs, template<typename RefStringTypeRhs,
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
inline bool operator==(const StringType& lhs, inline bool operator==(const StringType& lhs,
const json_pointer<RefStringTypeRhs>& rhs) const json_pointer<RefStringTypeRhs>& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return json_pointer<RefStringTypeRhs>(lhs) == rhs; return json_pointer<RefStringTypeRhs>(lhs) == rhs;
} }
#endif
template<typename RefStringTypeLhs, typename RefStringTypeRhs> template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
@@ -20976,18 +21026,26 @@ template<typename RefStringTypeLhs,
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
const StringType& rhs) const StringType& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
#endif
template<typename RefStringTypeRhs, template<typename RefStringTypeRhs,
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
inline bool operator!=(const StringType& lhs, inline bool operator!=(const StringType& lhs,
const json_pointer<RefStringTypeRhs>& rhs) const json_pointer<RefStringTypeRhs>& rhs)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
#endif
template<typename RefStringTypeLhs, typename RefStringTypeRhs> template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs, inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
@@ -27734,208 +27792,100 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// constructor for rvalue binary arrays (internal type) /// constructor for rvalue binary arrays (internal type)
json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {} json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
// raw, allocation-free transfer of m_data from src to dst: no void destroy(value_t t)
// set_parents()/assert_invariant() (the former is O(#children) per
// call under JSON_DIAGNOSTICS, which would make the walk below
// quadratic); dst takes ownership, src is left as value_t::null.
static void take(basic_json& dst, basic_json& src) noexcept
{
dst.m_data.m_type = src.m_data.m_type;
dst.m_data.m_value = src.m_data.m_value;
src.m_data.m_type = value_t::null;
}
// true if v is not an array/object, or is an already-empty one
static bool has_no_children(const basic_json& v) noexcept
{
switch (v.m_data.m_type)
{
case value_t::array:
return v.m_data.m_value.array->empty();
case value_t::object:
return v.m_data.m_value.object->empty();
default:
return true;
}
}
static basic_json& last_child(basic_json& v)
{
if (v.m_data.m_type == value_t::array)
{
return v.m_data.m_value.array->back();
}
JSON_ASSERT(v.m_data.m_type == value_t::object);
return v.m_data.m_value.object->rbegin()->second;
}
// removes the last child of a non-empty array/object v; this never
// allocates, and since it is only ever called when that child is a
// scalar or an already-empty array/object, destroying it never
// recurses more than one level deep (see destroy() below)
static void pop_last_child(basic_json& v)
{
if (v.m_data.m_type == value_t::array)
{
v.m_data.m_value.array->pop_back();
}
else
{
JSON_ASSERT(v.m_data.m_type == value_t::object);
// erase() needs a forward iterator, so std::prev(end()) is
// used here rather than rbegin() (see last_child() above)
v.m_data.m_value.object->erase(std::prev(v.m_data.m_value.object->end()));
}
}
// deallocates the (already empty) array/object held by v; this is
// the same allocator-based free the old recursive implementation
// used, just factored out so every level of the walk in destroy()
// can share it
static void free_container(basic_json& v) noexcept
{
if (v.m_data.m_type == value_t::array)
{
JSON_ASSERT(v.m_data.m_value.array->empty());
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, v.m_data.m_value.array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, v.m_data.m_value.array, 1);
}
else
{
JSON_ASSERT(v.m_data.m_type == value_t::object);
JSON_ASSERT(v.m_data.m_value.object->empty());
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, v.m_data.m_value.object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, v.m_data.m_value.object, 1);
}
v.m_data.m_type = value_t::null; // avoid a double free if v is later destructed
}
void destroy_string() noexcept
{
if (string == nullptr)
{
// not initialized (e.g., due to exception in the ctor)
return;
}
AllocatorType<string_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
}
void destroy_binary() noexcept
{
if (binary == nullptr)
{
// not initialized (e.g., due to exception in the ctor)
return;
}
AllocatorType<binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
}
// t must be value_t::array or value_t::object
void destroy_container(value_t t) noexcept
{ {
if ( if (
(t == value_t::object && object == nullptr) || (t == value_t::object && object == nullptr) ||
(t == value_t::array && array == nullptr) (t == value_t::array && array == nullptr) ||
(t == value_t::string && string == nullptr) ||
(t == value_t::binary && binary == nullptr)
) )
{ {
// not initialized (e.g., due to exception in the ctor) // not initialized (e.g., due to exception in the ctor)
return; return;
} }
if (t == value_t::array || t == value_t::object)
// Destroy the tree without recursing per nesting level and
// without any heap allocation: a heap-allocated flattening
// stack (the previous implementation) can itself throw
// bad_alloc, which would escape this noexcept destructor and
// terminate the program (#5135).
//
// Instead, walk down the "last child" chain, reversing links
// as we go: cur is the container currently being emptied,
// and prev is its parent (value_t::null when there is none).
// Each parent's last child slot doubles as storage for that
// parent's own parent link while we are below it, so no
// extra memory is needed. We only ever remove a child once
// it is a scalar or an empty array/object, which neither
// allocates nor recurses more than one level deep.
//
// This json_value is not itself a basic_json, so the
// top-level container is first moved into a local stand-in
// ("cur"); a default-constructed basic_json has a null
// pointer in its m_value (see data::m_value's initializer),
// so swapping it with *this leaves this union's own pointer
// null, and it is never looked at or freed a second time.
basic_json cur;
cur.m_data.m_type = t;
using std::swap;
swap(cur.m_data.m_value, *this);
basic_json prev; // value_t::null: no parent
while (true)
{ {
if (has_no_children(cur)) // flatten the current json_value to a heap-allocated stack
std::vector<basic_json> stack;
// move the top-level items to stack
if (t == value_t::array)
{ {
if (prev.m_data.m_type == value_t::null) stack.reserve(array->size());
{ std::move(array->begin(), array->end(), std::back_inserter(stack));
free_container(cur);
return; // back at the top with nothing left to do
} }
else
// ascend: detach the grandparent link from prev's
// last slot, drop that (now null) slot, free cur
// (it is empty), then move up one level
basic_json gp;
take(gp, last_child(prev));
pop_last_child(prev);
free_container(cur);
take(cur, prev);
take(prev, gp);
continue;
}
basic_json& cur_last_ref = last_child(cur);
if (has_no_children(cur_last_ref))
{ {
// scalar, or already-empty array/object stack.reserve(object->size());
pop_last_child(cur); for (auto&& it : *object)
continue; {
} stack.push_back(std::move(it.second));
// descend into the non-empty last child, reversing the
// link: its slot takes over prev, and the child becomes
// the new cur
basic_json tmp;
take(tmp, cur_last_ref);
take(cur_last_ref, prev);
take(prev, cur);
take(cur, tmp);
} }
} }
void destroy(value_t t) while (!stack.empty())
{ {
// move the last item to a local variable to be processed
basic_json current_item(std::move(stack.back()));
stack.pop_back();
// if current_item is array/object, move
// its children to the stack to be processed later
if (current_item.is_array())
{
std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
current_item.m_data.m_value.array->clear();
}
else if (current_item.is_object())
{
for (auto&& it : *current_item.m_data.m_value.object)
{
stack.push_back(std::move(it.second));
}
current_item.m_data.m_value.object->clear();
}
// it's now safe that current_item gets destructed
// since it doesn't have any children
}
}
switch (t) switch (t)
{ {
case value_t::string: case value_t::object:
destroy_string(); {
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
break; break;
}
case value_t::array:
{
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
break;
}
case value_t::string:
{
AllocatorType<string_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
break;
}
case value_t::binary: case value_t::binary:
destroy_binary(); {
break; AllocatorType<binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
case value_t::object: std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
case value_t::array:
destroy_container(t);
break; break;
}
case value_t::null: case value_t::null:
case value_t::boolean: case value_t::boolean:
@@ -27944,9 +27894,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::number_float: case value_t::number_float:
case value_t::discarded: case value_t::discarded:
default: default:
{
break; break;
} }
} }
}
}; };
private: private:
@@ -30720,9 +30672,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return value(ptr.convert(), default_value); return value(ptr.convert(), default_value);
} }
#endif
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type, template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t < detail::enable_if_t <
@@ -30731,9 +30687,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return value(ptr.convert(), std::forward<ValueType>(default_value)); return value(ptr.convert(), std::forward<ValueType>(default_value));
} }
#endif
/// @brief access the first element /// @brief access the first element
/// @sa https://json.nlohmann.me/api/basic_json/front/ /// @sa https://json.nlohmann.me/api/basic_json/front/
@@ -31091,9 +31051,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.contains(this); return ptr.contains(this);
} }
#endif
/// @} /// @}
@@ -31204,9 +31168,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`. /// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ref.items(); return ref.items();
} }
#endif
/// @brief wrapper to access iterator member functions in range-based for /// @brief wrapper to access iterator member functions in range-based for
/// @sa https://json.nlohmann.me/api/basic_json/items/ /// @sa https://json.nlohmann.me/api/basic_json/items/
@@ -31215,9 +31183,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`. /// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ref.items(); return ref.items();
} }
#endif
/// @brief helper to access iterator member functions in range-based for /// @brief helper to access iterator member functions in range-based for
/// @sa https://json.nlohmann.me/api/basic_json/items/ /// @sa https://json.nlohmann.me/api/basic_json/items/
@@ -32306,7 +32278,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -32315,7 +32287,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -32336,11 +32308,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif #endif
} }
// The friend comparisons with a scalar name the JSON type via decltype of
// their parameter in noexcept, because older MSVC versions do not see the
// class scope there: MSVC 2015 and 2017 take basic_json as the template,
// and MSVC 2019 16.0 rejects member types and template parameters.
/// @brief comparison: equal /// @brief comparison: equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs == basic_json(rhs); return lhs == basic_json(rhs);
} }
@@ -32349,7 +32326,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) == rhs; return basic_json(lhs) == rhs;
} }
@@ -32365,7 +32342,7 @@ 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/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs != basic_json(rhs); return lhs != basic_json(rhs);
} }
@@ -32374,7 +32351,7 @@ 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/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) != rhs; return basic_json(lhs) != rhs;
} }
@@ -32394,7 +32371,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs < basic_json(rhs); return lhs < basic_json(rhs);
} }
@@ -32403,7 +32380,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) < rhs; return basic_json(lhs) < rhs;
} }
@@ -32423,7 +32400,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs <= basic_json(rhs); return lhs <= basic_json(rhs);
} }
@@ -32432,7 +32409,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -32453,7 +32430,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs > basic_json(rhs); return lhs > basic_json(rhs);
} }
@@ -32462,7 +32439,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) > rhs; return basic_json(lhs) > rhs;
} }
@@ -32482,7 +32459,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs >= basic_json(rhs); return lhs >= basic_json(rhs);
} }
@@ -32491,7 +32468,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -32527,6 +32504,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return o; return o;
} }
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief serialize to stream /// @brief serialize to stream
/// @sa https://json.nlohmann.me/api/operator_ltlt/ /// @sa https://json.nlohmann.me/api/operator_ltlt/
/// @deprecated This function is deprecated since 3.0.0 and will be removed in /// @deprecated This function is deprecated since 3.0.0 and will be removed in
@@ -32538,6 +32518,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{ {
return o << j; return o << j;
} }
#endif
#endif // JSON_NO_IO #endif // JSON_NO_IO
/// @} /// @}
@@ -32589,12 +32570,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool allow_exceptions = true, const bool allow_exceptions = true,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
basic_json result; basic_json result;
auto p = parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas); auto p = parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
p.parse(true, result); p.parse(true, result);
return result; return result;
} }
#endif
/// @brief check if the input is valid JSON /// @brief check if the input is valid JSON
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
@@ -32624,9 +32609,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static bool accept(detail::span_input_adapter&& i, static bool accept(detail::span_input_adapter&& i,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true); return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
} }
#endif
/// @brief generate SAX events /// @brief generate SAX events
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
@@ -32687,6 +32676,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool strict = true, const bool strict = true,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
auto ia = i.get(); auto ia = i.get();
return format == input_format_t::json return format == input_format_t::json
@@ -32695,10 +32687,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
} }
#endif
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief deserialize from stream /// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @sa https://json.nlohmann.me/api/operator_gtgt/
/// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
@@ -32710,6 +32706,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{ {
return operator>>(i, j); return operator>>(i, j);
} }
#endif
/// @brief deserialize from stream /// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @sa https://json.nlohmann.me/api/operator_gtgt/
@@ -33057,9 +33054,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
@@ -33067,9 +33068,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler); return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler);
} }
#endif
/// @brief create a JSON value from an input in MessagePack format /// @brief create a JSON value from an input in MessagePack format
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
@@ -33102,18 +33107,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static basic_json from_msgpack(const T* ptr, std::size_t len, static basic_json from_msgpack(const T* ptr, std::size_t len,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_msgpack(ptr, ptr + len, strict, allow_exceptions); return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
static basic_json from_msgpack(detail::span_input_adapter&& i, static basic_json from_msgpack(detail::span_input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions); return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions);
} }
#endif
/// @brief create a JSON value from an input in UBJSON format /// @brief create a JSON value from an input in UBJSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
@@ -33146,18 +33159,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static basic_json from_ubjson(const T* ptr, std::size_t len, static basic_json from_ubjson(const T* ptr, std::size_t len,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_ubjson(ptr, ptr + len, strict, allow_exceptions); return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
static basic_json from_ubjson(detail::span_input_adapter&& i, static basic_json from_ubjson(detail::span_input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions); return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions);
} }
#endif
/// @brief create a JSON value from an input in BJData format /// @brief create a JSON value from an input in BJData format
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
@@ -33184,6 +33205,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler);
} }
template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len))
static basic_json from_bjdata(const T* ptr, std::size_t len,
const bool strict = true,
const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{
return from_bjdata(ptr, ptr + len, strict, allow_exceptions);
}
#endif
/// @brief create a JSON value from an input in BON8 format /// @brief create a JSON value from an input in BON8 format
/// @sa https://json.nlohmann.me/api/basic_json/from_bon8/ /// @sa https://json.nlohmann.me/api/basic_json/from_bon8/
template<typename InputType> template<typename InputType>
@@ -33207,6 +33242,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions); return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions);
} }
template<typename T>
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len))
static basic_json from_bon8(const T* ptr, std::size_t len,
const bool strict = true,
const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{
return from_bon8(ptr, ptr + len, strict, allow_exceptions);
}
#endif
/// @brief create a JSON value from an input in BSON format /// @brief create a JSON value from an input in BSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/ /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
template<typename InputType> template<typename InputType>
@@ -33238,18 +33287,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static basic_json from_bson(const T* ptr, std::size_t len, static basic_json from_bson(const T* ptr, std::size_t len,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_bson(ptr, ptr + len, strict, allow_exceptions); return from_bson(ptr, ptr + len, strict, allow_exceptions);
} }
#endif
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
static basic_json from_bson(detail::span_input_adapter&& i, static basic_json from_bson(detail::span_input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions); return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions);
} }
#endif
/// @} /// @}
////////////////////////// //////////////////////////
@@ -33269,9 +33326,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
#endif
/// @brief access specified element via JSON Pointer /// @brief access specified element via JSON Pointer
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
@@ -33283,9 +33344,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
#endif
/// @brief access specified element via JSON Pointer /// @brief access specified element via JSON Pointer
/// @sa https://json.nlohmann.me/api/basic_json/at/ /// @sa https://json.nlohmann.me/api/basic_json/at/
@@ -33297,9 +33362,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_checked(this); return ptr.get_checked(this);
} }
#endif
/// @brief access specified element via JSON Pointer /// @brief access specified element via JSON Pointer
/// @sa https://json.nlohmann.me/api/basic_json/at/ /// @sa https://json.nlohmann.me/api/basic_json/at/
@@ -33311,9 +33380,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return ptr.get_checked(this); return ptr.get_checked(this);
} }
#endif
/// @brief return flattened JSON value /// @brief return flattened JSON value
/// @sa https://json.nlohmann.me/api/basic_json/flatten/ /// @sa https://json.nlohmann.me/api/basic_json/flatten/
@@ -34290,6 +34363,18 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j)
return j.dump(); return j.dump();
} }
#if JSON_DELETE_DEPRECATED_FUNCTIONS && !defined(JSON_NO_IO)
/// @brief serialize to stream (deleted; use operator<<(std::ostream&, const basic_json&))
/// @sa https://json.nlohmann.me/api/operator_ltlt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::ostream& operator>>(const NLOHMANN_BASIC_JSON_TPL& j, std::ostream& o) = delete;
/// @brief deserialize from stream (deleted; use operator>>(std::istream&, basic_json&))
/// @sa https://json.nlohmann.me/api/operator_gtgt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::istream& operator<<(NLOHMANN_BASIC_JSON_TPL& j, std::istream& i) = delete;
#endif
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
/////////////////////// ///////////////////////
@@ -34473,6 +34558,7 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
#undef JSON_PRECISE_STREAM_POSITION #undef JSON_PRECISE_STREAM_POSITION
#undef JSON_STRICT_NUL_HANDLING #undef JSON_STRICT_NUL_HANDLING
#undef JSON_STRICT_BINARY_UTF8 #undef JSON_STRICT_BINARY_UTF8
#undef JSON_DELETE_DEPRECATED_FUNCTIONS
#undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS #undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif #endif
+33
View File
@@ -8,6 +8,7 @@ set(JSON_SIMDUTF_VERSION 9.1.0 CACHE STRING "The simdutf version used by JSON_Te
set(JSON_32bitTest AUTO CACHE STRING "Enable the 32bit unit test (ON/OFF/AUTO/ONLY).") set(JSON_32bitTest AUTO CACHE STRING "Enable the 32bit unit test (ON/OFF/AUTO/ONLY).")
set(JSON_TestStandards "" CACHE STRING "The list of standards to test explicitly.") set(JSON_TestStandards "" CACHE STRING "The list of standards to test explicitly.")
set(JSON_TestShard "" CACHE STRING "Build only a part of the unit tests, given as <index>/<count> (e.g. 0/2), to split them across CI jobs with a time limit.")
# using an env var, since this will also affect targets executing cmake (such as "ci_test_compiler_default") # using an env var, since this will also affect targets executing cmake (such as "ci_test_compiler_default")
if (NOT "" STREQUAL "$ENV{JSON_FORCED_GLOBAL_COMPILE_OPTIONS}") if (NOT "" STREQUAL "$ENV{JSON_FORCED_GLOBAL_COMPILE_OPTIONS}")
@@ -288,6 +289,33 @@ elseif(NOT json_32bit_test)
list(FILTER files EXCLUDE REGEX src/unit-32bit.cpp) list(FILTER files EXCLUDE REGEX src/unit-32bit.cpp)
endif() endif()
# with JSON_TestShard=<index>/<count>, keep every <count>-th unit test file,
# starting at <index> (the glob is sorted, so the split is stable)
set(test_shard_index 0)
if(NOT "${JSON_TestShard}" STREQUAL "")
if(NOT JSON_TestShard MATCHES "^([0-9]+)/([1-9][0-9]*)$")
message(FATAL_ERROR "JSON_TestShard must be <index>/<count>, e.g. 0/2, not '${JSON_TestShard}'.")
endif()
set(test_shard_index ${CMAKE_MATCH_1})
set(test_shard_count ${CMAKE_MATCH_2})
if(NOT test_shard_index LESS test_shard_count)
message(FATAL_ERROR "JSON_TestShard: the index must be less than the count, not '${JSON_TestShard}'.")
endif()
list(LENGTH files test_file_count)
set(shard_files "")
set(file_position 0)
foreach(file ${files})
math(EXPR file_shard "${file_position} % ${test_shard_count}")
if(file_shard EQUAL test_shard_index)
list(APPEND shard_files ${file})
endif()
math(EXPR file_position "${file_position} + 1")
endforeach()
set(files ${shard_files})
list(LENGTH files shard_file_count)
message(STATUS "Test shard ${JSON_TestShard}: ${shard_file_count} of ${test_file_count} unit test files")
endif()
foreach(file ${files}) foreach(file ${files})
json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}) json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force})
endforeach() endforeach()
@@ -305,6 +333,9 @@ if(json_32bit_test_only)
return() return()
endif() endif()
# the following variants of single test files are only built in the first shard
if(test_shard_index EQUAL 0)
# test legacy comparison of discarded values # test legacy comparison of discarded values
json_test_set_test_options(test-comparison_legacy json_test_set_test_options(test-comparison_legacy
COMPILE_DEFINITIONS JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1 COMPILE_DEFINITIONS JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1
@@ -332,6 +363,8 @@ json_test_add_test_for(src/unit-diagnostic-positions.cpp
MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}
) )
endif()
# *DO NOT* use json_test_set_test_options() below this line # *DO NOT* use json_test_set_test_options() below this line
############################################################################# #############################################################################
+5 -85
View File
@@ -521,6 +521,10 @@ struct countdown_allocator : std::allocator<T>
TEST_CASE("converting a deeply nested value from another specialization fails cleanly (#5650)") TEST_CASE("converting a deeply nested value from another specialization fails cleanly (#5650)")
{ {
// MSVC 2015's debug STL constructs the containers' debug proxies through
// the allocator in noexcept constructors, so a failing construction crashes
// the program there instead of throwing std::bad_alloc. Nothing to check.
#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
using countdown_json = nlohmann::basic_json<std::map, using countdown_json = nlohmann::basic_json<std::map,
std::vector, std::vector,
std::string, std::string,
@@ -558,6 +562,7 @@ TEST_CASE("converting a deeply nested value from another specialization fails cl
} }
} }
CHECK(failures > 0); CHECK(failures > 0);
#endif
} }
namespace namespace
@@ -602,88 +607,3 @@ TEST_CASE("bad my_allocator::construct")
j["test"].push_back("should not leak"); j["test"].push_back("should not leak");
} }
} }
namespace
{
std::size_t counting_allocator_allocations = 0;
std::size_t counting_allocator_deallocations = 0;
template<class T>
struct counting_allocator : std::allocator<T>
{
using std::allocator<T>::allocator;
T* allocate(std::size_t n)
{
++counting_allocator_allocations;
return std::allocator<T>::allocate(n);
}
void deallocate(T* p, std::size_t n)
{
++counting_allocator_deallocations;
std::allocator<T>::deallocate(p, n);
}
template <class U>
struct rebind
{
using other = counting_allocator<U>;
};
};
} // namespace
TEST_CASE("destructor performs no allocation, only deallocation")
{
// see https://github.com/nlohmann/json/issues/4842 and
// https://github.com/nlohmann/json/issues/5135: destroying nested
// arrays/objects used to allocate a temporary stack (first with
// std::allocator, later - after #4842 - with the provided allocator).
// Since that stack could itself throw bad_alloc from inside the
// noexcept destructor (#5135), destroy() no longer allocates anything:
// it only ever frees what is already there.
using counting_json = nlohmann::basic_json<std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
counting_allocator>;
SECTION("array")
{
auto* j = new counting_json({1, {2, {3, 4}}, 5}); // NOLINT(cppcoreguidelines-owning-memory)
const auto allocations_before = counting_allocator_allocations;
const auto deallocations_before = counting_allocator_deallocations;
delete j; // NOLINT(cppcoreguidelines-owning-memory)
CHECK(counting_allocator_allocations == allocations_before);
CHECK(counting_allocator_deallocations > deallocations_before);
}
SECTION("object")
{
auto* j = new counting_json({{"a", {{"b", {1, 2}}}}, {"c", 3}}); // NOLINT(cppcoreguidelines-owning-memory)
const auto allocations_before = counting_allocator_allocations;
const auto deallocations_before = counting_allocator_deallocations;
delete j; // NOLINT(cppcoreguidelines-owning-memory)
CHECK(counting_allocator_allocations == allocations_before);
CHECK(counting_allocator_deallocations > deallocations_before);
}
SECTION("mixed tree of empty/non-empty arrays and objects")
{
auto* j = new counting_json( // NOLINT(cppcoreguidelines-owning-memory)
{
{"empty_obj", counting_json::object()},
{"empty_arr", counting_json::array()},
{"nested", {{"a", counting_json::array({1, 2, counting_json::object()})}, {"b", 3}}},
{"tail", counting_json::array({counting_json::array({1}), 2, counting_json::array({3})})}
});
const auto allocations_before = counting_allocator_allocations;
const auto deallocations_before = counting_allocator_deallocations;
delete j; // NOLINT(cppcoreguidelines-owning-memory)
CHECK(counting_allocator_allocations == allocations_before);
CHECK(counting_allocator_deallocations > deallocations_before);
}
}
+38
View File
@@ -9,6 +9,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
#define JSON_TESTS_PRIVATE #define JSON_TESTS_PRIVATE
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
@@ -4490,3 +4498,33 @@ TEST_CASE("BJData roundtrips" * doctest::skip())
} }
} }
} }
TEST_CASE("issue #5648 - from_bjdata(ptr, len) must read len bytes, not treat ptr as a C string")
{
// to_bjdata() encodes the integer 0 as the two bytes 'i' 0x00 (a BJData
// type marker followed by the value byte 0x00), so the packed data
// below contains a 0x00 byte before its end.
const json j = {{"a", 0}};
const std::vector<std::uint8_t> packed = json::to_bjdata(j);
bool contains_nul = false;
for (const auto byte : packed)
{
contains_nul |= (byte == 0x00);
}
REQUIRE(contains_nul);
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
// before the fix, from_bjdata had no (ptr, len) overload, so this call
// bound to from_bjdata(InputType&&, bool strict) instead: ptr was read
// as a NUL-terminated C string (stopping at the embedded 0x00 byte), and
// len was silently converted to the strict flag. The deprecated
// overload added for this issue forwards to from_bjdata(ptr, ptr + len,
// ...) instead, like from_ubjson's deprecated (ptr, len) overload does.
json result;
CHECK_NOTHROW(result = json::from_bjdata(packed.data(), packed.size()));
CHECK(result == j);
// len must not collapse into the strict flag either
CHECK(json::from_bjdata(packed.data(), packed.size(), false) == j);
#endif
}
+38
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
@@ -1014,6 +1022,36 @@ TEST_CASE("BON8 roundtrips" * doctest::skip())
} }
} }
TEST_CASE("issue #5648 - from_bon8(ptr, len) must read len bytes, not treat ptr as a C string")
{
// to_bon8() encodes the integer 40 as the two bytes 0xC2 0x00 (a BON8
// lead byte followed by a continuation byte of 0x00), so the packed data
// below contains a 0x00 byte before its end.
const json j = {{"a", 40}, {"b", "x"}};
const std::vector<std::uint8_t> packed = json::to_bon8(j);
bool contains_nul = false;
for (const auto byte : packed)
{
contains_nul |= (byte == 0x00);
}
REQUIRE(contains_nul);
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
// before the fix, from_bon8 had no (ptr, len) overload, so this call
// bound to from_bon8(InputType&&, bool strict) instead: ptr was read as
// a NUL-terminated C string (stopping at the embedded 0x00 byte), and
// len was silently converted to the strict flag. The deprecated
// overload added for this issue forwards to from_bon8(ptr, ptr + len,
// ...) instead, like from_cbor's deprecated (ptr, len) overload does.
json result;
CHECK_NOTHROW(result = json::from_bon8(packed.data(), packed.size()));
CHECK(result == j);
// len must not collapse into the strict flag either
CHECK(json::from_bon8(packed.data(), packed.size(), false) == j);
#endif
}
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
TEST_CASE("BON8 with std::byte") TEST_CASE("BON8 with std::byte")
{ {
+12
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
@@ -1261,8 +1269,10 @@ TEST_CASE("BSON input that cannot be read is discarded by every overload")
CHECK_THROWS_AS(_ = json::from_bson(input.begin(), input.end()), json::parse_error&); CHECK_THROWS_AS(_ = json::from_bson(input.begin(), input.end()), json::parse_error&);
CHECK(json::from_bson(input, true, false).is_discarded()); CHECK(json::from_bson(input, true, false).is_discarded());
CHECK(json::from_bson(input.begin(), input.end(), true, false).is_discarded()); CHECK(json::from_bson(input.begin(), input.end(), true, false).is_discarded());
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
CHECK(json::from_bson(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_bson(input.data(), input.size(), true, false).is_discarded());
CHECK(json::from_bson({input.data(), input.size()}, true, false).is_discarded()); CHECK(json::from_bson({input.data(), input.size()}, true, false).is_discarded());
#endif
} }
TEST_CASE("BSON SAX parsing stops at every event") TEST_CASE("BSON SAX parsing stops at every event")
@@ -1740,6 +1750,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
{ {
INFO_WITH_TEMP(filename + ": uint8_t* and size"); INFO_WITH_TEMP(filename + ": uint8_t* and size");
// parse JSON file // parse JSON file
@@ -1754,6 +1765,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
// compare parsed JSON values // compare parsed JSON values
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#endif
{ {
INFO_WITH_TEMP(filename + ": output to output adapters"); INFO_WITH_TEMP(filename + ": output to output adapters");
+12
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
@@ -2215,8 +2223,10 @@ TEST_CASE("CBOR input that cannot be read is discarded by every overload")
CHECK_THROWS_AS(_ = json::from_cbor(input.begin(), input.end()), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(input.begin(), input.end()), json::parse_error&);
CHECK(json::from_cbor(input, true, false).is_discarded()); CHECK(json::from_cbor(input, true, false).is_discarded());
CHECK(json::from_cbor(input.begin(), input.end(), true, false).is_discarded()); CHECK(json::from_cbor(input.begin(), input.end(), true, false).is_discarded());
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
CHECK(json::from_cbor(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_cbor(input.data(), input.size(), true, false).is_discarded());
CHECK(json::from_cbor({input.data(), input.size()}, true, false).is_discarded()); CHECK(json::from_cbor({input.data(), input.size()}, true, false).is_discarded());
#endif
// a string that ends early, read through iterators that are not // a string that ends early, read through iterators that are not
// contiguous and have to be copied from one element at a time // contiguous and have to be copied from one element at a time
@@ -2613,12 +2623,14 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
{ {
INFO_WITH_TEMP(filename + ": uint8_t* and size"); INFO_WITH_TEMP(filename + ": uint8_t* and size");
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()})); CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()}));
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#endif
{ {
INFO_WITH_TEMP(filename + ": output to output adapters"); INFO_WITH_TEMP(filename + ": output to output adapters");
+7 -2
View File
@@ -191,8 +191,10 @@ TEST_CASE("value conversion")
{ {
enum class bool_enum : bool { off, on }; enum class bool_enum : bool { off, on };
CHECK(json(bool_enum::off).get<bool_enum>() == bool_enum::off); // the extra parentheses keep doctest from printing the enum via its
CHECK(json(bool_enum::on).get<bool_enum>() == bool_enum::on); // underlying type, which MSVC 2015 reports as C4800
CHECK((json(bool_enum::off).get<bool_enum>() == bool_enum::off));
CHECK((json(bool_enum::on).get<bool_enum>() == bool_enum::on));
} }
#endif #endif
@@ -851,8 +853,11 @@ TEST_CASE("std::optional")
CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&); CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&);
// the conversion is noexcept exactly when converting the contained value is // the conversion is noexcept exactly when converting the contained value is
// (except with MSVC 2017, where it is never noexcept, see to_json.hpp)
#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1920
static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value); static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value);
static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value); static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value);
#endif
} }
#endif #endif
} }
@@ -0,0 +1,229 @@
// __ _____ _____ _____
// __| | __| | | | 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_DELETE_DEPRECATED_FUNCTIONS, so it defines the
// macro itself instead of relying on the build configuration.
#ifdef JSON_DELETE_DEPRECATED_FUNCTIONS
#undef JSON_DELETE_DEPRECATED_FUNCTIONS
#endif
#define JSON_DELETE_DEPRECATED_FUNCTIONS 1
#include <nlohmann/json.hpp>
using nlohmann::json;
#include <cstddef>
#include <cstdint>
#include <istream>
#include <ostream>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
namespace
{
template<typename...>
struct make_void
{
using type = void;
};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
// A deleted function is still found by overload resolution, but naming it in an
// unevaluated operand is ill-formed, so each of the following traits is false
// exactly if the expression selects a deleted (or no) function.
#define JSON_TEST_DETECT(name, expr) \
template<typename J, typename = void> \
struct name : std::false_type {}; \
template<typename J> \
struct name<J, void_t<decltype(expr)>> : std::true_type {}
using ptr_t = const std::uint8_t*;
JSON_TEST_DETECT(from_cbor_ptr_len, J::from_cbor(std::declval<ptr_t>(), std::declval<std::size_t>()));
JSON_TEST_DETECT(from_msgpack_ptr_len, J::from_msgpack(std::declval<ptr_t>(), std::declval<std::size_t>()));
JSON_TEST_DETECT(from_ubjson_ptr_len, J::from_ubjson(std::declval<ptr_t>(), std::declval<std::size_t>()));
JSON_TEST_DETECT(from_bjdata_ptr_len, J::from_bjdata(std::declval<ptr_t>(), std::declval<std::size_t>()));
JSON_TEST_DETECT(from_bon8_ptr_len, J::from_bon8(std::declval<ptr_t>(), std::declval<std::size_t>()));
JSON_TEST_DETECT(from_bson_ptr_len, J::from_bson(std::declval<ptr_t>(), std::declval<std::size_t>()));
JSON_TEST_DETECT(from_cbor_ptr_ptr, J::from_cbor(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(from_msgpack_ptr_ptr, J::from_msgpack(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(from_ubjson_ptr_ptr, J::from_ubjson(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(from_bjdata_ptr_ptr, J::from_bjdata(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(from_bon8_ptr_ptr, J::from_bon8(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(from_bson_ptr_ptr, J::from_bson(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(from_cbor_init_list, J::from_cbor({std::declval<ptr_t>(), std::declval<std::size_t>()}));
JSON_TEST_DETECT(from_msgpack_init_list, J::from_msgpack({std::declval<ptr_t>(), std::declval<std::size_t>()}));
JSON_TEST_DETECT(from_ubjson_init_list, J::from_ubjson({std::declval<ptr_t>(), std::declval<std::size_t>()}));
JSON_TEST_DETECT(from_bson_init_list, J::from_bson({std::declval<ptr_t>(), std::declval<std::size_t>()}));
JSON_TEST_DETECT(parse_init_list, J::parse({std::declval<ptr_t>(), std::declval<std::size_t>()}));
JSON_TEST_DETECT(accept_init_list, J::accept({std::declval<ptr_t>(), std::declval<std::size_t>()}));
JSON_TEST_DETECT(sax_parse_init_list, J::sax_parse({std::declval<ptr_t>(), std::declval<std::size_t>()}, std::declval<nlohmann::json_sax<J>*>()));
JSON_TEST_DETECT(parse_ptr_ptr, J::parse(std::declval<ptr_t>(), std::declval<ptr_t>()));
JSON_TEST_DETECT(iterator_wrapper, J::iterator_wrapper(std::declval<J&>()));
JSON_TEST_DETECT(iterator_wrapper_const, J::iterator_wrapper(std::declval<const J&>()));
JSON_TEST_DETECT(items, std::declval<J&>().items());
JSON_TEST_DETECT(json_ltlt_istream, std::declval<J&>() << std::declval<std::istream&>());
JSON_TEST_DETECT(istream_gtgt_json, std::declval<std::istream&>() >> std::declval<J&>());
JSON_TEST_DETECT(json_gtgt_ostream, std::declval<const J&>() >> std::declval<std::ostream&>());
JSON_TEST_DETECT(ostream_ltlt_json, std::declval<std::ostream&>() << std::declval<const J&>());
JSON_TEST_DETECT(ptr_eq_ptr, std::declval<const typename J::json_pointer&>() == std::declval<const typename J::json_pointer&>());
JSON_TEST_DETECT(ptr_ne_ptr, std::declval<const typename J::json_pointer&>() != std::declval<const typename J::json_pointer&>());
JSON_TEST_DETECT(ptr_eq_string, std::declval<const typename J::json_pointer&>() == std::declval<const std::string&>());
JSON_TEST_DETECT(string_eq_ptr, std::declval<const std::string&>() == std::declval<const typename J::json_pointer&>());
JSON_TEST_DETECT(ptr_eq_c_string, std::declval<const typename J::json_pointer&>() == std::declval<const char*>());
JSON_TEST_DETECT(c_string_eq_ptr, std::declval<const char*>() == std::declval<const typename J::json_pointer&>());
JSON_TEST_DETECT(ptr_ne_string, std::declval<const typename J::json_pointer&>() != std::declval<const std::string&>());
JSON_TEST_DETECT(string_ne_ptr, std::declval<const std::string&>() != std::declval<const typename J::json_pointer&>());
JSON_TEST_DETECT(ptr_to_string, std::declval<const typename J::json_pointer&>().to_string());
// json_pointer with a basic_json type as template argument
template<typename J>
using legacy_ptr_t = const nlohmann::json_pointer<J>& ;
JSON_TEST_DETECT(legacy_ptr_value, std::declval<const J&>().value(std::declval<legacy_ptr_t<J>>(), 0));
JSON_TEST_DETECT(legacy_ptr_value_rvalue, std::declval<const J&>().value(std::declval<legacy_ptr_t<J>>(), std::string()));
JSON_TEST_DETECT(legacy_ptr_contains, std::declval<const J&>().contains(std::declval<legacy_ptr_t<J>>()));
JSON_TEST_DETECT(legacy_ptr_subscript, std::declval<J&>()[std::declval<legacy_ptr_t<J>>()]);
JSON_TEST_DETECT(legacy_ptr_subscript_const, std::declval<const J&>()[std::declval<legacy_ptr_t<J>>()]);
JSON_TEST_DETECT(legacy_ptr_at, std::declval<J&>().at(std::declval<legacy_ptr_t<J>>()));
JSON_TEST_DETECT(legacy_ptr_at_const, std::declval<const J&>().at(std::declval<legacy_ptr_t<J>>()));
JSON_TEST_DETECT(ptr_value, std::declval<const J&>().value(std::declval<const typename J::json_pointer&>(), 0));
JSON_TEST_DETECT(ptr_at, std::declval<J&>().at(std::declval<const typename J::json_pointer&>()));
#undef JSON_TEST_DETECT
} // namespace
TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS")
{
// MSVC 2015 does not treat selecting a deleted function in decltype as a
// substitution failure, so the traits cannot tell deleted functions apart
// there; calling them still fails to compile
#if !(defined(_MSC_VER) && _MSC_VER < 1910)
SECTION("from_* with a pointer and a length")
{
// the overloads are deleted rather than removed, so the length cannot
// silently bind to the strict parameter of from_*(InputType&&, bool)
CHECK_FALSE(from_cbor_ptr_len<json>::value);
CHECK_FALSE(from_msgpack_ptr_len<json>::value);
CHECK_FALSE(from_ubjson_ptr_len<json>::value);
CHECK_FALSE(from_bjdata_ptr_len<json>::value);
CHECK_FALSE(from_bon8_ptr_len<json>::value);
CHECK_FALSE(from_bson_ptr_len<json>::value);
// the replacement
CHECK(from_cbor_ptr_ptr<json>::value);
CHECK(from_msgpack_ptr_ptr<json>::value);
CHECK(from_ubjson_ptr_ptr<json>::value);
CHECK(from_bjdata_ptr_ptr<json>::value);
CHECK(from_bon8_ptr_ptr<json>::value);
CHECK(from_bson_ptr_ptr<json>::value);
}
SECTION("initializer lists of a pointer and a length")
{
CHECK_FALSE(from_cbor_init_list<json>::value);
CHECK_FALSE(from_msgpack_init_list<json>::value);
CHECK_FALSE(from_ubjson_init_list<json>::value);
CHECK_FALSE(from_bson_init_list<json>::value);
CHECK_FALSE(parse_init_list<json>::value);
CHECK_FALSE(accept_init_list<json>::value);
CHECK_FALSE(sax_parse_init_list<json>::value);
// the replacement
CHECK(parse_ptr_ptr<json>::value);
}
SECTION("iterator_wrapper")
{
CHECK_FALSE(iterator_wrapper<json>::value);
CHECK_FALSE(iterator_wrapper_const<json>::value);
// the replacement
CHECK(items<json>::value);
}
SECTION("stream operators with reversed operands")
{
CHECK_FALSE(json_ltlt_istream<json>::value);
CHECK_FALSE(json_gtgt_ostream<json>::value);
// the replacement
CHECK(istream_gtgt_json<json>::value);
CHECK(ostream_ltlt_json<json>::value);
}
SECTION("json_pointer")
{
// conversion to a string
CHECK_FALSE(std::is_constructible<std::string, json::json_pointer>::value);
CHECK_FALSE(std::is_convertible<json::json_pointer, std::string>::value);
// comparison with a string
CHECK_FALSE(ptr_eq_string<json>::value);
CHECK_FALSE(string_eq_ptr<json>::value);
CHECK_FALSE(ptr_eq_c_string<json>::value);
CHECK_FALSE(c_string_eq_ptr<json>::value);
CHECK_FALSE(ptr_ne_string<json>::value);
CHECK_FALSE(string_ne_ptr<json>::value);
// the replacement
CHECK(ptr_to_string<json>::value);
CHECK(ptr_eq_ptr<json>::value);
CHECK(ptr_ne_ptr<json>::value);
}
SECTION("json_pointer with a basic_json type as template argument")
{
CHECK_FALSE(legacy_ptr_value<json>::value);
CHECK_FALSE(legacy_ptr_value_rvalue<json>::value);
CHECK_FALSE(legacy_ptr_contains<json>::value);
CHECK_FALSE(legacy_ptr_subscript<json>::value);
CHECK_FALSE(legacy_ptr_subscript_const<json>::value);
CHECK_FALSE(legacy_ptr_at<json>::value);
CHECK_FALSE(legacy_ptr_at_const<json>::value);
// the replacement
CHECK(ptr_value<json>::value);
CHECK(ptr_at<json>::value);
}
#endif
SECTION("the non-deprecated functions still work")
{
const json j = {{"a", {1, 2}}};
const auto cbor = json::to_cbor(j);
CHECK(json::from_cbor(cbor.data(), cbor.data() + cbor.size()) == j);
const json::json_pointer ptr("/a/1");
CHECK(ptr == json::json_pointer("/a/1"));
CHECK(ptr.to_string() == "/a/1");
CHECK(j[ptr] == 2);
CHECK(j.at(ptr) == 2);
CHECK(j.value(ptr, 0) == 2);
CHECK(j.contains(ptr));
std::ostringstream os;
os << j;
CHECK(os.str() == R"({"a":[1,2]})");
std::istringstream is(os.str());
json parsed;
is >> parsed;
CHECK(parsed == j);
}
}
+14 -2
View File
@@ -16,6 +16,14 @@
#define JSON_TEST_STRICT_NUL_HANDLING_ENABLED 1 #define JSON_TEST_STRICT_NUL_HANDLING_ENABLED 1
#endif #endif
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
@@ -291,6 +299,7 @@ TEST_CASE("deserialization")
})); }));
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
SECTION("operator<<") SECTION("operator<<")
{ {
std::stringstream ss; std::stringstream ss;
@@ -299,6 +308,7 @@ TEST_CASE("deserialization")
j << ss; j << ss;
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
} }
#endif
SECTION("operator>>") SECTION("operator>>")
{ {
@@ -423,6 +433,7 @@ TEST_CASE("deserialization")
CHECK_THROWS_WITH_AS(_ = json::parse(nullptr), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::parse(nullptr), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
SECTION("operator<<") SECTION("operator<<")
{ {
std::stringstream ss; std::stringstream ss;
@@ -430,6 +441,7 @@ TEST_CASE("deserialization")
json j; json j;
CHECK_THROWS_WITH_AS(j << ss, "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); CHECK_THROWS_WITH_AS(j << ss, "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&);
} }
#endif
SECTION("operator>>") SECTION("operator>>")
{ {
@@ -1148,9 +1160,9 @@ TEST_CASE("deserialization")
{ {
std::istringstream s(bom + "123 456"); std::istringstream s(bom + "123 456");
json j; json j;
j << s; s >> j;
CHECK(j == 123); CHECK(j == 123);
j << s; s >> j;
CHECK(j == 456); CHECK(j == 456);
} }
} }
+5
View File
@@ -1551,6 +1551,10 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
// count(0) used to compile and then crash instead of failing to compile // count(0) used to compile and then crash instead of failing to compile
using nlohmann::detail::is_detected; using nlohmann::detail::is_detected;
// MSVC 2015 does not treat selecting a deleted function in decltype as
// a substitution failure, so it detects the deleted overloads as
// callable; calling them still fails to compile
#if !(defined(_MSC_VER) && _MSC_VER < 1910)
CHECK_FALSE(is_detected<can_call_find_with_0, Json&>::value); CHECK_FALSE(is_detected<can_call_find_with_0, Json&>::value);
CHECK_FALSE(is_detected<can_call_find_with_0, const Json&>::value); CHECK_FALSE(is_detected<can_call_find_with_0, const Json&>::value);
CHECK_FALSE(is_detected<can_call_count_with_0, Json&>::value); CHECK_FALSE(is_detected<can_call_count_with_0, Json&>::value);
@@ -1562,6 +1566,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
// another integral literal type must be rejected as well, not just int // another integral literal type must be rejected as well, not just int
CHECK_FALSE(is_detected<can_call_contains_with_0L, Json&>::value); CHECK_FALSE(is_detected<can_call_contains_with_0L, Json&>::value);
#endif
// the valid overloads must remain callable // the valid overloads must remain callable
CHECK(is_detected<can_call_find, Json&, const char*>::value); CHECK(is_detected<can_call_find, Json&, const char*>::value);
+10
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
@@ -19,6 +27,7 @@ DOCTEST_GCC_SUPPRESS_WARNING_PUSH
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
DOCTEST_CLANG_SUPPRESS_WARNING("-Wrange-loop-construct") DOCTEST_CLANG_SUPPRESS_WARNING("-Wrange-loop-construct")
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
TEST_CASE("iterator_wrapper") TEST_CASE("iterator_wrapper")
{ {
SECTION("object") SECTION("object")
@@ -715,6 +724,7 @@ TEST_CASE("iterator_wrapper")
} }
} }
} }
#endif
TEST_CASE("items()") TEST_CASE("items()")
{ {
+19 -4
View File
@@ -9,6 +9,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
#define JSON_TESTS_PRIVATE #define JSON_TESTS_PRIVATE
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
@@ -564,7 +572,9 @@ TEST_CASE("JSON pointers")
std::stringstream ss; std::stringstream ss;
ss << ptr; ss << ptr;
CHECK(ptr.to_string() == ptr_str); CHECK(ptr.to_string() == ptr_str);
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
CHECK(std::string(ptr) == ptr_str); CHECK(std::string(ptr) == ptr_str);
#endif
CHECK(ss.str() == ptr_str); CHECK(ss.str() == ptr_str);
} }
} }
@@ -744,8 +754,6 @@ TEST_CASE("JSON pointers")
SECTION("equality comparison") SECTION("equality comparison")
{ {
const char* ptr_cpstring = "/foo/bar";
const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
std::string ptr_string{"/foo/bar"}; std::string ptr_string{"/foo/bar"};
auto ptr1 = json::json_pointer(ptr_string); auto ptr1 = json::json_pointer(ptr_string);
auto ptr2 = json::json_pointer(ptr_string); auto ptr2 = json::json_pointer(ptr_string);
@@ -755,6 +763,12 @@ TEST_CASE("JSON pointers")
CHECK(ptr1 == ptr2); CHECK(ptr1 == ptr2);
CHECK_FALSE(ptr1 != ptr2);
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
const char* ptr_cpstring = "/foo/bar";
const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
CHECK(ptr1 == "/foo/bar"); CHECK(ptr1 == "/foo/bar");
CHECK(ptr1 == ptr_cpstring); CHECK(ptr1 == ptr_cpstring);
CHECK(ptr1 == ptr_castring); CHECK(ptr1 == ptr_castring);
@@ -765,8 +779,6 @@ TEST_CASE("JSON pointers")
CHECK(ptr_castring == ptr1); CHECK(ptr_castring == ptr1);
CHECK(ptr_string == ptr1); CHECK(ptr_string == ptr1);
CHECK_FALSE(ptr1 != ptr2);
CHECK_FALSE(ptr1 != "/foo/bar"); CHECK_FALSE(ptr1 != "/foo/bar");
CHECK_FALSE(ptr1 != ptr_cpstring); CHECK_FALSE(ptr1 != ptr_cpstring);
CHECK_FALSE(ptr1 != ptr_castring); CHECK_FALSE(ptr1 != ptr_castring);
@@ -788,6 +800,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_WITH_AS("/~~" == ptr1, CHECK_THROWS_WITH_AS("/~~" == ptr1,
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&);
} }
#endif
} }
SECTION("less-than comparison") SECTION("less-than comparison")
@@ -839,6 +852,7 @@ TEST_CASE("JSON pointers")
json_ptr_j ptr_j{ptr_string}; json_ptr_j ptr_j{ptr_string};
json_ptr_oj ptr_oj{ptr_string}; json_ptr_oj ptr_oj{ptr_string};
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
CHECK(j.contains(ptr)); CHECK(j.contains(ptr));
CHECK(j.contains(ptr_j)); CHECK(j.contains(ptr_j));
CHECK(j.contains(ptr_oj)); CHECK(j.contains(ptr_oj));
@@ -851,6 +865,7 @@ TEST_CASE("JSON pointers")
CHECK(j.value(ptr, "x") == j.value(ptr_j, "x")); CHECK(j.value(ptr, "x") == j.value(ptr_j, "x"));
CHECK(j.value(ptr, "x") == j.value(ptr_oj, "x")); CHECK(j.value(ptr, "x") == j.value(ptr_oj, "x"));
#endif
CHECK(ptr == ptr_j); CHECK(ptr == ptr_j);
CHECK(ptr == ptr_oj); CHECK(ptr == ptr_oj);
+12
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
@@ -1795,8 +1803,10 @@ TEST_CASE("MessagePack input that cannot be read is discarded by every overload"
CHECK_THROWS_AS(_ = json::from_msgpack(input.begin(), input.end()), json::parse_error&); CHECK_THROWS_AS(_ = json::from_msgpack(input.begin(), input.end()), json::parse_error&);
CHECK(json::from_msgpack(input, true, false).is_discarded()); CHECK(json::from_msgpack(input, true, false).is_discarded());
CHECK(json::from_msgpack(input.begin(), input.end(), true, false).is_discarded()); CHECK(json::from_msgpack(input.begin(), input.end(), true, false).is_discarded());
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
CHECK(json::from_msgpack(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_msgpack(input.data(), input.size(), true, false).is_discarded());
CHECK(json::from_msgpack({input.data(), input.size()}, true, false).is_discarded()); CHECK(json::from_msgpack({input.data(), input.size()}, true, false).is_discarded());
#endif
} }
TEST_CASE("MessagePack SAX parsing stops at every event") TEST_CASE("MessagePack SAX parsing stops at every event")
@@ -2099,12 +2109,14 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip())
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
{ {
INFO_WITH_TEMP(filename + ": uint8_t* and size"); INFO_WITH_TEMP(filename + ": uint8_t* and size");
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()})); CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()}));
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#endif
{ {
INFO_WITH_TEMP(filename + ": output to output adapters"); INFO_WITH_TEMP(filename + ": output to output adapters");
+1 -288
View File
@@ -40,9 +40,7 @@ using ordered_json = nlohmann::ordered_json;
#endif #endif
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <list> #include <list>
#include <new>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -109,84 +107,6 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>; using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
namespace
{
// An allocator whose allocate() can be told to fail on demand, so tests can
// check that ~basic_json() tolerates - in fact, after #5135, never even
// triggers - an allocation failure. This replaces an earlier version of
// this test that overrode the process-wide ::operator new/::operator
// delete, which affected every allocation in the whole unit-regression2
// binary rather than just the values under test.
std::size_t failing_allocator_allocations = 0;
std::size_t failing_allocator_deallocations = 0;
bool fail_next_allocation = false;
template<class T>
struct failing_allocator : std::allocator<T>
{
using std::allocator<T>::allocator;
failing_allocator() noexcept = default;
template<class U>
failing_allocator(const failing_allocator<U>& /*unused*/) noexcept {} // NOLINT(google-explicit-constructor)
T* allocate(std::size_t n)
{
if (fail_next_allocation)
{
fail_next_allocation = false;
throw std::bad_alloc();
}
++failing_allocator_allocations;
return std::allocator<T>::allocate(n);
}
void deallocate(T* p, std::size_t n)
{
++failing_allocator_deallocations;
std::allocator<T>::deallocate(p, n);
}
template<class U>
struct rebind
{
using other = failing_allocator<U>;
};
};
using failing_json = nlohmann::basic_json<std::map, std::vector, std::string, bool,
std::int64_t, std::uint64_t, double, failing_allocator>;
using failing_ordered_json = nlohmann::basic_json<nlohmann::ordered_map, std::vector, std::string, bool,
std::int64_t, std::uint64_t, double, failing_allocator>;
// builds `depth` levels of nesting around a scalar, iteratively (never
// recursing: each wrap only moves the previous, already-built value, which
// is O(1)), each level an array or an object depending on `nest_objects`
template<class BasicJsonType>
BasicJsonType make_deep_nest(std::size_t depth, bool nest_objects)
{
BasicJsonType v = 0;
for (std::size_t i = 0; i < depth; ++i)
{
if (nest_objects)
{
BasicJsonType wrapper = BasicJsonType::object();
wrapper["x"] = std::move(v);
v = std::move(wrapper);
}
else
{
BasicJsonType wrapper = BasicJsonType::array();
wrapper.push_back(std::move(v));
v = std::move(wrapper);
}
}
return v;
}
} // namespace
#endif
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// for #1647 // for #1647
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -649,7 +569,7 @@ TEST_CASE("regression tests 2")
SECTION("issue #2067 - cannot serialize binary data to text JSON") SECTION("issue #2067 - cannot serialize binary data to text JSON")
{ {
const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}}; const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}};
const json j = json::from_msgpack(data.data(), data.size()); const json j = json::from_msgpack(data.begin(), data.end());
// dump() is nodiscard; this only checks that dumping does not throw // dump() is nodiscard; this only checks that dumping does not throw
CHECK_NOTHROW( CHECK_NOTHROW(
utils::ignore_return_value( utils::ignore_return_value(
@@ -1020,211 +940,4 @@ TEST_CASE("regression test - excessive binary container size honors allow_except
CHECK(json::from_cbor(std::vector<std::uint8_t> {0x9b, 0, 0, 0, 0, 0, 0, 0, 0x02}, true, false).is_discarded()); CHECK(json::from_cbor(std::vector<std::uint8_t> {0x9b, 0, 0, 0, 0, 0, 0, 0, 0x02}, true, false).is_discarded());
} }
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
TEST_CASE("regression test #5135 - destructor never allocates, even under memory pressure")
{
// Before the fix, ~basic_json() flattened a nested array/object into a
// heap-allocated std::vector to avoid recursing; that allocation could
// itself throw bad_alloc, which escapes a noexcept destructor and
// terminates the program. destroy() no longer allocates anything, so
// none of the sections below ever observe fail_next_allocation being
// consumed: CHECK(fail_next_allocation) confirms it was never touched.
SECTION("the original report: a small, mixed array/object nest")
{
failing_allocator_allocations = 0;
failing_allocator_deallocations = 0;
{
failing_json j = failing_json::array(
{
failing_json::array({1, 2}),
failing_json::object({{"key", failing_json::array({3})}})
});
fail_next_allocation = true;
} // j is destroyed here, with every further allocation set to fail
CHECK(fail_next_allocation);
fail_next_allocation = false;
CHECK(failing_allocator_deallocations > 0);
}
SECTION("100000-deep nested array")
{
std::size_t allocations_before = 0;
{
failing_json j = make_deep_nest<failing_json>(100000, false);
allocations_before = failing_allocator_allocations;
fail_next_allocation = true;
}
CHECK(fail_next_allocation);
fail_next_allocation = false;
CHECK(failing_allocator_allocations == allocations_before);
}
SECTION("100000-deep nested object")
{
std::size_t allocations_before = 0;
{
failing_json j = make_deep_nest<failing_json>(100000, true);
allocations_before = failing_allocator_allocations;
fail_next_allocation = true;
}
CHECK(fail_next_allocation);
fail_next_allocation = false;
CHECK(failing_allocator_allocations == allocations_before);
}
SECTION("100000-deep nested ordered_json")
{
std::size_t allocations_before = 0;
{
failing_ordered_json j = make_deep_nest<failing_ordered_json>(100000, true);
allocations_before = failing_allocator_allocations;
fail_next_allocation = true;
}
CHECK(fail_next_allocation);
fail_next_allocation = false;
CHECK(failing_allocator_allocations == allocations_before);
}
SECTION("wide and deep: 1000 arrays of 1000 elements, each a small nested object")
{
std::size_t allocations_before = 0;
{
failing_json wide = failing_json::array();
for (std::size_t i = 0; i < 1000; ++i)
{
failing_json inner = failing_json::array();
for (std::size_t k = 0; k < 1000; ++k)
{
inner.push_back(failing_json::object({{"a", 1}, {"b", failing_json::array({1, 2, 3})}}));
}
wide.push_back(std::move(inner));
}
allocations_before = failing_allocator_allocations;
fail_next_allocation = true;
}
CHECK(fail_next_allocation);
fail_next_allocation = false;
CHECK(failing_allocator_allocations == allocations_before);
}
}
#endif
namespace
{
// a single-element chain of `depth` arrays, built iteratively (never
// recursing: each wrap only moves the previous, already-built value)
template<class BasicJsonType>
BasicJsonType make_single_chain(std::size_t depth)
{
BasicJsonType v = 1;
for (std::size_t i = 0; i < depth; ++i)
{
BasicJsonType wrapper = BasicJsonType::array();
wrapper.push_back(std::move(v));
v = std::move(wrapper);
}
return v;
}
// copies value first, to make sure nothing was corrupted by building it,
// then lets both the copy and the original destruct via normal scope exit
template<class BasicJsonType>
void check_destroy_edge_case(const BasicJsonType& value)
{
const BasicJsonType copy = value;
CHECK(copy == value);
}
} // namespace
TEST_CASE_TEMPLATE("regression test #5135 - destroy() edge cases", BasicJsonType, json, ordered_json)
{
using binary_t = typename BasicJsonType::binary_t;
SECTION("mix of empty objects, empty arrays, non-empty containers, and scalars")
{
BasicJsonType root = BasicJsonType::array();
root.push_back(BasicJsonType::object());
root.push_back(BasicJsonType::array());
root.push_back(BasicJsonType::object({{"k", 1}}));
root.push_back(BasicJsonType::array({1, 2, 3}));
root.push_back(nullptr);
root.push_back(true);
root.push_back(42);
root.push_back(3.14);
root.push_back("a string");
root.push_back(BasicJsonType(binary_t({1, 2, 3})));
check_destroy_edge_case(root);
}
SECTION("container child in first position only")
{
BasicJsonType root = BasicJsonType::array({BasicJsonType::array({1, 2}), 3, 4, 5});
check_destroy_edge_case(root);
}
SECTION("container child in last position only")
{
BasicJsonType root = BasicJsonType::array({1, 2, 3, BasicJsonType::array({4, 5})});
check_destroy_edge_case(root);
}
SECTION("container children in first and last position")
{
BasicJsonType root = BasicJsonType::array({BasicJsonType::array({1}), 2, 3, BasicJsonType::array({4})});
check_destroy_edge_case(root);
}
SECTION("single-element chain, 1000 levels deep")
{
BasicJsonType root = make_single_chain<BasicJsonType>(1000);
check_destroy_edge_case(root);
}
SECTION("top-level empty array")
{
BasicJsonType root = BasicJsonType::array();
check_destroy_edge_case(root);
}
SECTION("top-level empty object")
{
BasicJsonType root = BasicJsonType::object();
check_destroy_edge_case(root);
}
SECTION("object whose last child is a non-empty array whose last child is an empty object")
{
BasicJsonType inner_array = BasicJsonType::array({1, 2, BasicJsonType::object()});
BasicJsonType root = BasicJsonType::object({{"a", 1}, {"b", inner_array}});
check_destroy_edge_case(root);
}
SECTION("destruction via erase() on a deeply nested child")
{
BasicJsonType root = BasicJsonType::array();
root.push_back(make_single_chain<BasicJsonType>(500));
root.push_back(BasicJsonType::object({{"k", BasicJsonType::array({1, 2, 3})}}));
// erase() must destroy the removed subtree without recursing or
// allocating beyond what erase() itself needs
root.erase(0);
CAPTURE(root.size())
CHECK(root.size() == 1);
}
SECTION("destruction via assignment on a deep tree")
{
BasicJsonType root = make_single_chain<BasicJsonType>(2000);
// assigning a new value destroys the old one in place
root = nullptr;
CHECK(root.is_null());
}
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP DOCTEST_CLANG_SUPPRESS_WARNING_POP
+10
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
@@ -48,6 +56,7 @@ TEST_CASE("serialization")
} }
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
SECTION("operator>>") SECTION("operator>>")
{ {
SECTION("no given width") SECTION("no given width")
@@ -79,6 +88,7 @@ TEST_CASE("serialization")
"[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]"); "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]");
} }
} }
#endif
SECTION("dump") SECTION("dump")
{ {
+12
View File
@@ -8,6 +8,14 @@
#include "doctest_compatibility.h" #include "doctest_compatibility.h"
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
// line *before* including json.hpp, since the library #undefs it once the header
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
// tests of deprecated functions are skipped if these functions are deleted
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
@@ -2212,8 +2220,10 @@ TEST_CASE("UBJSON input that cannot be read is discarded by every overload")
CHECK_THROWS_AS(_ = json::from_ubjson(input.begin(), input.end()), json::parse_error&); CHECK_THROWS_AS(_ = json::from_ubjson(input.begin(), input.end()), json::parse_error&);
CHECK(json::from_ubjson(input, true, false).is_discarded()); CHECK(json::from_ubjson(input, true, false).is_discarded());
CHECK(json::from_ubjson(input.begin(), input.end(), true, false).is_discarded()); CHECK(json::from_ubjson(input.begin(), input.end(), true, false).is_discarded());
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
CHECK(json::from_ubjson(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_ubjson(input.data(), input.size(), true, false).is_discarded());
CHECK(json::from_ubjson({input.data(), input.size()}, true, false).is_discarded()); CHECK(json::from_ubjson({input.data(), input.size()}, true, false).is_discarded());
#endif
} }
TEST_CASE("UBJSON SAX parsing stops at every event") TEST_CASE("UBJSON SAX parsing stops at every event")
@@ -2961,12 +2971,14 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
{ {
INFO_WITH_TEMP(filename + ": uint8_t* and size"); INFO_WITH_TEMP(filename + ": uint8_t* and size");
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_ubjson({packed.data(), packed.size()})); CHECK_NOTHROW(j2 = json::from_ubjson({packed.data(), packed.size()}));
CHECK(j1 == j2); CHECK(j1 == j2);
} }
#endif
{ {
INFO_WITH_TEMP(filename + ": output to output adapters"); INFO_WITH_TEMP(filename + ": output to output adapters");