mirror of
https://github.com/nlohmann/json.git
synced 2026-09-09 17:58:00 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d027f06a42 |
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -369,7 +369,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -392,7 +392,7 @@ jobs:
|
||||
target: [ci_test_examples, ci_test_build_documentation]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef
|
||||
.PHONY: pretty clean ChangeLog.md release
|
||||
|
||||
##########################################################################
|
||||
# configuration
|
||||
@@ -41,8 +41,6 @@ all:
|
||||
@echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser"
|
||||
@echo "pretty - beautify code with Artistic Style"
|
||||
@echo "run_benchmarks - build and run benchmarks"
|
||||
@echo "update_hedley - download Hedley and regenerate hedley.hpp / hedley_undef.hpp"
|
||||
@echo "update_hedley_undef - rebuild hedley_undef.hpp from the JSON_HEDLEY_* #define names in hedley.hpp"
|
||||
|
||||
|
||||
##########################################################################
|
||||
@@ -243,24 +241,11 @@ update_hedley:
|
||||
rm -f include/nlohmann/thirdparty/hedley/hedley.hpp include/nlohmann/thirdparty/hedley/hedley_undef.hpp
|
||||
curl https://raw.githubusercontent.com/nemequ/hedley/master/hedley.h -o include/nlohmann/thirdparty/hedley/hedley.hpp
|
||||
$(SED) -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp
|
||||
grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | $(SED) 's/ //g' | $(SED) 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp
|
||||
$(SED) -i '1s/^/#pragma once\n\n/' include/nlohmann/thirdparty/hedley/hedley.hpp
|
||||
$(MAKE) update_hedley_undef
|
||||
$(SED) -i '1s/^/#pragma once\n\n/' include/nlohmann/thirdparty/hedley/hedley_undef.hpp
|
||||
$(MAKE) amalgamate
|
||||
|
||||
# Rebuild hedley_undef.hpp from every JSON_HEDLEY_* name that hedley.hpp
|
||||
# #defines. Hedley does not #undef all of its public macros internally (see
|
||||
# #5408), so grepping those #undef lines misses names such as
|
||||
# JSON_HEDLEY_PRAGMA. cmake/scripts/gen_hedley_undef_check.cmake is the
|
||||
# single source of truth for this extraction (tests/CMakeLists.txt uses the
|
||||
# same script, in MODE=checks, to generate the matching leak-check test), so
|
||||
# the vendored header, the generated #undef list, and the regression test
|
||||
# cannot drift apart.
|
||||
update_hedley_undef:
|
||||
cmake -DHEDLEY_HPP=include/nlohmann/thirdparty/hedley/hedley.hpp \
|
||||
-DOUTPUT=include/nlohmann/thirdparty/hedley/hedley_undef.hpp \
|
||||
-DMODE=undef \
|
||||
-P cmake/scripts/gen_hedley_undef_check.cmake
|
||||
|
||||
##########################################################################
|
||||
# serve_header.py
|
||||
##########################################################################
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
# Shared extractor for the JSON_HEDLEY_* macro names defined in hedley.hpp.
|
||||
#
|
||||
# Every macro that hedley.hpp #defines must be #undef-ed again once json.hpp
|
||||
# has been fully processed (see include/nlohmann/detail/macro_unscope.hpp
|
||||
# and https://github.com/nlohmann/json/issues/5408). Deriving the macro list
|
||||
# straight from hedley.hpp here -- instead of hand-maintaining it in two
|
||||
# places -- means hedley_undef.hpp and the regression test that checks for
|
||||
# leaked macros can never drift apart, even after a future `make
|
||||
# update_hedley` pulls in new macros from upstream Hedley.
|
||||
#
|
||||
# MODE=undef (default): write hedley_undef.hpp (SPDX header, #pragma once,
|
||||
# one #undef per macro name) -- used by `make update_hedley_undef`
|
||||
# MODE=checks: write one #ifdef/FAIL_CHECK/#endif per macro name,
|
||||
# meant to be #include-d inside a TEST_CASE -- used by
|
||||
# tests/CMakeLists.txt to (re)generate the include for
|
||||
# tests/src/unit-no-macro-leak.cpp
|
||||
#
|
||||
# Required variables:
|
||||
# HEDLEY_HPP path to include/nlohmann/thirdparty/hedley/hedley.hpp
|
||||
# OUTPUT path of the file to (over)write
|
||||
# Optional:
|
||||
# MODE "undef" (default) or "checks"
|
||||
|
||||
if(NOT DEFINED HEDLEY_HPP OR NOT DEFINED OUTPUT)
|
||||
message(FATAL_ERROR "HEDLEY_HPP and OUTPUT must be set")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${HEDLEY_HPP}")
|
||||
message(FATAL_ERROR "Hedley header not found: ${HEDLEY_HPP}")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED MODE)
|
||||
set(MODE undef)
|
||||
endif()
|
||||
|
||||
if(NOT MODE STREQUAL "undef" AND NOT MODE STREQUAL "checks")
|
||||
message(FATAL_ERROR "MODE must be undef or checks, got: ${MODE}")
|
||||
endif()
|
||||
|
||||
# Line-anchored, like `grep -oE "^[[:blank:]]*#[[:blank:]]*define[[:blank:]]+JSON_HEDLEY_[A-Za-z0-9_]+"`.
|
||||
# Unanchored matching would also pick up JSON_HEDLEY_* mentions inside
|
||||
# comments or string literals elsewhere in the file, which must not turn
|
||||
# into #undef lines.
|
||||
file(STRINGS "${HEDLEY_HPP}" hedley_lines)
|
||||
set(macro_names)
|
||||
foreach(line IN LISTS hedley_lines)
|
||||
if("${line}" MATCHES "^[ \t]*#[ \t]*define[ \t]+(JSON_HEDLEY_[A-Za-z0-9_]+)")
|
||||
list(APPEND macro_names "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT macro_names)
|
||||
message(FATAL_ERROR "No JSON_HEDLEY_* macros found in ${HEDLEY_HPP}")
|
||||
endif()
|
||||
|
||||
list(REMOVE_DUPLICATES macro_names)
|
||||
# Lexicographic, locale-independent (ASCII-only names) -- matches `LC_ALL=C sort`.
|
||||
list(SORT macro_names COMPARE STRING)
|
||||
list(LENGTH macro_names macro_count)
|
||||
|
||||
set(generated "")
|
||||
if(MODE STREQUAL "undef")
|
||||
# Same banner `make update_hedley_undef` would stamp by hand, so the
|
||||
# recipe is self-contained and its output is byte-stable across reruns.
|
||||
# The embedded SPDX tags below are part of the *generated* file's
|
||||
# content, not a REUSE header for this .cmake script itself (which is
|
||||
# already covered by the blanket "Files: *" rule in .reuse/dep5) -- keep
|
||||
# them wrapped in REUSE-IgnoreStart/End so `reuse lint` does not try to
|
||||
# parse "MIT\n")" as this file's own SPDX-License-Identifier value.
|
||||
# REUSE-IgnoreStart
|
||||
string(APPEND generated "// __ _____ _____ _____\n")
|
||||
string(APPEND generated "// __| | __| | | | JSON for Modern C++\n")
|
||||
string(APPEND generated "// | | |__ | | | | | | version 3.12.0\n")
|
||||
string(APPEND generated "// |_____|_____|_____|_|___| https://github.com/nlohmann/json\n")
|
||||
string(APPEND generated "//\n")
|
||||
string(APPEND generated "// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>\n")
|
||||
string(APPEND generated "// SPDX-License-Identifier: MIT\n")
|
||||
# REUSE-IgnoreEnd
|
||||
string(APPEND generated "\n")
|
||||
string(APPEND generated "#pragma once\n")
|
||||
string(APPEND generated "\n")
|
||||
foreach(name IN LISTS macro_names)
|
||||
string(APPEND generated "#undef ${name}\n")
|
||||
endforeach()
|
||||
else()
|
||||
string(APPEND generated "// This file is generated by cmake/scripts/gen_hedley_undef_check.cmake\n")
|
||||
string(APPEND generated "// from include/nlohmann/thirdparty/hedley/hedley.hpp. Do not edit it by\n")
|
||||
string(APPEND generated "// hand -- it is regenerated on every build. ${macro_count} macros checked.\n\n")
|
||||
foreach(name IN LISTS macro_names)
|
||||
string(APPEND generated "#ifdef ${name}\n")
|
||||
string(APPEND generated " FAIL_CHECK(\"${name} leaked after including nlohmann/json.hpp\");\n")
|
||||
string(APPEND generated "#endif\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
get_filename_component(output_dir "${OUTPUT}" DIRECTORY)
|
||||
if(output_dir)
|
||||
file(MAKE_DIRECTORY "${output_dir}")
|
||||
endif()
|
||||
|
||||
# Avoid rewriting the file (and busting downstream incremental rebuilds)
|
||||
# when the content has not actually changed.
|
||||
set(write_output TRUE)
|
||||
if(EXISTS "${OUTPUT}")
|
||||
file(READ "${OUTPUT}" existing_content)
|
||||
if(existing_content STREQUAL generated)
|
||||
set(write_output FALSE)
|
||||
endif()
|
||||
endif()
|
||||
if(write_output)
|
||||
file(WRITE "${OUTPUT}" "${generated}")
|
||||
endif()
|
||||
@@ -34,10 +34,6 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
("add", "remove", "move")
|
||||
- Throws [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) if an "add" operation's target
|
||||
location has a parent that is neither an object nor an array.
|
||||
- Throws [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) if a "remove" operation's target
|
||||
location has a parent that is neither an object nor an array.
|
||||
- Throws [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) if a "move" operation's "from"
|
||||
location is a proper prefix of its "path" location.
|
||||
- Throws [`other_error.501`](../../home/exceptions.md#jsonexceptionother_error501) if "test" operation was
|
||||
unsuccessful.
|
||||
|
||||
@@ -79,7 +75,3 @@ is thrown. In any case, the original value is not changed: the patch is applied
|
||||
- Added in version 2.0.0.
|
||||
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
||||
target location has a non-object/non-array parent in version 3.13.0.
|
||||
- Added [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) and stopped silently ignoring a "remove" operation whose target
|
||||
location has a non-object/non-array parent in version 3.13.0.
|
||||
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
||||
prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0.
|
||||
|
||||
@@ -30,10 +30,6 @@ No guarantees, value may be corrupted by an unsuccessful patch operation.
|
||||
("add", "remove", "move")
|
||||
- Throws [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) if an "add" operation's target
|
||||
location has a parent that is neither an object nor an array.
|
||||
- Throws [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) if a "remove" operation's target
|
||||
location has a parent that is neither an object nor an array.
|
||||
- Throws [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) if a "move" operation's "from"
|
||||
location is a proper prefix of its "path" location.
|
||||
- Throws [`other_error.501`](../../home/exceptions.md#jsonexceptionother_error501) if "test" operation was
|
||||
unsuccessful.
|
||||
|
||||
@@ -76,7 +72,3 @@ function throws an exception.
|
||||
- Added in version 3.11.0.
|
||||
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
||||
target location has a non-object/non-array parent in version 3.13.0.
|
||||
- Added [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) and stopped silently ignoring a "remove" operation whose target
|
||||
location has a non-object/non-array parent in version 3.13.0.
|
||||
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
||||
prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0.
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
Hello, world!
|
||||
1 2 3 4 5
|
||||
|
||||
string: "Hello, world!"
|
||||
number: {"floating-point":17.23,"integer":42}
|
||||
null: null
|
||||
string: "Hello, world!"
|
||||
boolean: true
|
||||
array: [1,2,3,4,5]
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
Hello, world!
|
||||
1 2 3 4 5
|
||||
|
||||
string: "Hello, world!"
|
||||
number: {"floating-point":17.23,"integer":42}
|
||||
null: null
|
||||
string: "Hello, world!"
|
||||
boolean: true
|
||||
array: [1,2,3,4,5]
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
Hello, world!
|
||||
1 2 3 4 5
|
||||
|
||||
string: "Hello, world!"
|
||||
number: {"floating-point":17.23,"integer":42}
|
||||
null: null
|
||||
string: "Hello, world!"
|
||||
boolean: true
|
||||
array: [1,2,3,4,5]
|
||||
[json.exception.type_error.302] type must be boolean, but is string
|
||||
|
||||
@@ -933,34 +933,6 @@ BSON stores the length of documents, arrays, strings, and binary values in a sig
|
||||
[`to_bson`](../api/basic_json/to_bson.md) produced documents with negative length prefixes that
|
||||
[`from_bson`](../api/basic_json/from_bson.md) rejected.
|
||||
|
||||
### json.exception.out_of_range.413
|
||||
|
||||
A JSON Patch `remove` operation cannot be applied because the target location's parent is neither an object nor an array. Per [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902), a `remove` target must reference a member of an existing object or an element of an existing array; a primitive value (string, number, boolean, etc.) or `null` has no members or elements to remove.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
cannot remove value: the JSON Patch 'remove' target's parent is of type number, but must be an object or array
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
This exception was added in version 3.13.0. Before that, this situation was silently ignored (the `remove` operation had no effect).
|
||||
|
||||
### json.exception.out_of_range.414
|
||||
|
||||
A JSON Patch `move` operation's `"from"` location is a proper prefix of its `"path"` location. Per [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) (section 4.4), a location cannot be moved into one of its own children.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
cannot move value: 'from' path '/0' is a proper prefix of 'path' '/0/0'
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
This exception was added in version 3.13.0. Before that, this situation could succeed with a corrupted result: for an array target, removing the "from" element before the "add" step shifted subsequent indices, so "path" silently re-resolved to a different element than intended.
|
||||
|
||||
## Further exceptions
|
||||
|
||||
This exception is thrown in case of errors that cannot be classified with the
|
||||
|
||||
@@ -398,17 +398,6 @@ inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType>
|
||||
auto from_json_object_reserve(ConstructibleObjectType& obj, typename ConstructibleObjectType::size_type size, priority_tag<1> /*unused*/)
|
||||
-> decltype(obj.reserve(size), void())
|
||||
{
|
||||
obj.reserve(size);
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType>
|
||||
inline void from_json_object_reserve(ConstructibleObjectType& /*obj*/, std::size_t /*size*/, priority_tag<0> /*unused*/)
|
||||
{}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
@@ -420,7 +409,6 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
|
||||
ConstructibleObjectType ret;
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
from_json_object_reserve(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
ret.emplace(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
|
||||
|
||||
@@ -1075,8 +1075,8 @@ char* to_chars(char* first, const char* last, FloatType value)
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
if (value == 0) // +-0
|
||||
{
|
||||
@@ -1087,7 +1087,7 @@ char* to_chars(char* first, const char* last, FloatType value)
|
||||
return first;
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
// code stumbling over this. See https://github.com/nlohmann/json/issues/4087
|
||||
// for a discussion.
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(clang diagnostic ignored "-Wweak-vtables")
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
@@ -287,5 +287,5 @@ class other_error : public exception
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -149,11 +149,10 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
public:
|
||||
using token_type = typename lexer_base<BasicJsonType>::token_type;
|
||||
|
||||
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false, bool discard_number_values_ = false) noexcept
|
||||
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
|
||||
: ia(std::move(adapter))
|
||||
, ignore_comments(ignore_comments_)
|
||||
, decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
|
||||
, discard_number_values(discard_number_values_)
|
||||
{}
|
||||
|
||||
// deleted because of pointer members
|
||||
@@ -1280,58 +1279,6 @@ scan_number_done:
|
||||
// we are done scanning a number)
|
||||
unget();
|
||||
|
||||
// If the caller does not need the converted value (only whether the
|
||||
// input is syntactically valid; see json_sax_acceptor/accept()), an
|
||||
// unsigned/integer token can be reported without calling
|
||||
// strtoull()/strtoll() at all, *provided* we can already tell from
|
||||
// the digit count alone that the conversion cannot overflow 64 bits.
|
||||
// Such tokens are always finite and are accepted unconditionally by
|
||||
// the parser regardless of their actual value (parser::sax_parse_internal()
|
||||
// never checks finiteness for value_unsigned/value_integer), so the
|
||||
// classification below is all that is needed.
|
||||
//
|
||||
// A decimal number with up to 18 digits is always representable in
|
||||
// both std::uint64_t and std::int64_t (18 nines is ~1e18, well below
|
||||
// both UINT64_MAX ~1.8e19 and INT64_MAX ~9.2e18), so strtoull()/strtoll()
|
||||
// could not have set errno to ERANGE for it. Numbers with more digits
|
||||
// (rare in practice) fall through to the exact code below, unchanged,
|
||||
// so their handling -- including reclassification to value_float when
|
||||
// the value overflows 64 bits, and rejection when it is not even
|
||||
// finite as a double -- is bit-for-bit identical to before this
|
||||
// optimization.
|
||||
//
|
||||
// Note this reasons about std::uint64_t/std::int64_t, not about
|
||||
// number_unsigned_t/number_integer_t (BasicJsonType's own, possibly
|
||||
// narrower, template parameters -- e.g. std::uint32_t). That is fine
|
||||
// *only* because discard_number_values is exclusively set by
|
||||
// accept() (see json.hpp), and accept() always parses through the
|
||||
// library's own json_sax_acceptor -- never a user-supplied SAX
|
||||
// consumer -- whose number_unsigned()/number_integer()/number_float()
|
||||
// callbacks unconditionally discard their argument and return true.
|
||||
// So for every caller that can reach this branch, neither the token
|
||||
// classification below nor the eventual (possibly narrowed, and on
|
||||
// this fast path left stale/unset) value_unsigned/value_integer is
|
||||
// ever consulted -- an unsigned/integer token is accepted outright,
|
||||
// and even a >18-digit token that this fast path deliberately falls
|
||||
// through for is, once reclassified to value_float, still finite
|
||||
// (and thus accepted) for any digit count that fits in number_unsigned_t
|
||||
// or number_integer_t regardless of that type's width. If this
|
||||
// function is ever taught to run with discard_number_values true for
|
||||
// a caller that *does* read the converted value, this reasoning (and
|
||||
// the fast path below) would need to be revisited.
|
||||
if (discard_number_values)
|
||||
{
|
||||
constexpr std::size_t safe_digit_count = 18;
|
||||
if (number_type == token_type::value_unsigned && token_buffer.size() <= safe_digit_count)
|
||||
{
|
||||
return token_type::value_unsigned;
|
||||
}
|
||||
if (number_type == token_type::value_integer && token_buffer.size() - 1 <= safe_digit_count)
|
||||
{
|
||||
return token_type::value_integer;
|
||||
}
|
||||
}
|
||||
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
errno = 0;
|
||||
|
||||
@@ -1446,7 +1393,8 @@ scan_number_done:
|
||||
*/
|
||||
char_int_type get()
|
||||
{
|
||||
advance_position();
|
||||
++position.chars_read_total;
|
||||
++position.chars_read_current_line;
|
||||
|
||||
if (next_unget)
|
||||
{
|
||||
@@ -1458,23 +1406,6 @@ scan_number_done:
|
||||
current = ia.get_character();
|
||||
}
|
||||
|
||||
return track_after_read();
|
||||
}
|
||||
|
||||
/// shared head of get() / get_ignoring_pending_unget(): bump the
|
||||
/// per-character position counters (line-count-on-'\n' bookkeeping is
|
||||
/// handled afterwards, in track_after_read(), once `current` is known)
|
||||
void advance_position() noexcept
|
||||
{
|
||||
++position.chars_read_total;
|
||||
++position.chars_read_current_line;
|
||||
}
|
||||
|
||||
/// shared tail of get() / get_ignoring_pending_unget(): capture the
|
||||
/// character for error messages (if needed) and update line/column
|
||||
/// bookkeeping for the character now in `current`
|
||||
char_int_type track_after_read()
|
||||
{
|
||||
// seekable adapters reconstruct the token lazily on error (see
|
||||
// get_token_string), so the eager per-character copy is skipped
|
||||
capture_char(std::integral_constant<bool, lazy_token_string> {});
|
||||
@@ -1488,29 +1419,6 @@ scan_number_done:
|
||||
return current;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief like get(), but for call sites that can prove no unget() is pending
|
||||
|
||||
get() has to check the `next_unget` flag on every call, because a
|
||||
previous token may have ended with unget() (e.g. scan_number() always
|
||||
ungets the character that terminated the number, so the next call to
|
||||
scan() can see it again). skip_whitespace() reads that first,
|
||||
possibly-ungotten character via a plain get(), but every further
|
||||
character it reads is guaranteed to be a fresh read: nothing between
|
||||
those calls invokes unget(). This variant skips the (otherwise always
|
||||
false) next_unget branch for those calls; it is not a general
|
||||
replacement for get().
|
||||
*/
|
||||
char_int_type get_ignoring_pending_unget()
|
||||
{
|
||||
JSON_ASSERT(!next_unget);
|
||||
|
||||
advance_position();
|
||||
current = ia.get_character();
|
||||
|
||||
return track_after_read();
|
||||
}
|
||||
|
||||
/// seekable adapter: nothing to capture, the token is rebuilt on error
|
||||
void capture_char(std::true_type /*lazy*/) const noexcept {}
|
||||
|
||||
@@ -1704,37 +1612,13 @@ scan_number_done:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// whether `current` is one of the four JSON whitespace characters
|
||||
bool current_is_whitespace() const noexcept
|
||||
{
|
||||
return current == ' ' || current == '\t' || current == '\n' || current == '\r';
|
||||
}
|
||||
|
||||
void skip_whitespace()
|
||||
{
|
||||
// the first character may be a pending unget() left over from the
|
||||
// previous token (see get_ignoring_pending_unget()); every
|
||||
// subsequent character read by this loop is guaranteed fresh, since
|
||||
// nothing below calls unget()
|
||||
get();
|
||||
|
||||
if (!current_is_whitespace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// this is written as an if-guarded do-while (rather than a plain
|
||||
// while loop) because that shape is what lets both GCC and Clang
|
||||
// keep the input adapter's read pointer in a register across
|
||||
// iterations; the equivalent while-loop measurably defeated that
|
||||
// optimization in testing, turning long whitespace runs (e.g. the
|
||||
// indentation of pretty-printed JSON) from a register-only loop
|
||||
// into one that reloads the pointer from memory every character
|
||||
do
|
||||
{
|
||||
get_ignoring_pending_unget();
|
||||
get();
|
||||
}
|
||||
while (current_is_whitespace());
|
||||
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
|
||||
}
|
||||
|
||||
token_type scan()
|
||||
@@ -1870,13 +1754,6 @@ scan_number_done:
|
||||
const char_int_type decimal_point_char = '.';
|
||||
/// the position of the decimal point in the input
|
||||
std::size_t decimal_point_position = std::string::npos;
|
||||
|
||||
/// whether the caller (e.g. accept()/json_sax_acceptor) only needs the
|
||||
/// token classification and never looks at the converted numeric value;
|
||||
/// when set, scan_number() may skip strtoull()/strtoll() for
|
||||
/// value_unsigned/value_integer tokens whose digit count guarantees they
|
||||
/// fit into 64 bits (see scan_number())
|
||||
const bool discard_number_values = false;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -72,10 +72,9 @@ class parser
|
||||
parser_callback_t<BasicJsonType> cb = nullptr,
|
||||
const bool allow_exceptions_ = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas_ = false,
|
||||
const bool discard_number_values_ = false)
|
||||
const bool ignore_trailing_commas_ = false)
|
||||
: callback(std::move(cb))
|
||||
, m_lexer(std::move(adapter), ignore_comments, discard_number_values_)
|
||||
, m_lexer(std::move(adapter), ignore_comments)
|
||||
, allow_exceptions(allow_exceptions_)
|
||||
, ignore_trailing_commas(ignore_trailing_commas_)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#endif
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/string_utils.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
@@ -207,10 +206,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
namespace std
|
||||
{
|
||||
|
||||
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(clang diagnostic ignored "-Wmismatched-tags")
|
||||
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template<typename IteratorType>
|
||||
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
|
||||
@@ -225,7 +224,7 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
|
||||
::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
|
||||
};
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
@@ -748,20 +748,6 @@ class json_pointer
|
||||
}
|
||||
}
|
||||
|
||||
// the reference token consists only of digits at this point (cf. checks
|
||||
// above); however, its numeric value might not be representable, in which
|
||||
// case array_index() would throw out_of_range.404/410 -- contains() must
|
||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
||||
errno = 0; // strtoull() does not reset errno on success
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||
{
|
||||
// the array index cannot be represented as size_type
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||
if (idx >= ptr->size())
|
||||
{
|
||||
|
||||
@@ -1850,8 +1850,8 @@ class binary_writer
|
||||
void write_compact_float(const number_float_t n, detail::input_format_t format)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
if (!std::isfinite(n) || ((static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
|
||||
static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
|
||||
@@ -1870,7 +1870,7 @@ class binary_writer
|
||||
write_number(n);
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class serializer
|
||||
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
|
||||
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
|
||||
, indent_char(ichar)
|
||||
, indent_string(512, indent_char)
|
||||
, indent_string()
|
||||
, error_handler(error_handler_)
|
||||
{}
|
||||
|
||||
@@ -126,6 +126,10 @@ class serializer
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
|
||||
{
|
||||
indent_string.resize(512, indent_char);
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
@@ -199,6 +203,10 @@ class serializer
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
|
||||
{
|
||||
indent_string.resize(512, indent_char);
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
@@ -260,6 +268,10 @@ class serializer
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
|
||||
{
|
||||
indent_string.resize(512, indent_char);
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
@@ -1010,7 +1022,7 @@ class serializer
|
||||
|
||||
/// the indentation character
|
||||
const char indent_char;
|
||||
/// the indentation string
|
||||
/// the indentation string (lazily allocated on first use by a pretty-print branch)
|
||||
string_t indent_string;
|
||||
|
||||
/// error_handler how to react on decoding errors
|
||||
|
||||
+11
-74
@@ -164,12 +164,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::parser_callback_t<basic_json>cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
const bool discard_number_values = false
|
||||
const bool ignore_trailing_commas = false
|
||||
)
|
||||
{
|
||||
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
||||
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas, discard_number_values);
|
||||
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1336,7 +1335,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief serialization
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/dump/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
string_t dump(const int indent = -1,
|
||||
const char indent_char = ' ',
|
||||
const bool ensure_ascii = false,
|
||||
@@ -1359,7 +1357,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return the type of the JSON value (explicit)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/type/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr value_t type() const noexcept
|
||||
{
|
||||
return m_data.m_type;
|
||||
@@ -1367,7 +1364,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether type is primitive
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_primitive() const noexcept
|
||||
{
|
||||
return is_null() || is_string() || is_boolean() || is_number() || is_binary();
|
||||
@@ -1375,7 +1371,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether type is structured
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_structured/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_structured() const noexcept
|
||||
{
|
||||
return is_array() || is_object();
|
||||
@@ -1383,7 +1378,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is null
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_null/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_null() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::null;
|
||||
@@ -1391,7 +1385,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a boolean
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_boolean() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::boolean;
|
||||
@@ -1399,7 +1392,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number() const noexcept
|
||||
{
|
||||
return is_number_integer() || is_number_float();
|
||||
@@ -1407,7 +1399,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an integer number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number_integer() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
|
||||
@@ -1415,7 +1406,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an unsigned integer number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number_unsigned() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::number_unsigned;
|
||||
@@ -1423,7 +1413,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a floating-point number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number_float() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::number_float;
|
||||
@@ -1431,7 +1420,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an object
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_object/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_object() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::object;
|
||||
@@ -1439,7 +1427,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an array
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_array/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_array() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::array;
|
||||
@@ -1447,7 +1434,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a string
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_string/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_string() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::string;
|
||||
@@ -1455,7 +1441,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a binary array
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_binary/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_binary() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::binary;
|
||||
@@ -1463,7 +1448,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is discarded
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_discarded() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::discarded;
|
||||
@@ -2795,7 +2779,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief returns the number of occurrences of a key in a JSON object
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/count/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type count(const typename object_t::key_type& key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
@@ -2806,7 +2789,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/count/
|
||||
template<class KeyType, detail::enable_if_t<
|
||||
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type count(KeyType && key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
@@ -2815,7 +2797,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief check the existence of an element in a JSON object
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(const typename object_t::key_type& key) const
|
||||
{
|
||||
return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
|
||||
@@ -2825,7 +2806,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
||||
template<class KeyType, detail::enable_if_t<
|
||||
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(KeyType && key) const
|
||||
{
|
||||
return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
|
||||
@@ -2833,14 +2813,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief check the existence of an element in a JSON object given a JSON pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(const json_pointer& ptr) const
|
||||
{
|
||||
return ptr.contains(this);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
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)
|
||||
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
@@ -2996,7 +2974,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief checks whether the container is empty.
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/empty/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool empty() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
@@ -3036,7 +3013,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief returns the number of elements
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/size/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type size() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
@@ -3076,7 +3052,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief returns the maximum possible number of elements
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/max_size/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
@@ -3795,13 +3770,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
bool operator==(const_reference rhs) const noexcept
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
const_reference lhs = *this;
|
||||
JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3888,12 +3863,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4154,24 +4129,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @brief check if the input is valid JSON
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename InputType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static bool accept(InputType&& i,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
/// @brief check if the input is valid JSON (iterator pair, or iterator+sentinel pair for C++20 ranges support)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename IteratorType, typename SentinelType = IteratorType,
|
||||
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static bool accept(IteratorType first, SentinelType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
@@ -4180,7 +4153,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
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).accept(true);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events
|
||||
@@ -4266,7 +4239,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return the type as string
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/type_name/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
const char* type_name() const noexcept
|
||||
{
|
||||
@@ -4967,36 +4939,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// note erase performs range check
|
||||
parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
// the parent of a "remove" target must be an object or array
|
||||
// (see #5396)
|
||||
JSON_THROW(out_of_range::create(413, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
||||
}
|
||||
};
|
||||
|
||||
// RFC 6902 (section 4.4) forbids "from" from being a proper prefix
|
||||
// of "path" for a "move" operation: a location cannot be moved into
|
||||
// one of its own children. Compares reference tokens (already
|
||||
// unescaped by json_pointer's parser) rather than the raw pointer
|
||||
// strings, since a token may itself contain an escaped '/' or '~'
|
||||
// that would defeat a naive string-prefix comparison. "from" equal
|
||||
// to "path" is *not* a proper prefix and must return false.
|
||||
const auto is_proper_prefix = [](const json_pointer & from, const json_pointer & to)
|
||||
{
|
||||
const auto from_size = from.reference_tokens.size();
|
||||
if (from_size >= to.reference_tokens.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (std::size_t i = 0; i < from_size; ++i)
|
||||
{
|
||||
if (!(from.reference_tokens[i] == to.reference_tokens[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// type check: top level value must be an array
|
||||
@@ -5074,11 +5016,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const auto from_path = get_value("move", "from", true).template get<string_t>();
|
||||
json_pointer from_ptr(from_path);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
|
||||
}
|
||||
|
||||
// the "from" location must exist - use at()
|
||||
basic_json const v = result.at(from_ptr);
|
||||
|
||||
|
||||
+1
-4
@@ -17,7 +17,7 @@
|
||||
#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
|
||||
#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
|
||||
#undef JSON_HEDLEY_CLANG_HAS_FEATURE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_WARNING
|
||||
@@ -108,10 +108,7 @@
|
||||
#undef JSON_HEDLEY_PELLES_VERSION_CHECK
|
||||
#undef JSON_HEDLEY_PGI_VERSION
|
||||
#undef JSON_HEDLEY_PGI_VERSION_CHECK
|
||||
#undef JSON_HEDLEY_PRAGMA
|
||||
#undef JSON_HEDLEY_PREDICT
|
||||
#undef JSON_HEDLEY_PREDICT_FALSE
|
||||
#undef JSON_HEDLEY_PREDICT_TRUE
|
||||
#undef JSON_HEDLEY_PRINTF_FORMAT
|
||||
#undef JSON_HEDLEY_PRIVATE
|
||||
#undef JSON_HEDLEY_PUBLIC
|
||||
|
||||
@@ -4945,8 +4945,8 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// code stumbling over this. See https://github.com/nlohmann/json/issues/4087
|
||||
// for a discussion.
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(clang diagnostic ignored "-Wweak-vtables")
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
@@ -5199,7 +5199,7 @@ class other_error : public exception
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
@@ -5693,17 +5693,6 @@ inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType>
|
||||
auto from_json_object_reserve(ConstructibleObjectType& obj, typename ConstructibleObjectType::size_type size, priority_tag<1> /*unused*/)
|
||||
-> decltype(obj.reserve(size), void())
|
||||
{
|
||||
obj.reserve(size);
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType>
|
||||
inline void from_json_object_reserve(ConstructibleObjectType& /*obj*/, std::size_t /*size*/, priority_tag<0> /*unused*/)
|
||||
{}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
@@ -5715,7 +5704,6 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
|
||||
ConstructibleObjectType ret;
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
from_json_object_reserve(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
ret.emplace(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
|
||||
@@ -5987,8 +5975,6 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
// #include <nlohmann/detail/string_utils.hpp>
|
||||
@@ -6218,10 +6204,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
namespace std
|
||||
{
|
||||
|
||||
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(clang diagnostic ignored "-Wmismatched-tags")
|
||||
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template<typename IteratorType>
|
||||
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
|
||||
@@ -6236,7 +6222,7 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
|
||||
::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
|
||||
};
|
||||
#if defined(__clang__)
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
@@ -7946,11 +7932,10 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
public:
|
||||
using token_type = typename lexer_base<BasicJsonType>::token_type;
|
||||
|
||||
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false, bool discard_number_values_ = false) noexcept
|
||||
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
|
||||
: ia(std::move(adapter))
|
||||
, ignore_comments(ignore_comments_)
|
||||
, decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
|
||||
, discard_number_values(discard_number_values_)
|
||||
{}
|
||||
|
||||
// deleted because of pointer members
|
||||
@@ -9077,58 +9062,6 @@ scan_number_done:
|
||||
// we are done scanning a number)
|
||||
unget();
|
||||
|
||||
// If the caller does not need the converted value (only whether the
|
||||
// input is syntactically valid; see json_sax_acceptor/accept()), an
|
||||
// unsigned/integer token can be reported without calling
|
||||
// strtoull()/strtoll() at all, *provided* we can already tell from
|
||||
// the digit count alone that the conversion cannot overflow 64 bits.
|
||||
// Such tokens are always finite and are accepted unconditionally by
|
||||
// the parser regardless of their actual value (parser::sax_parse_internal()
|
||||
// never checks finiteness for value_unsigned/value_integer), so the
|
||||
// classification below is all that is needed.
|
||||
//
|
||||
// A decimal number with up to 18 digits is always representable in
|
||||
// both std::uint64_t and std::int64_t (18 nines is ~1e18, well below
|
||||
// both UINT64_MAX ~1.8e19 and INT64_MAX ~9.2e18), so strtoull()/strtoll()
|
||||
// could not have set errno to ERANGE for it. Numbers with more digits
|
||||
// (rare in practice) fall through to the exact code below, unchanged,
|
||||
// so their handling -- including reclassification to value_float when
|
||||
// the value overflows 64 bits, and rejection when it is not even
|
||||
// finite as a double -- is bit-for-bit identical to before this
|
||||
// optimization.
|
||||
//
|
||||
// Note this reasons about std::uint64_t/std::int64_t, not about
|
||||
// number_unsigned_t/number_integer_t (BasicJsonType's own, possibly
|
||||
// narrower, template parameters -- e.g. std::uint32_t). That is fine
|
||||
// *only* because discard_number_values is exclusively set by
|
||||
// accept() (see json.hpp), and accept() always parses through the
|
||||
// library's own json_sax_acceptor -- never a user-supplied SAX
|
||||
// consumer -- whose number_unsigned()/number_integer()/number_float()
|
||||
// callbacks unconditionally discard their argument and return true.
|
||||
// So for every caller that can reach this branch, neither the token
|
||||
// classification below nor the eventual (possibly narrowed, and on
|
||||
// this fast path left stale/unset) value_unsigned/value_integer is
|
||||
// ever consulted -- an unsigned/integer token is accepted outright,
|
||||
// and even a >18-digit token that this fast path deliberately falls
|
||||
// through for is, once reclassified to value_float, still finite
|
||||
// (and thus accepted) for any digit count that fits in number_unsigned_t
|
||||
// or number_integer_t regardless of that type's width. If this
|
||||
// function is ever taught to run with discard_number_values true for
|
||||
// a caller that *does* read the converted value, this reasoning (and
|
||||
// the fast path below) would need to be revisited.
|
||||
if (discard_number_values)
|
||||
{
|
||||
constexpr std::size_t safe_digit_count = 18;
|
||||
if (number_type == token_type::value_unsigned && token_buffer.size() <= safe_digit_count)
|
||||
{
|
||||
return token_type::value_unsigned;
|
||||
}
|
||||
if (number_type == token_type::value_integer && token_buffer.size() - 1 <= safe_digit_count)
|
||||
{
|
||||
return token_type::value_integer;
|
||||
}
|
||||
}
|
||||
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
errno = 0;
|
||||
|
||||
@@ -9243,7 +9176,8 @@ scan_number_done:
|
||||
*/
|
||||
char_int_type get()
|
||||
{
|
||||
advance_position();
|
||||
++position.chars_read_total;
|
||||
++position.chars_read_current_line;
|
||||
|
||||
if (next_unget)
|
||||
{
|
||||
@@ -9255,23 +9189,6 @@ scan_number_done:
|
||||
current = ia.get_character();
|
||||
}
|
||||
|
||||
return track_after_read();
|
||||
}
|
||||
|
||||
/// shared head of get() / get_ignoring_pending_unget(): bump the
|
||||
/// per-character position counters (line-count-on-'\n' bookkeeping is
|
||||
/// handled afterwards, in track_after_read(), once `current` is known)
|
||||
void advance_position() noexcept
|
||||
{
|
||||
++position.chars_read_total;
|
||||
++position.chars_read_current_line;
|
||||
}
|
||||
|
||||
/// shared tail of get() / get_ignoring_pending_unget(): capture the
|
||||
/// character for error messages (if needed) and update line/column
|
||||
/// bookkeeping for the character now in `current`
|
||||
char_int_type track_after_read()
|
||||
{
|
||||
// seekable adapters reconstruct the token lazily on error (see
|
||||
// get_token_string), so the eager per-character copy is skipped
|
||||
capture_char(std::integral_constant<bool, lazy_token_string> {});
|
||||
@@ -9285,29 +9202,6 @@ scan_number_done:
|
||||
return current;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief like get(), but for call sites that can prove no unget() is pending
|
||||
|
||||
get() has to check the `next_unget` flag on every call, because a
|
||||
previous token may have ended with unget() (e.g. scan_number() always
|
||||
ungets the character that terminated the number, so the next call to
|
||||
scan() can see it again). skip_whitespace() reads that first,
|
||||
possibly-ungotten character via a plain get(), but every further
|
||||
character it reads is guaranteed to be a fresh read: nothing between
|
||||
those calls invokes unget(). This variant skips the (otherwise always
|
||||
false) next_unget branch for those calls; it is not a general
|
||||
replacement for get().
|
||||
*/
|
||||
char_int_type get_ignoring_pending_unget()
|
||||
{
|
||||
JSON_ASSERT(!next_unget);
|
||||
|
||||
advance_position();
|
||||
current = ia.get_character();
|
||||
|
||||
return track_after_read();
|
||||
}
|
||||
|
||||
/// seekable adapter: nothing to capture, the token is rebuilt on error
|
||||
void capture_char(std::true_type /*lazy*/) const noexcept {}
|
||||
|
||||
@@ -9501,37 +9395,13 @@ scan_number_done:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// whether `current` is one of the four JSON whitespace characters
|
||||
bool current_is_whitespace() const noexcept
|
||||
{
|
||||
return current == ' ' || current == '\t' || current == '\n' || current == '\r';
|
||||
}
|
||||
|
||||
void skip_whitespace()
|
||||
{
|
||||
// the first character may be a pending unget() left over from the
|
||||
// previous token (see get_ignoring_pending_unget()); every
|
||||
// subsequent character read by this loop is guaranteed fresh, since
|
||||
// nothing below calls unget()
|
||||
get();
|
||||
|
||||
if (!current_is_whitespace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// this is written as an if-guarded do-while (rather than a plain
|
||||
// while loop) because that shape is what lets both GCC and Clang
|
||||
// keep the input adapter's read pointer in a register across
|
||||
// iterations; the equivalent while-loop measurably defeated that
|
||||
// optimization in testing, turning long whitespace runs (e.g. the
|
||||
// indentation of pretty-printed JSON) from a register-only loop
|
||||
// into one that reloads the pointer from memory every character
|
||||
do
|
||||
{
|
||||
get_ignoring_pending_unget();
|
||||
get();
|
||||
}
|
||||
while (current_is_whitespace());
|
||||
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
|
||||
}
|
||||
|
||||
token_type scan()
|
||||
@@ -9667,13 +9537,6 @@ scan_number_done:
|
||||
const char_int_type decimal_point_char = '.';
|
||||
/// the position of the decimal point in the input
|
||||
std::size_t decimal_point_position = std::string::npos;
|
||||
|
||||
/// whether the caller (e.g. accept()/json_sax_acceptor) only needs the
|
||||
/// token classification and never looks at the converted numeric value;
|
||||
/// when set, scan_number() may skip strtoull()/strtoll() for
|
||||
/// value_unsigned/value_integer tokens whose digit count guarantees they
|
||||
/// fit into 64 bits (see scan_number())
|
||||
const bool discard_number_values = false;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -14180,10 +14043,9 @@ class parser
|
||||
parser_callback_t<BasicJsonType> cb = nullptr,
|
||||
const bool allow_exceptions_ = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas_ = false,
|
||||
const bool discard_number_values_ = false)
|
||||
const bool ignore_trailing_commas_ = false)
|
||||
: callback(std::move(cb))
|
||||
, m_lexer(std::move(adapter), ignore_comments, discard_number_values_)
|
||||
, m_lexer(std::move(adapter), ignore_comments)
|
||||
, allow_exceptions(allow_exceptions_)
|
||||
, ignore_trailing_commas(ignore_trailing_commas_)
|
||||
{
|
||||
@@ -16532,20 +16394,6 @@ class json_pointer
|
||||
}
|
||||
}
|
||||
|
||||
// the reference token consists only of digits at this point (cf. checks
|
||||
// above); however, its numeric value might not be representable, in which
|
||||
// case array_index() would throw out_of_range.404/410 -- contains() must
|
||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
||||
errno = 0; // strtoull() does not reset errno on success
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||
{
|
||||
// the array index cannot be represented as size_type
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||
if (idx >= ptr->size())
|
||||
{
|
||||
@@ -19010,8 +18858,8 @@ class binary_writer
|
||||
void write_compact_float(const number_float_t n, detail::input_format_t format)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
if (!std::isfinite(n) || ((static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
|
||||
static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
|
||||
@@ -19030,7 +18878,7 @@ class binary_writer
|
||||
write_number(n);
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20205,8 +20053,8 @@ char* to_chars(char* first, const char* last, FloatType value)
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
if (value == 0) // +-0
|
||||
{
|
||||
@@ -20217,7 +20065,7 @@ char* to_chars(char* first, const char* last, FloatType value)
|
||||
return first;
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
|
||||
@@ -20302,7 +20150,7 @@ class serializer
|
||||
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
|
||||
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
|
||||
, indent_char(ichar)
|
||||
, indent_string(512, indent_char)
|
||||
, indent_string()
|
||||
, error_handler(error_handler_)
|
||||
{}
|
||||
|
||||
@@ -20357,6 +20205,10 @@ class serializer
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
|
||||
{
|
||||
indent_string.resize(512, indent_char);
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
@@ -20430,6 +20282,10 @@ class serializer
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
|
||||
{
|
||||
indent_string.resize(512, indent_char);
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
@@ -20491,6 +20347,10 @@ class serializer
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
|
||||
{
|
||||
indent_string.resize(512, indent_char);
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
@@ -21241,7 +21101,7 @@ class serializer
|
||||
|
||||
/// the indentation character
|
||||
const char indent_char;
|
||||
/// the indentation string
|
||||
/// the indentation string (lazily allocated on first use by a pretty-print branch)
|
||||
string_t indent_string;
|
||||
|
||||
/// error_handler how to react on decoding errors
|
||||
@@ -21744,12 +21604,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::parser_callback_t<basic_json>cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
const bool discard_number_values = false
|
||||
const bool ignore_trailing_commas = false
|
||||
)
|
||||
{
|
||||
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
||||
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas, discard_number_values);
|
||||
std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -22916,7 +22775,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief serialization
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/dump/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
string_t dump(const int indent = -1,
|
||||
const char indent_char = ' ',
|
||||
const bool ensure_ascii = false,
|
||||
@@ -22939,7 +22797,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return the type of the JSON value (explicit)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/type/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr value_t type() const noexcept
|
||||
{
|
||||
return m_data.m_type;
|
||||
@@ -22947,7 +22804,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether type is primitive
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_primitive() const noexcept
|
||||
{
|
||||
return is_null() || is_string() || is_boolean() || is_number() || is_binary();
|
||||
@@ -22955,7 +22811,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether type is structured
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_structured/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_structured() const noexcept
|
||||
{
|
||||
return is_array() || is_object();
|
||||
@@ -22963,7 +22818,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is null
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_null/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_null() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::null;
|
||||
@@ -22971,7 +22825,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a boolean
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_boolean() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::boolean;
|
||||
@@ -22979,7 +22832,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number() const noexcept
|
||||
{
|
||||
return is_number_integer() || is_number_float();
|
||||
@@ -22987,7 +22839,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an integer number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number_integer() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
|
||||
@@ -22995,7 +22846,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an unsigned integer number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number_unsigned() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::number_unsigned;
|
||||
@@ -23003,7 +22853,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a floating-point number
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_number_float() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::number_float;
|
||||
@@ -23011,7 +22860,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an object
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_object/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_object() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::object;
|
||||
@@ -23019,7 +22867,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is an array
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_array/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_array() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::array;
|
||||
@@ -23027,7 +22874,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a string
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_string/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_string() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::string;
|
||||
@@ -23035,7 +22881,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is a binary array
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_binary/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_binary() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::binary;
|
||||
@@ -23043,7 +22888,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return whether value is discarded
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
constexpr bool is_discarded() const noexcept
|
||||
{
|
||||
return m_data.m_type == value_t::discarded;
|
||||
@@ -24375,7 +24219,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief returns the number of occurrences of a key in a JSON object
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/count/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type count(const typename object_t::key_type& key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
@@ -24386,7 +24229,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/count/
|
||||
template<class KeyType, detail::enable_if_t<
|
||||
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type count(KeyType && key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
@@ -24395,7 +24237,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief check the existence of an element in a JSON object
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(const typename object_t::key_type& key) const
|
||||
{
|
||||
return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
|
||||
@@ -24405,7 +24246,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
||||
template<class KeyType, detail::enable_if_t<
|
||||
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(KeyType && key) const
|
||||
{
|
||||
return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
|
||||
@@ -24413,14 +24253,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief check the existence of an element in a JSON object given a JSON pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/contains/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(const json_pointer& ptr) const
|
||||
{
|
||||
return ptr.contains(this);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
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)
|
||||
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
@@ -24576,7 +24414,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief checks whether the container is empty.
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/empty/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool empty() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
@@ -24616,7 +24453,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief returns the number of elements
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/size/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type size() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
@@ -24656,7 +24492,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief returns the maximum possible number of elements
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/max_size/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
@@ -25375,13 +25210,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
bool operator==(const_reference rhs) const noexcept
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
const_reference lhs = *this;
|
||||
JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -25468,12 +25303,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
|
||||
#ifdef __GNUC__
|
||||
JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -25734,24 +25569,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @brief check if the input is valid JSON
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename InputType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static bool accept(InputType&& i,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
/// @brief check if the input is valid JSON (iterator pair, or iterator+sentinel pair for C++20 ranges support)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename IteratorType, typename SentinelType = IteratorType,
|
||||
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static bool accept(IteratorType first, SentinelType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
@@ -25760,7 +25593,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false)
|
||||
{
|
||||
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).accept(true);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events
|
||||
@@ -25846,7 +25679,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @brief return the type as string
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/type_name/
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
const char* type_name() const noexcept
|
||||
{
|
||||
@@ -26547,36 +26379,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// note erase performs range check
|
||||
parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
// the parent of a "remove" target must be an object or array
|
||||
// (see #5396)
|
||||
JSON_THROW(out_of_range::create(413, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
||||
}
|
||||
};
|
||||
|
||||
// RFC 6902 (section 4.4) forbids "from" from being a proper prefix
|
||||
// of "path" for a "move" operation: a location cannot be moved into
|
||||
// one of its own children. Compares reference tokens (already
|
||||
// unescaped by json_pointer's parser) rather than the raw pointer
|
||||
// strings, since a token may itself contain an escaped '/' or '~'
|
||||
// that would defeat a naive string-prefix comparison. "from" equal
|
||||
// to "path" is *not* a proper prefix and must return false.
|
||||
const auto is_proper_prefix = [](const json_pointer & from, const json_pointer & to)
|
||||
{
|
||||
const auto from_size = from.reference_tokens.size();
|
||||
if (from_size >= to.reference_tokens.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (std::size_t i = 0; i < from_size; ++i)
|
||||
{
|
||||
if (!(from.reference_tokens[i] == to.reference_tokens[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// type check: top level value must be an array
|
||||
@@ -26654,11 +26456,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
const auto from_path = get_value("move", "from", true).template get<string_t>();
|
||||
json_pointer from_ptr(from_path);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
|
||||
}
|
||||
|
||||
// the "from" location must exist - use at()
|
||||
basic_json const v = result.at(from_ptr);
|
||||
|
||||
@@ -27180,7 +26977,7 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
|
||||
#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
|
||||
#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
|
||||
#undef JSON_HEDLEY_CLANG_HAS_FEATURE
|
||||
#undef JSON_HEDLEY_CLANG_HAS_WARNING
|
||||
@@ -27271,10 +27068,7 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
|
||||
#undef JSON_HEDLEY_PELLES_VERSION_CHECK
|
||||
#undef JSON_HEDLEY_PGI_VERSION
|
||||
#undef JSON_HEDLEY_PGI_VERSION_CHECK
|
||||
#undef JSON_HEDLEY_PRAGMA
|
||||
#undef JSON_HEDLEY_PREDICT
|
||||
#undef JSON_HEDLEY_PREDICT_FALSE
|
||||
#undef JSON_HEDLEY_PREDICT_TRUE
|
||||
#undef JSON_HEDLEY_PRINTF_FORMAT
|
||||
#undef JSON_HEDLEY_PRIVATE
|
||||
#undef JSON_HEDLEY_PUBLIC
|
||||
|
||||
@@ -125,51 +125,6 @@ json_test_set_test_options(test-unicode4 TEST_PROPERTIES TIMEOUT 3000)
|
||||
# add unit tests
|
||||
#############################################################################
|
||||
|
||||
# Generate the leak checks for every JSON_HEDLEY_* macro defined in
|
||||
# hedley.hpp; tests/src/unit-no-macro-leak.cpp #include-s the result after
|
||||
# nlohmann/json.hpp (see issue #5408). Using the shared
|
||||
# cmake/scripts/gen_hedley_undef_check.cmake script (also used by `make
|
||||
# update_hedley_undef`) instead of a hand-maintained list of macro names
|
||||
# means this test can never go stale after a future `make update_hedley`.
|
||||
set(hedley_hpp "${PROJECT_SOURCE_DIR}/include/nlohmann/thirdparty/hedley/hedley.hpp")
|
||||
set(hedley_undef_check_script "${PROJECT_SOURCE_DIR}/cmake/scripts/gen_hedley_undef_check.cmake")
|
||||
set(hedley_undef_checks "${PROJECT_BINARY_DIR}/include/hedley_undef_checks.inc")
|
||||
|
||||
# Reconfigure whenever the vendored header or the generator script changes,
|
||||
# so a `cmake --build` after `make update_hedley` does not silently keep a
|
||||
# stale generated file around.
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
||||
"${hedley_hpp}"
|
||||
"${hedley_undef_check_script}")
|
||||
|
||||
# Generate once at configure time, so the very first build (before any
|
||||
# custom-command build step has run) already has an up-to-date file.
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DHEDLEY_HPP=${hedley_hpp}"
|
||||
"-DOUTPUT=${hedley_undef_checks}"
|
||||
-DMODE=checks
|
||||
-P "${hedley_undef_check_script}"
|
||||
RESULT_VARIABLE hedley_undef_check_result
|
||||
)
|
||||
if(NOT hedley_undef_check_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to generate ${hedley_undef_checks}")
|
||||
endif()
|
||||
|
||||
# Also (re)generate as a build step, so an incremental build after editing
|
||||
# hedley.hpp without a full reconfigure still picks up the change.
|
||||
add_custom_command(
|
||||
OUTPUT "${hedley_undef_checks}"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DHEDLEY_HPP=${hedley_hpp}"
|
||||
"-DOUTPUT=${hedley_undef_checks}"
|
||||
-DMODE=checks
|
||||
-P "${hedley_undef_check_script}"
|
||||
DEPENDS "${hedley_hpp}" "${hedley_undef_check_script}"
|
||||
COMMENT "Generating Hedley undef leak checks"
|
||||
VERBATIM)
|
||||
add_custom_target(generate_hedley_undef_checks DEPENDS "${hedley_undef_checks}")
|
||||
|
||||
if("${JSON_TestStandards}" STREQUAL "")
|
||||
set(test_cxx_standards 11 14 17 20 23)
|
||||
unset(test_force)
|
||||
@@ -208,14 +163,6 @@ foreach(file ${files})
|
||||
json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force})
|
||||
endforeach()
|
||||
|
||||
# tests/src/unit-no-macro-leak.cpp #include-s the generated leak-check file,
|
||||
# so its test targets must be built after generate_hedley_undef_checks.
|
||||
foreach(cxx_standard ${test_cxx_standards})
|
||||
if(TARGET test-no-macro-leak_cpp${cxx_standard})
|
||||
add_dependencies(test-no-macro-leak_cpp${cxx_standard} generate_hedley_undef_checks)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(json_32bit_test_only)
|
||||
# Skip all other tests in this file
|
||||
return()
|
||||
|
||||
@@ -15,15 +15,6 @@
|
||||
namespace utils
|
||||
{
|
||||
|
||||
// Some tests intentionally discard the [[nodiscard]]/JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
// return value of a call they only make to exercise its side effects (e.g. checking
|
||||
// that it does not throw). A plain (void) cast on the call expression does not
|
||||
// suppress GCC's warning for functions using the GNU __attribute__((warn_unused_result))
|
||||
// form (as opposed to the C++17 [[nodiscard]] attribute) -- passing the value into an
|
||||
// ordinary function call does.
|
||||
template<typename T>
|
||||
inline void ignore_return_value(T&& /*unused*/) noexcept {}
|
||||
|
||||
inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
|
||||
{
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
|
||||
+3
-142
@@ -38,54 +38,6 @@ class huge_binary_t : public std::vector<std::uint8_t>
|
||||
using huge_binary_json = nlohmann::basic_json <
|
||||
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, huge_binary_t, void >;
|
||||
|
||||
// a string type that can be made to report a size beyond INT32_MAX without
|
||||
// allocating that much memory, so BSON length overflow can be tested for
|
||||
// strings and (embedded) documents as well, following the same idea as
|
||||
// huge_binary_t.
|
||||
//
|
||||
// Unlike huge_binary_t (which is only ever used as the BSON *value* type),
|
||||
// this type doubles as basic_json's StringType and is therefore also used
|
||||
// for *object keys* (e.g. "s" or "nested" below). Only the designated test
|
||||
// value is meant to lie about its size - if every huge_string_t (including
|
||||
// keys) reported a huge size, the running totals computed while walking the
|
||||
// BSON document (see calc_bson_object_size & friends in binary_writer.hpp)
|
||||
// would need more than 32 bits, and on platforms where std::size_t is only
|
||||
// 32 bits wide that arithmetic would silently wrap around, producing wrong
|
||||
// (or even unguarded) lengths. The fake size is therefore opt-in via
|
||||
// as_huge(), and plain strings - in particular object keys - keep reporting
|
||||
// their real, small size.
|
||||
class huge_string_t : public std::string
|
||||
{
|
||||
public:
|
||||
using std::string::string;
|
||||
huge_string_t(const std::string& s) : std::string(s) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
|
||||
// returns a copy of @a s whose size() pretends to be huge
|
||||
static huge_string_t as_huge(const std::string& s)
|
||||
{
|
||||
huge_string_t result(s);
|
||||
result.pretend_huge = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
size_type size() const noexcept
|
||||
{
|
||||
if (pretend_huge)
|
||||
{
|
||||
// one byte more than the BSON length field can represent
|
||||
return static_cast<size_type>((std::numeric_limits<std::int32_t>::max)()) + 1;
|
||||
}
|
||||
return std::string::size();
|
||||
}
|
||||
|
||||
private:
|
||||
bool pretend_huge = false;
|
||||
};
|
||||
|
||||
using huge_string_json = nlohmann::basic_json <
|
||||
std::map, std::vector, huge_string_t, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, std::vector<std::uint8_t>, void >;
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("BSON")
|
||||
@@ -153,36 +105,10 @@ TEST_CASE("BSON")
|
||||
|
||||
SECTION("lengths exceeding INT32_MAX cannot be serialized to BSON")
|
||||
{
|
||||
// out_of_range.412 is thrown from a single shared helper
|
||||
// (to_bson_length) that guards the BSON length fields of binary
|
||||
// values, strings, and (embedded) documents alike
|
||||
SECTION("binary")
|
||||
{
|
||||
huge_binary_json j;
|
||||
j["b"] = huge_binary_json::binary(huge_binary_t{});
|
||||
huge_binary_json j;
|
||||
j["b"] = huge_binary_json::binary(huge_binary_t{});
|
||||
|
||||
CHECK_THROWS_WITH_AS(huge_binary_json::to_bson(j), "[json.exception.out_of_range.412] BSON length 2147483661 exceeds maximum of 2147483647", huge_binary_json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
huge_string_json j;
|
||||
j["s"] = huge_string_t::as_huge("value");
|
||||
|
||||
CHECK_THROWS_WITH_AS(huge_string_json::to_bson(j), "[json.exception.out_of_range.412] BSON length 2147483661 exceeds maximum of 2147483647", huge_string_json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("document")
|
||||
{
|
||||
// an oversized string nested one level deep makes the
|
||||
// *embedded* document's own length exceed INT32_MAX as well
|
||||
huge_string_json nested;
|
||||
nested["s"] = huge_string_t::as_huge("value");
|
||||
huge_string_json j;
|
||||
j["nested"] = nested;
|
||||
|
||||
CHECK_THROWS_WITH_AS(huge_string_json::to_bson(j), "[json.exception.out_of_range.412] BSON length 2147483674 exceeds maximum of 2147483647", huge_string_json::out_of_range&);
|
||||
}
|
||||
CHECK_THROWS_WITH_AS(huge_binary_json::to_bson(j), "[json.exception.out_of_range.412] BSON length 2147483661 exceeds maximum of 2147483647", huge_binary_json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("string length must be at least 1")
|
||||
@@ -267,23 +193,6 @@ TEST_CASE("BSON")
|
||||
CHECK(json::from_bson(result, true, false) == j);
|
||||
}
|
||||
|
||||
SECTION("non-empty object with bool from a non-0/1 byte (lenient parsing)")
|
||||
{
|
||||
// documented lenient behavior (see gh-5333): any non-zero byte
|
||||
// is accepted as `true`, not just 0x01
|
||||
std::vector<std::uint8_t> const input =
|
||||
{
|
||||
0x0D, 0x00, 0x00, 0x00, // size (little endian)
|
||||
0x08, // entry: boolean
|
||||
'e', 'n', 't', 'r', 'y', '\x00',
|
||||
0x02, // value = 0x02 (neither 0x00 nor 0x01)
|
||||
0x00 // end marker
|
||||
};
|
||||
|
||||
const json expected = { { "entry", true } };
|
||||
CHECK(json::from_bson(input) == expected);
|
||||
}
|
||||
|
||||
SECTION("non-empty object with double")
|
||||
{
|
||||
json const j =
|
||||
@@ -590,29 +499,6 @@ TEST_CASE("BSON")
|
||||
CHECK(json::from_bson(result, true, false) == j);
|
||||
}
|
||||
|
||||
SECTION("array elements with non-conforming keys (lenient parsing)")
|
||||
{
|
||||
// documented lenient behavior (see gh-5333): BSON array element
|
||||
// keys are not checked against the required decimal sequence
|
||||
// "0", "1", "2", ... - elements are taken in encoded order
|
||||
std::vector<std::uint8_t> const input =
|
||||
{
|
||||
0x26, 0x00, 0x00, 0x00, // size (little endian)
|
||||
0x04, 'e', 'n', 't', 'r', 'y', '\x00', // entry: embedded array
|
||||
|
||||
0x1A, 0x00, 0x00, 0x00, // size (little endian)
|
||||
0x10, '5', 0x00, 0x0A, 0x00, 0x00, 0x00, // key "5" (bogus) -> 10
|
||||
0x10, 'x', 0x00, 0x14, 0x00, 0x00, 0x00, // key "x" (non-numeric) -> 20
|
||||
0x10, '1', 0x00, 0x1E, 0x00, 0x00, 0x00, // key "1" (out of order) -> 30
|
||||
0x00, // end marker (embedded array)
|
||||
|
||||
0x00 // end marker
|
||||
};
|
||||
|
||||
const json expected = { { "entry", json::array({10, 20, 30}) } };
|
||||
CHECK(json::from_bson(input) == expected);
|
||||
}
|
||||
|
||||
SECTION("non-empty object with binary member")
|
||||
{
|
||||
const size_t N = 10;
|
||||
@@ -708,31 +594,6 @@ TEST_CASE("BSON")
|
||||
CHECK(json::from_bson(result, true, false) == j);
|
||||
}
|
||||
|
||||
SECTION("binary member with subtype 0x02 (old binary) keeps its inner length prefix (lenient parsing)")
|
||||
{
|
||||
// documented lenient behavior (see gh-5333): the payload for
|
||||
// binary subtype 0x02 ("old binary") is returned as-is,
|
||||
// including its own inner 4-byte length prefix; it is not
|
||||
// stripped or reinterpreted
|
||||
std::vector<std::uint8_t> const input =
|
||||
{
|
||||
0x17, 0x00, 0x00, 0x00, // size (little endian)
|
||||
0x05, 'e', 'n', 't', 'r', 'y', '\x00', // entry: binary
|
||||
|
||||
0x06, 0x00, 0x00, 0x00, // size of binary (little endian)
|
||||
0x02, // "old binary" subtype
|
||||
0x02, 0x00, 0x00, 0x00, // inner length prefix (part of the old-binary payload)
|
||||
0x68, 0x69, // payload ('h', 'i')
|
||||
|
||||
0x00 // end marker
|
||||
};
|
||||
|
||||
// the inner length prefix is part of the (unmodified) payload
|
||||
const std::vector<std::uint8_t> expected_payload = {0x02, 0x00, 0x00, 0x00, 0x68, 0x69};
|
||||
const json expected = { { "entry", json::binary(expected_payload, 0x02) } };
|
||||
CHECK(json::from_bson(input) == expected);
|
||||
}
|
||||
|
||||
SECTION("Some more complex document")
|
||||
{
|
||||
json const j =
|
||||
|
||||
@@ -23,8 +23,6 @@ using nlohmann::json;
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxEventLogger
|
||||
@@ -626,8 +624,7 @@ TEST_CASE("parser class")
|
||||
SECTION("overflow")
|
||||
{
|
||||
// overflows during parsing yield an exception
|
||||
// empty() is nodiscard; the exception is thrown by parser_helper() itself, before empty() would run
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(parser_helper("1.18973e+4932").empty()), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("invalid numbers")
|
||||
@@ -933,98 +930,6 @@ TEST_CASE("parser class")
|
||||
CHECK(accept_helper("+1") == false);
|
||||
CHECK(accept_helper("+0") == false);
|
||||
}
|
||||
|
||||
SECTION("issue #5411 - skip conversion when accept() does not need the numeric value")
|
||||
{
|
||||
// lexer::scan_number() may skip strtoull()/strtoll() for
|
||||
// value_unsigned/value_integer tokens when the caller (e.g.
|
||||
// json::accept()) does not need the converted value, as long
|
||||
// as the digit count alone guarantees no 64-bit overflow (see
|
||||
// the "safe_digit_count" fast path in scan_number()). This
|
||||
// differential test checks that json::accept() (which enables
|
||||
// the fast path) and json::parse() (which never does) always
|
||||
// agree, over a corpus that exercises both the fast path
|
||||
// (<=18 digits) and the untouched, exact fallback path (>=19
|
||||
// digits) -- including reclassification of huge digit-only
|
||||
// integers to a (possibly non-finite) floating-point value.
|
||||
const std::vector<std::pair<std::string, bool>> cases =
|
||||
{
|
||||
// normal small/large integers, both signs
|
||||
{"0", true}, {"1", true}, {"-1", true}, {"42", true}, {"-42", true},
|
||||
{"123456789", true}, {"-123456789", true},
|
||||
|
||||
// digit-count boundary around the 18-digit safe cutoff (both signs)
|
||||
{std::string(17, '9'), true},
|
||||
{std::string(18, '9'), true},
|
||||
{std::string(19, '9'), true},
|
||||
{std::string(20, '9'), true},
|
||||
{"-" + std::string(17, '9'), true},
|
||||
{"-" + std::string(18, '9'), true},
|
||||
{"-" + std::string(19, '9'), true},
|
||||
{"-" + std::string(20, '9'), true},
|
||||
|
||||
// 64-bit boundaries
|
||||
{"9223372036854775807", true}, // INT64_MAX
|
||||
{"-9223372036854775808", true}, // INT64_MIN
|
||||
{"18446744073709551615", true}, // UINT64_MAX
|
||||
{"18446744073709551616", true}, // UINT64_MAX + 1 (overflows uint64_t, finite double)
|
||||
|
||||
// the 28-digit example from the issue: overflows uint64_t
|
||||
// but is finite as a double, so the scanner reclassifies
|
||||
// it to value_float and it is accepted
|
||||
{"9999999999999999999999999999", true},
|
||||
|
||||
// huge digit-only integers that overflow even a double -> rejected
|
||||
{std::string(309, '9'), false},
|
||||
{std::string(400, '9'), false},
|
||||
{"1" + std::string(400, '0'), false},
|
||||
|
||||
// 1e999 / 1e400 style overflow -> rejected
|
||||
{"1e999", false},
|
||||
{"1e400", false},
|
||||
{"-1e999", false},
|
||||
{"1E999", false},
|
||||
|
||||
// values straddling DBL_MAX
|
||||
{"1.7976931348623157e308", true}, // <= DBL_MAX, finite
|
||||
{"1.7976931348623159e308", false}, // > DBL_MAX, overflows to inf
|
||||
|
||||
// a mix of other valid/invalid numeric syntax
|
||||
{"3.14159", true},
|
||||
{"-0.0", true},
|
||||
{"1.0e10", true},
|
||||
{"01", false},
|
||||
{"-", false},
|
||||
{"1.", false},
|
||||
{"1e", false},
|
||||
{"+1", false},
|
||||
};
|
||||
|
||||
for (const auto& c : cases)
|
||||
{
|
||||
const std::string& number = c.first;
|
||||
const bool expected = c.second;
|
||||
CAPTURE(number)
|
||||
CAPTURE(expected)
|
||||
|
||||
// accept() takes the fast path (skips conversion when possible)
|
||||
CHECK(json::accept(number) == expected);
|
||||
|
||||
// parse() always performs the full conversion; it must agree
|
||||
json j;
|
||||
CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(number), nullptr, false).parse(true, j));
|
||||
CHECK(!j.is_discarded() == expected);
|
||||
|
||||
// wrap in an array so get_token() is exercised beyond the
|
||||
// very first (constructor-time) scan as well
|
||||
std::string wrapped = "[";
|
||||
wrapped += number;
|
||||
wrapped += ",";
|
||||
wrapped += number;
|
||||
wrapped += "]";
|
||||
CHECK(json::accept(wrapped) == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1489,71 +1394,6 @@ TEST_CASE("parser class")
|
||||
CHECK(accept_helper("\"\\uD80C\\uFFFF\"") == false);
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
SECTION("issue #5412 - whitespace skipping bookkeeping (compact vs. pretty-printed)")
|
||||
{
|
||||
// lexer::skip_whitespace() reads its first character with get() (to
|
||||
// honor a possibly pending unget() from the previous token) and every
|
||||
// further whitespace character with get_ignoring_pending_unget() (a
|
||||
// get() variant that skips the then-always-false next_unget check).
|
||||
// This must not change the reported byte offset, line, or column of
|
||||
// a syntax error, even when a long run of whitespace containing
|
||||
// multiple newlines is skipped beforehand (as with pretty-printed
|
||||
// input). The expected values below were captured from the
|
||||
// unmodified do-while(get()) loop, so any regression that miscounts
|
||||
// characters or newlines while skipping whitespace changes them.
|
||||
const auto check_error = [](const std::string & input, std::size_t expected_byte,
|
||||
const std::string & expected_what)
|
||||
{
|
||||
CAPTURE(input)
|
||||
try
|
||||
{
|
||||
json _ = json::parse(input);
|
||||
FAIL_CHECK("expected a parse_error, but parsing succeeded");
|
||||
}
|
||||
catch (const json::parse_error& e)
|
||||
{
|
||||
CHECK(e.byte == expected_byte);
|
||||
CHECK(std::string(e.what()) == expected_what);
|
||||
}
|
||||
};
|
||||
|
||||
// a nested document, serialized both compactly and pretty-printed
|
||||
// (dump(4)), each truncated right before the final closing '}' so
|
||||
// that the parser hits EOF after skipping all of the (in the
|
||||
// pretty-printed case, substantial) indentation whitespace
|
||||
const json doc =
|
||||
{
|
||||
{"a", 1},
|
||||
{"b", json::array({true, false, nullptr, "x"})},
|
||||
{"c", json::object({{"d", 3.14}, {"e", json::array({1, 2, 3})}})}
|
||||
};
|
||||
|
||||
const std::string compact = doc.dump();
|
||||
const std::string pretty = doc.dump(4);
|
||||
|
||||
check_error(compact.substr(0, compact.size() - 1), 60,
|
||||
"[json.exception.parse_error.101] parse error at line 1, column 60: syntax error while parsing object - unexpected end of input; expected '}'");
|
||||
check_error(pretty.substr(0, pretty.size() - 1), 193,
|
||||
"[json.exception.parse_error.101] parse error at line 17, column 1: syntax error while parsing object - unexpected end of input; expected '}'");
|
||||
|
||||
// an invalid token appearing after several indented, multi-line
|
||||
// whitespace runs vs. the same document without any of that
|
||||
// whitespace
|
||||
check_error(R"({
|
||||
"a": 1,
|
||||
"b": [
|
||||
true,
|
||||
false
|
||||
],
|
||||
"c": @
|
||||
})", 70,
|
||||
"[json.exception.parse_error.101] parse error at line 7, column 10: syntax error while parsing value - invalid literal; last read: '\"c\": @'");
|
||||
check_error(R"({"a":1,"b":[true,false],"c":@})", 29,
|
||||
"[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing value - invalid literal; last read: '\"c\":@'");
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("tests found by mutate++")
|
||||
{
|
||||
// test case to make sure no comma precedes the first key
|
||||
|
||||
@@ -22,8 +22,6 @@ using nlohmann::json;
|
||||
|
||||
#include <valarray>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxEventLogger
|
||||
@@ -631,8 +629,7 @@ TEST_CASE("parser class")
|
||||
SECTION("overflow")
|
||||
{
|
||||
// overflows during parsing yield an exception
|
||||
// empty() is nodiscard; the exception is thrown by parser_helper() itself, before empty() would run
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(parser_helper("1.18973e+4932").empty()), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("invalid numbers")
|
||||
|
||||
@@ -1389,37 +1389,6 @@ TEST_CASE("value conversion")
|
||||
// CHECK(m5["one"] == "eins");
|
||||
}
|
||||
|
||||
SECTION("reserve is called on containers that support it (#5406)")
|
||||
{
|
||||
// build a larger object so that a missing/incorrect reserve()
|
||||
// call would be more likely to corrupt or drop elements
|
||||
json j_large;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
j_large[std::to_string(i)] = i;
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map (supports reserve)")
|
||||
{
|
||||
const auto m = j_large.get<std::unordered_map<std::string, int>>();
|
||||
CHECK(m.size() == 100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
CHECK(m.at(std::to_string(i)) == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::map (no reserve, fallback path)")
|
||||
{
|
||||
const auto m = j_large.get<std::map<std::string, int>>();
|
||||
CHECK(m.size() == 100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
CHECK(m.at(std::to_string(i)) == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::multimap")
|
||||
{
|
||||
j1.get<std::multimap<std::string, int>>();
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// This file contains the C++17-only part of unit-items.cpp (structured
|
||||
// bindings support for json::items()). It is kept in a separate
|
||||
// translation unit so the (much larger) unit-items.cpp does not need to
|
||||
// be compiled a second time just for this one SECTION.
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("items()")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("structured bindings")
|
||||
{
|
||||
json j = { {"A", 1}, {"B", 2} };
|
||||
|
||||
std::map<std::string, int> m;
|
||||
|
||||
for (auto const&[key, value] : j.items())
|
||||
{
|
||||
m.emplace(key, value);
|
||||
}
|
||||
|
||||
CHECK(j.get<decltype(m)>() == m);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -862,6 +862,22 @@ TEST_CASE("items()")
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
SECTION("structured bindings")
|
||||
{
|
||||
json j = { {"A", 1}, {"B", 2} };
|
||||
|
||||
std::map<std::string, int> m;
|
||||
|
||||
for (auto const&[key, value] : j.items())
|
||||
{
|
||||
m.emplace(key, value);
|
||||
}
|
||||
|
||||
CHECK(j.get<decltype(m)>() == m);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("const object")
|
||||
|
||||
@@ -1389,192 +1389,6 @@ TEST_CASE("JSON patch - add to a primitive parent (regression #4292)")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JSON patch - remove with primitive or null parent (regression #5396)")
|
||||
{
|
||||
// Regression test for https://github.com/nlohmann/json/issues/5396
|
||||
//
|
||||
// RFC 6902 (§4.2) requires the target location of a "remove" operation
|
||||
// to exist. When the target's parent resolves to a primitive value or
|
||||
// null, the operation must fail. Previously operation_remove silently
|
||||
// did nothing in this case (neither the "is_object" nor the "is_array"
|
||||
// branch matched, and there was no final "else"), so the patch appeared
|
||||
// to succeed without changing the document. It now throws
|
||||
// out_of_range.413.
|
||||
|
||||
SECTION("parent is a primitive (number)")
|
||||
{
|
||||
json const doc = {{"a", 1}};
|
||||
json const patch = {{{"op", "remove"}, {"path", "/a/b"}}};
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.413] (/a) cannot remove value: the JSON Patch 'remove' target's parent is of type number, but must be an object or array", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.413] cannot remove value: the JSON Patch 'remove' target's parent is of type number, but must be an object or array", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("parent is a primitive (string)")
|
||||
{
|
||||
json const doc = {{"foo", {{"bar", "a string"}}}};
|
||||
json const patch = {{{"op", "remove"}, {"path", "/foo/bar/baz"}}};
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.413] (/foo/bar) cannot remove value: the JSON Patch 'remove' target's parent is of type string, but must be an object or array", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.413] cannot remove value: the JSON Patch 'remove' target's parent is of type string, but must be an object or array", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("top-level document is null")
|
||||
{
|
||||
json const doc = nullptr;
|
||||
json const patch = {{{"op", "remove"}, {"path", "/a"}}};
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.413] cannot remove value: the JSON Patch 'remove' target's parent is of type null, but must be an object or array", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("legitimate removes still work")
|
||||
{
|
||||
// object member
|
||||
json const doc1 = {{"a", 1}, {"b", 2}};
|
||||
json const patch1 = {{{"op", "remove"}, {"path", "/a"}}};
|
||||
CHECK(doc1.patch(patch1) == json({{"b", 2}}));
|
||||
|
||||
// array element
|
||||
json const doc2 = R"([1, 2, 3])"_json;
|
||||
json const patch2 = {{{"op", "remove"}, {"path", "/1"}}};
|
||||
CHECK(doc2.patch(patch2) == R"([1, 3])"_json);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JSON patch - move where 'from' is a proper prefix of 'path' (regression #5397)")
|
||||
{
|
||||
// Regression test for https://github.com/nlohmann/json/issues/5397
|
||||
//
|
||||
// RFC 6902 (§4.4) forbids "from" from being a proper prefix of "path"
|
||||
// for a "move" operation: "a location cannot be moved into one of its
|
||||
// children." "move" is implemented as remove-then-add; for an object
|
||||
// target this happened to throw anyway as a side effect of the "add"
|
||||
// step re-resolving through the now-removed parent, but for an array
|
||||
// target the removal shifted subsequent indices, so "path" silently
|
||||
// re-resolved to a different element and the operation "succeeded"
|
||||
// with a corrupted result. It now throws out_of_range.414 for both
|
||||
// object and array targets.
|
||||
|
||||
SECTION("array target (from the issue)")
|
||||
{
|
||||
json const doc = R"([[1,2],[3]])"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/0"}, {"path", "/0/0"}}};
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] (bytes 0-11) cannot move value: 'from' path '/0' is a proper prefix of 'path' '/0/0'", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] cannot move value: 'from' path '/0' is a proper prefix of 'path' '/0/0'", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("object target")
|
||||
{
|
||||
json const doc = R"({"a": {"b": 1}})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/a"}, {"path", "/a/b"}}};
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] (bytes 0-15) cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/b'", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/b'", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("from == path is not a proper prefix and must not be rejected")
|
||||
{
|
||||
// "from" equal to "path" is a no-op move; it is not a *proper*
|
||||
// prefix relationship, so this new check must not reject it.
|
||||
json const doc = R"({"a": 1, "b": 2})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/a"}, {"path", "/a"}}};
|
||||
CHECK(doc.patch(patch) == doc);
|
||||
}
|
||||
|
||||
SECTION("raw string prefix that is not a pointer-token prefix must be allowed")
|
||||
{
|
||||
// "/ab" is a string-prefix of "/abc/x" as raw text, but "ab" and
|
||||
// "abc" are different reference tokens, so this is NOT a
|
||||
// pointer-token prefix relationship and the move must succeed.
|
||||
// This is the key case proving the check compares tokens, not
|
||||
// raw pointer text (a naive std::string prefix/rfind check on
|
||||
// the undecoded pointer would wrongly reject this).
|
||||
json const doc = R"({"ab": 1, "abc": {"x": 2}})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/ab"}, {"path", "/abc/x"}}};
|
||||
json const result = R"({"abc": {"x": 1}})"_json;
|
||||
CHECK(doc.patch(patch) == result);
|
||||
}
|
||||
|
||||
SECTION("escaped reference tokens are compared unescaped")
|
||||
{
|
||||
// "from" is the single token "a/b" (escaped as "a~1b"); "path"
|
||||
// addresses member "x" of that same value, so "from" is a
|
||||
// proper (token-level) prefix of "path" and must be rejected.
|
||||
json const doc = R"({"a/b": {"x": 1}})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/a~1b"}, {"path", "/a~1b/x"}}};
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] (bytes 0-17) cannot move value: 'from' path '/a~1b' is a proper prefix of 'path' '/a~1b/x'", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] cannot move value: 'from' path '/a~1b' is a proper prefix of 'path' '/a~1b/x'", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("ordinary valid moves still work")
|
||||
{
|
||||
// unrelated top-level members
|
||||
json const doc1 = R"({"a": 1, "b": 2})"_json;
|
||||
json const patch1 = {{{"op", "move"}, {"from", "/a"}, {"path", "/c"}}};
|
||||
CHECK(doc1.patch(patch1) == R"({"b": 2, "c": 1})"_json);
|
||||
|
||||
// sibling paths that share a textual prefix but are unrelated
|
||||
json const doc2 = R"({"a": {"x": 1}, "b": {"y": 2}})"_json;
|
||||
json const patch2 = {{{"op", "move"}, {"from", "/a/x"}, {"path", "/b/z"}}};
|
||||
CHECK(doc2.patch(patch2) == R"({"a": {}, "b": {"y": 2, "z": 1}})"_json);
|
||||
|
||||
// "path" is a proper prefix of "from" (the reverse relationship,
|
||||
// which RFC 6902 does not forbid)
|
||||
json const doc3 = R"({"a": {"b": 1}})"_json;
|
||||
json const patch3 = {{{"op", "move"}, {"from", "/a/b"}, {"path", "/a"}}};
|
||||
CHECK(doc3.patch(patch3) == R"({"a": 1})"_json);
|
||||
}
|
||||
|
||||
SECTION("root 'from' is a proper prefix of every non-root 'path'")
|
||||
{
|
||||
// the whole document is a proper prefix of any location inside it
|
||||
json const doc = R"({"a": 1})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", ""}, {"path", "/a"}}};
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] (bytes 0-8) cannot move value: 'from' path '' is a proper prefix of 'path' '/a'", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] cannot move value: 'from' path '' is a proper prefix of 'path' '/a'", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("root 'path' is never a proper prefix violation for a non-root 'from'")
|
||||
{
|
||||
// the reverse of the above: moving a non-root location to the root
|
||||
// is the "path is a prefix of from" relationship, which RFC 6902
|
||||
// permits (already covered generally above; this pins the root
|
||||
// case specifically, since root is the one path with no reference
|
||||
// tokens at all)
|
||||
json const doc = R"({"a": {"b": 1}})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/a"}, {"path", ""}}};
|
||||
CHECK(doc.patch(patch) == R"({"b": 1})"_json);
|
||||
}
|
||||
|
||||
SECTION("the array-append token '-' is an ordinary child token")
|
||||
{
|
||||
// "-" (append-to-array) addresses a location *inside* the array,
|
||||
// so "from" pointing at the array is still a proper prefix of
|
||||
// "path" ending in "-" and must be rejected like any other child.
|
||||
json const doc = R"({"a": [1, 2]})"_json;
|
||||
json const patch = {{{"op", "move"}, {"from", "/a"}, {"path", "/a/-"}}};
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] (bytes 0-13) cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/-'", json::out_of_range&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(doc.patch(patch), "[json.exception.out_of_range.414] cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/-'", json::out_of_range&);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JSON patch - diff emits array removals in descending index order")
|
||||
{
|
||||
SECTION("array shrunk to empty")
|
||||
|
||||
@@ -319,44 +319,6 @@ TEST_CASE("JSON pointers")
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
|
||||
// #5395: contains() must not throw for a reference token that is a
|
||||
// syntactically valid array index but numerically exceeds ULLONG_MAX
|
||||
// (causing strtoull() to set errno to ERANGE) -- it should just report
|
||||
// that the pointer does not resolve to an element
|
||||
CHECK(!j.contains(jp));
|
||||
CHECK(!j_const.contains(jp));
|
||||
}
|
||||
|
||||
{
|
||||
// #5395: same as above, but using the exact reproduction from the issue
|
||||
json::json_pointer const jp("/99999999999999999999");
|
||||
std::string const throw_msg = "[json.exception.out_of_range.404] unresolved reference token '99999999999999999999'";
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j.at(jp) = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at(jp) == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
|
||||
CHECK(!j.contains(jp));
|
||||
CHECK(!j_const.contains(jp));
|
||||
}
|
||||
|
||||
{
|
||||
// #5395: a reference token that is numerically representable in
|
||||
// unsigned long long but exceeds size_type's max (e.g. ULLONG_MAX
|
||||
// itself on typical 64-bit platforms, where size_type's max equals
|
||||
// ULLONG_MAX) must not make contains() throw either
|
||||
json::json_pointer const jp("/18446744073709551615");
|
||||
std::string const throw_msg = "[json.exception.out_of_range.410] array index 18446744073709551615 exceeds size_type";
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j.at(jp) = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at(jp) == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
|
||||
CHECK(!j.contains(jp));
|
||||
CHECK(!j_const.contains(jp));
|
||||
}
|
||||
|
||||
// on some machines, the check below is not constant
|
||||
@@ -372,10 +334,6 @@ TEST_CASE("JSON pointers")
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
|
||||
// #5395: contains() must not throw for a reference token exceeding size_type's max
|
||||
CHECK(!j.contains(jp));
|
||||
CHECK(!j_const.contains(jp));
|
||||
}
|
||||
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// This file makes sure that none of the internal JSON_HEDLEY_* macros (vendored
|
||||
// from https://nemequ.github.io/hedley/, see
|
||||
// include/nlohmann/thirdparty/hedley/hedley.hpp) leak into the including
|
||||
// translation unit. include/nlohmann/detail/macro_unscope.hpp is supposed to
|
||||
// #undef every JSON_HEDLEY_* macro (via hedley_undef.hpp) once json.hpp has
|
||||
// been fully processed. See https://github.com/nlohmann/json/issues/5408,
|
||||
// where JSON_HEDLEY_PRAGMA, JSON_HEDLEY_PREDICT_TRUE, JSON_HEDLEY_PREDICT_FALSE,
|
||||
// and JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE escaped this cleanup because
|
||||
// hedley_undef.hpp had no matching #undef for them.
|
||||
//
|
||||
// hedley_undef_checks.inc (included below) is generated at CMake configure/
|
||||
// build time by cmake/scripts/gen_hedley_undef_check.cmake, which derives the
|
||||
// full list of JSON_HEDLEY_* macro names directly from hedley.hpp. That way
|
||||
// this test covers every macro Hedley actually defines -- not a hardcoded
|
||||
// snapshot that would silently go stale the next time `make update_hedley`
|
||||
// runs -- and can never drift from the vendored header.
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
TEST_CASE("JSON_HEDLEY macros do not leak after including json.hpp")
|
||||
{
|
||||
#include "hedley_undef_checks.inc"
|
||||
CHECK(true); // keep an assertion when nothing leaked
|
||||
}
|
||||
@@ -29,7 +29,10 @@ using nlohmann::json;
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
#include "fifo_map.hpp"
|
||||
|
||||
@@ -1370,8 +1373,7 @@ TEST_CASE("regression tests 1")
|
||||
std::array<uint8_t, 28> key1 = {{ 103, 92, 117, 48, 48, 48, 55, 92, 114, 215, 126, 214, 95, 92, 34, 174, 40, 71, 38, 174, 40, 71, 38, 223, 134, 247, 127, 0 }};
|
||||
std::string const key1_str(reinterpret_cast<char*>(key1.data()));
|
||||
json const j = key1_str;
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] invalid UTF-8 byte at index 10: 0x7E", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 10: 0x7E", json::type_error&);
|
||||
}
|
||||
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
|
||||
@@ -31,8 +31,6 @@ using ordered_json = nlohmann::ordered_json;
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <any>
|
||||
#include <variant>
|
||||
@@ -641,8 +639,7 @@ TEST_CASE("regression tests 2")
|
||||
s += static_cast<char>(i);
|
||||
}
|
||||
dump_test["1"] = s;
|
||||
// dump() is nodiscard; this only checks that dumping does not throw/crash
|
||||
utils::ignore_return_value(dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace));
|
||||
dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,14 +731,12 @@ TEST_CASE("regression tests 2")
|
||||
{
|
||||
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());
|
||||
// dump() is nodiscard; this only checks that dumping does not throw
|
||||
CHECK_NOTHROW(
|
||||
utils::ignore_return_value(
|
||||
j.dump(4, // Indent
|
||||
' ', // Indent char
|
||||
false, // Ensure ascii
|
||||
json::error_handler_t::strict // Error
|
||||
)));
|
||||
j.dump(4, // Indent
|
||||
' ', // Indent char
|
||||
false, // Ensure ascii
|
||||
json::error_handler_t::strict // Error
|
||||
));
|
||||
}
|
||||
|
||||
SECTION("PR #2181 - regression bug with lvalue")
|
||||
|
||||
@@ -14,8 +14,40 @@ using nlohmann::json;
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <new>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
namespace
|
||||
{
|
||||
// heap allocation counter used by the regression test for issue #5413
|
||||
// (https://github.com/nlohmann/json/issues/5413); disabled (and thus a
|
||||
// no-op besides the counting) unless explicitly toggled on
|
||||
bool count_heap_allocations = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::size_t heap_allocations = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
} // namespace
|
||||
|
||||
void* operator new (std::size_t size) // NOLINT(cppcoreguidelines-owning-memory,misc-new-delete-overloads)
|
||||
{
|
||||
if (count_heap_allocations)
|
||||
{
|
||||
++heap_allocations;
|
||||
}
|
||||
if (void* ptr = std::malloc(size)) // NOLINT(cppcoreguidelines-no-malloc,cppcoreguidelines-owning-memory)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
throw std::bad_alloc(); // NOLINT(hicpp-exception-baseclass)
|
||||
}
|
||||
|
||||
void operator delete (void* ptr) noexcept // NOLINT(cppcoreguidelines-owning-memory,misc-new-delete-overloads)
|
||||
{
|
||||
std::free(ptr); // NOLINT(cppcoreguidelines-no-malloc,cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
void operator delete (void* ptr, std::size_t /*size*/) noexcept // NOLINT(cppcoreguidelines-owning-memory,misc-new-delete-overloads)
|
||||
{
|
||||
std::free(ptr); // NOLINT(cppcoreguidelines-no-malloc,cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
TEST_CASE("serialization")
|
||||
{
|
||||
@@ -86,9 +118,8 @@ TEST_CASE("serialization")
|
||||
{
|
||||
const json j = "ä\xA9ü";
|
||||
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump(1, ' ', false, json::error_handler_t::strict)), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.dump(1, ' ', false, json::error_handler_t::strict), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
|
||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\"");
|
||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\"");
|
||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\"");
|
||||
@@ -98,9 +129,8 @@ TEST_CASE("serialization")
|
||||
{
|
||||
const json j = "123\xC2";
|
||||
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump(1, ' ', false, json::error_handler_t::strict)), json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
|
||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\"");
|
||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\"");
|
||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\"");
|
||||
@@ -110,9 +140,8 @@ TEST_CASE("serialization")
|
||||
{
|
||||
const json j = "123\xF1\xB0\x34\x35\x36";
|
||||
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34", json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump(1, ' ', false, json::error_handler_t::strict)), json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34", json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
|
||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\"");
|
||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\"");
|
||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\"");
|
||||
@@ -387,3 +416,76 @@ TEST_CASE("dump for basic_json with long double number_float_t")
|
||||
check_same(100.0L, 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("regression test for issue #5413 - lazily allocated indent_string")
|
||||
{
|
||||
// the serializer used to unconditionally allocate a 512-byte
|
||||
// indent_string in its constructor, even though it is only ever read
|
||||
// inside the pretty_print branches of dump(). This wasted a heap
|
||||
// allocation (and its matching deallocation) on every single compact
|
||||
// (i.e. non-pretty, the default) dump() call. indent_string is now
|
||||
// allocated lazily, the first time a pretty-print branch actually
|
||||
// needs it -- so a compact dump() must perform strictly fewer heap
|
||||
// allocations than a pretty dump() of the same value.
|
||||
const json j = {{"level", "info"}, {"msg", "hello world"}, {"id", 12345}};
|
||||
|
||||
// warm up anything unrelated to indentation (e.g., one-time locale
|
||||
// lookups) that might otherwise allocate on first use regardless of
|
||||
// pretty-printing, so it does not skew the counts measured below
|
||||
const auto warmup = j.dump();
|
||||
const auto warmup_pretty = j.dump(4);
|
||||
CHECK(!warmup.empty());
|
||||
CHECK(!warmup_pretty.empty());
|
||||
|
||||
SECTION("compact dump() has a stable, minimal allocation count")
|
||||
{
|
||||
count_heap_allocations = true;
|
||||
|
||||
heap_allocations = 0;
|
||||
const auto compact1 = j.dump();
|
||||
const auto allocs_compact1 = heap_allocations;
|
||||
|
||||
heap_allocations = 0;
|
||||
const auto compact2 = j.dump(-1);
|
||||
const auto allocs_compact2 = heap_allocations;
|
||||
|
||||
count_heap_allocations = false;
|
||||
|
||||
CHECK(compact1 == compact2);
|
||||
// dump() and dump(-1) both take the compact code path and must
|
||||
// never touch indent_string, so they allocate identically often
|
||||
CHECK(allocs_compact1 == allocs_compact2);
|
||||
}
|
||||
|
||||
SECTION("first pretty dump() allocates more than a compact dump()")
|
||||
{
|
||||
// use a tiny value whose compact ({"a":1}, 7 bytes) and pretty
|
||||
// ({"a": 1} with 1-space indent, 11 bytes) serializations both stay
|
||||
// well inside every common std::string small-string-optimization
|
||||
// buffer (>= 15 bytes on libstdc++/MSVC STL, >= 22 on libc++), so
|
||||
// building the result string itself causes no heap allocation
|
||||
// either way -- isolating indent_string as the only thing that can
|
||||
// possibly account for a difference in allocation count
|
||||
const json tiny = {{"a", 1}};
|
||||
|
||||
count_heap_allocations = true;
|
||||
|
||||
heap_allocations = 0;
|
||||
const auto compact = tiny.dump();
|
||||
const auto allocs_compact = heap_allocations;
|
||||
|
||||
heap_allocations = 0;
|
||||
const auto pretty = tiny.dump(1);
|
||||
const auto allocs_pretty = heap_allocations;
|
||||
|
||||
count_heap_allocations = false;
|
||||
|
||||
CHECK(compact == "{\"a\":1}");
|
||||
CHECK(pretty == "{\n \"a\": 1\n}");
|
||||
// a fresh serializer is created per dump() call; the pretty branch
|
||||
// lazily allocates indent_string on its first use, so it must
|
||||
// allocate at least once more than the compact branch, which never
|
||||
// touches indent_string at all
|
||||
CHECK(allocs_pretty > allocs_compact);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ using nlohmann::json;
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
TEST_CASE("Unicode (1/5)" * doctest::skip())
|
||||
{
|
||||
@@ -241,8 +240,7 @@ void roundtrip(bool success_expected, const std::string& s)
|
||||
if (success_expected)
|
||||
{
|
||||
// serialization succeeds
|
||||
// dump() is nodiscard; this only checks that dumping does not throw
|
||||
CHECK_NOTHROW(utils::ignore_return_value(j.dump()));
|
||||
CHECK_NOTHROW(j.dump());
|
||||
|
||||
// exclude parse test for U+0000
|
||||
if (s[0] != '\0')
|
||||
@@ -261,8 +259,7 @@ void roundtrip(bool success_expected, const std::string& s)
|
||||
else
|
||||
{
|
||||
// serialization fails
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
|
||||
// parsing JSON text fails
|
||||
CHECK_THROWS_AS(_ = json::parse(ps), json::parse_error&);
|
||||
|
||||
@@ -19,7 +19,6 @@ using nlohmann::json;
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
// this test suite uses static variables with non-trivial destructors
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
||||
else
|
||||
{
|
||||
// strict mode must throw if success is not expected
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
// ignore and replace must create different dumps
|
||||
CHECK(s_ignored != s_replaced);
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ using nlohmann::json;
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
// this test suite uses static variables with non-trivial destructors
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
||||
else
|
||||
{
|
||||
// strict mode must throw if success is not expected
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
// ignore and replace must create different dumps
|
||||
CHECK(s_ignored != s_replaced);
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ using nlohmann::json;
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
// this test suite uses static variables with non-trivial destructors
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
||||
else
|
||||
{
|
||||
// strict mode must throw if success is not expected
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
// ignore and replace must create different dumps
|
||||
CHECK(s_ignored != s_replaced);
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ using nlohmann::json;
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
// this test suite uses static variables with non-trivial destructors
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
||||
else
|
||||
{
|
||||
// strict mode must throw if success is not expected
|
||||
// dump() is nodiscard; the exception is thrown by dump() itself before it would return
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
// ignore and replace must create different dumps
|
||||
CHECK(s_ignored != s_replaced);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user