Compare commits

..
Author SHA1 Message Date
Niels Lohmann 855155d1ab Regenerate single_include after merging develop
The merge commit kept develop's single_include/nlohmann/json.hpp because
make amalgamate saw it as up to date.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 20:34:15 +02:00
Niels Lohmann 5fc53e3e0a Merge branch 'develop' into techdebt/5708-meta-cleanup
Conflicts:
- include/nlohmann/detail/conversions/from_json.hpp: kept the shared from_json_pair_array_to_map() body; develop's #5681 element-path fix (&p instead of &j) is already applied there
- include/nlohmann/detail/json_pointer.hpp: kept the parse_array_index()-based contains(); it already returns false for an empty token (#5614) and only uses documented StringType members (#5692)
- include/nlohmann/detail/macro_scope.hpp: combined develop's #5698 NLOHMANN_JSON_SERIALIZE_ENUM_STRICT message with the ::nlohmann::detail::templated_json_throw qualification
- single_include/nlohmann/json.hpp: regenerated with make amalgamate

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 20:30:46 +02:00
Niels Lohmann f30ee4bcfe Unify json_pointer's three array-index parsers
array_index(), contains() and get_checked_or_null() each re-implemented
the RFC 6901 array-index rules and the size_type range check: array_index()
does the canonical parse and throws; contains() (which must not throw,
#5395) re-validates every digit by hand and runs its own strtoull/ERANGE
check before calling array_index() anyway, parsing every array token
twice; get_checked_or_null() wraps array_index() in JSON_TRY/
JSON_INTERNAL_CATCH (detail::out_of_range&) to turn an unrepresentable
index into "not found".

Add a single private, noexcept parse_array_index(s, idx) returning an
array_index_status (ok / leading_zero / not_a_number / unresolved /
exceeds_size_type). array_index() becomes a thin wrapper mapping each
status to the existing parse_error.106/109 or out_of_range.404/410;
contains() and get_checked_or_null() switch on the status directly. This
removes contains()'s digit-validation loop and its second strtoull call,
and get_checked_or_null()'s JSON_TRY/JSON_INTERNAL_CATCH.

Bugfix as a consequence: get_checked_or_null()'s JSON_TRY/
JSON_INTERNAL_CATCH was dead code under JSON_NOEXCEPTION (JSON_TRY
expands to "if(true)" and the catch to "if(false)", so JSON_THROW's
std::abort() ran unconditionally), meaning value() and contains() would
abort instead of returning the default/false for an out-of-range-sized
or oversized array index when exceptions are disabled (#5672). Switching
on parse_array_index()'s return value instead of relying on an actual
throw/catch fixes this: get_checked_or_null() now returns nullptr for
array_index_status::unresolved/exceeds_size_type in every build
configuration, and still calls JSON_THROW (aborting under
JSON_NOEXCEPTION, as before) only for a malformed index
(leading_zero/not_a_number), matching its documented @throw list.

All existing error ids, messages and diagnostic paths are unchanged; a
few reference tokens that used to fail contains()'s manual per-character
validation (e.g. "1a") now fail via array_index_status::unresolved
instead, with no observable difference since contains() only returns
bool.

Adds regression tests to unit-element_access2.cpp's "access on array
type" section covering value() with an index that exceeds size_type and
one with a trailing non-digit, both of which must yield the default
value rather than abort/throw.

Public API: no change.

Overlaps #5700, #5614 and #5692, which touch the contains() and
get_checked_or_null() array hunks; this change replaces those hunks with
calls into the new shared parser, so a rebase will need to re-apply
their token-handling changes (e.g. the empty-token case) on top of the
switch statements here.

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

#5708 item 4
2026-09-30 18:27:29 +02:00
Niels Lohmann e32de7bb8c De-duplicate from_json.hpp's map and array-fallback bodies
Several from_json() overload pairs in from_json.hpp were copies of each
other, so a fix has to be applied twice (as #5681 already does):

- from_json(..., std::map&) and from_json(..., std::unordered_map&) for
  non-string keys had identical 16-line bodies: array check, m.clear(),
  pair check loop, m.emplace(...). Route both through a new
  from_json_pair_array_to_map(j, m) helper.
- The from_json_array_impl priority_tag<1> and priority_tag<0> fallbacks
  ran the same std::transform/std::inserter loop, differing only in
  ret.reserve(j.size()). Merge them into one body and, modeled on the
  existing from_json_object_reserve, add a from_json_array_reserve pair
  so the reserve() call is only made for ConstructibleArrayType that
  support it.

Error ids (type_error.302), messages, diagnostic paths ((at(0)/at(1))
and behavior for types with/without reserve() are unchanged; only the
duplication is removed.

Public API: no change.

Overlaps #5681, which changes the "&j" to "&p" line in both map bodies;
the shared helper here should make that a one-line change instead of two
on rebase.

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

#5708 item 5
2026-09-30 18:16:32 +02:00
Niels Lohmann 93231c6c2f Factor the repeated JSON_HAS_RANGES/MinGW guard into one macro
The std::ranges view conversion (excluded on MinGW because of its
incomplete C++20 ranges support, #4916) was gated by the same
#if JSON_HAS_RANGES && !defined(__MINGW32__) condition at seven
independent sites in to_json.hpp and type_traits.hpp, with the MinGW
rationale duplicated in two of them and missing from the rest. Since the
sites come in matching pairs (one enables is_compatible_range_view and a
view-based overload, the other adds the exclusion to the
plain-array-type overload), a drift between any pair would produce an
ambiguous or missing overload on exactly one platform.

Add JSON_HAS_RANGE_VIEW_CONVERSION next to JSON_HAS_RANGES in
macro_scope.hpp, combining both conditions with the #4916 reasoning in
one place, #undef it in macro_unscope.hpp, and use it at all seven
sites. This does not fold the MinGW check into JSON_HAS_RANGES itself:
JSON_HAS_RANGES is user-overridable and also gates the
enable_borrowed_range specialization in iteration_proxy.hpp, which is
not excluded on MinGW.

No behavior or public API change: JSON_HAS_RANGE_VIEW_CONVERSION expands
to exactly the condition that was previously written out at each site.

Overlaps #5585, #5600 and #3575, which touch the same to_json.hpp and
type_traits.hpp lines; the change here is a mechanical
search-and-replace of the guard condition and should rebase cleanly.

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

#5708 item 11
2026-09-30 18:12:58 +02:00
Niels Lohmann d254f62764 Move templated_json_throw into nlohmann::detail
templated_json_throw() was defined in macro_scope.hpp, which is included
outside NLOHMANN_JSON_NAMESPACE_BEGIN, so the helper leaked into the
global namespace as ::templated_json_throw with no ABI tag. Unqualified
lookup in NLOHMANN_JSON_SERIALIZE_ENUM_STRICT could then bind to a
same-named function declared in the user's own namespace instead, which
fails to compile with Clang ("does not name a template").

Move the helper next to the exception classes in exceptions.hpp, inside
nlohmann::detail, and call it qualified as
::nlohmann::detail::templated_json_throw<...>(...) from both macro
expansion sites. Rewrite the doc comment to give the real reason for the
helper (JSON_THROW may expand to code that discards its argument, e.g.
when exceptions are disabled) and fix the "supress" typo.

templated_json_throw was never released (added by #5151 after v3.12.0),
so it can be moved freely.

Adds a regression test that expands NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
inside a namespace declaring its own templated_json_throw.

Public API: no change (::templated_json_throw was an unreleased,
unintentional global-namespace leak with no callers relying on its
location).

Overlaps #5698, which rewrites the same two macro call lines; the
overlapping hunks are small and should be trivial to reconcile on
rebase.

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

#5708 item 2
2026-09-30 18:08:45 +02:00
Niels Lohmann 23aa069e63 Support any-rank C arrays in from_json, not just rank 1-4
from_json() for C arrays had four hand-unrolled overloads (rank 1-4,
added incrementally in #4262), each with its own nested loops. to_json()
already handles any rank recursively, so a rank-5+ C array could be
serialized but not read back with get_to()/get<>().

Replace the four overloads with one from_json() SFINAE-constrained on
get<remove_all_extents<T>::type>() existing, forwarding to a pair of
mutually recursive from_json_c_array_element() helpers: one assigns a
non-array element via get<T>(), the other loops over a array element and
recurses one dimension at a time. Each dimension still goes through at(),
so type_error.304/out_of_range.401 stay unchanged; ranks 1-4 keep their
existing behavior and semantics.

Adds rank-5 round-trip and mismatched-shape tests to unit-conversions.cpp.

Public API: additive only (rank 5+ C arrays become readable).

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

#5708 item 1
2026-09-30 18:00:16 +02:00
Niels Lohmann b5fad30499 Fix misplaced and stale comments in JSON_HAS_RANGES and conversions
The JSON_HAS_RANGES feature-detection block had its libc++ comment
sitting above the clang+libstdc++ branch it does not describe,
leaving the libc++ branch uncommented and the clang+libstdc++ branch
without its own rationale. Move each comment to sit under its own
branch, and give the clang+libstdc++ branch (added in issue 5161) its
own one-line reason referencing that issue instead of reusing the
libc++ branch's comment. Also fix a duplicated-word typo ("in large
in large cpp files") in from_json.hpp, drop two unanswered 2017
design questions left as comments in type_traits.hpp and
from_json.hpp that no longer reflect open questions, and correct
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's @since tag from 3.12.0 to
3.13.0, the release it was actually introduced in.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 10:11:36 +02:00
Niels Lohmann a9cc4243b7 Fix tautological clause in iter_impl's iterator category assertion
The static_assert meant to check the LegacyBidirectionalIterator
named requirement had a first clause comparing
std::bidirectional_iterator_tag to itself, which is always true and
checks nothing; only array_t::iterator was actually being checked,
despite the message claiming object iterators were checked too.
Drop the tautological clause, reword the message to describe what
is actually checked, and note that object_t may use a forward-only
iterator as long as reverse iteration and operator-- are unused.
The check is intentionally not extended to object_t::iterator, since
that would reject object types with forward-only iterators that
compile and work correctly today.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:54:59 +02:00
Niels Lohmann 03319da529 Remove duplicate const overload of json_pointer::get_checked
The const and non-const get_checked() overloads had byte-identical
50-line bodies, differing only in the signature. The remaining
template deduces a const-qualified BasicJsonType for const callers,
so at(), the out_of_range::create() calls and the bounds check all
still work.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:53:14 +02:00
Niels Lohmann ae9ef9dde1 Simplify is_ordered_map to reuse has_capacity
is_ordered_map re-detected capacity() with a C++03 sizeof/vararg
trick right after has_capacity did the same detection through
is_detected. For ordered_map, the old trick took the address of
std::vector::capacity, which [namespace.std]/6 makes unspecified.
Reuse has_capacity instead, which removes the unspecified-behavior
pointer-to-std-member and two NOLINT suppressions.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:50:52 +02:00
Niels Lohmann f9d4b51455 Remove unused would_call_std_* from NLOHMANN_CAN_CALL_STD_FUNC_IMPL
Besides detail::result_of_begin/end, which is_range and iterator_t use,
the macro defined a namespace detail2 with a tag type, a catch-all
overload and would_call_std_begin/end, plus would_call_std_begin/end
structs directly in namespace nlohmann. Nothing has used them since
they were added in #3020.

Reduce the macro to its detail part. Without the trailing struct the
';' after the two invocations would be an empty declaration that
-Wextra-semi flags, so drop it. macro_scope.hpp included
meta/detected.hpp only for this macro; all users of detected.hpp
include it (or type_traits.hpp) themselves, so remove the include.

Behavior and ABI are unchanged. The undocumented, untested and unused
names nlohmann::would_call_std_begin, nlohmann::would_call_std_end and
namespace nlohmann::detail2 are no longer declared.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:46:04 +02:00
Niels Lohmann 31883d06a8 Replace meta/logic.hpp with a disjunction trait
meta/logic.hpp added a second set of type-level boolean helpers
(cxpr_and, cxpr_or, cxpr_not, ...) next to the existing conjunction
and negation in type_traits.hpp. It was used only by one static_assert
in from_json_tuple_impl, two of its templates were never used, and it
was the only header without the license banner and relied on
transitive includes for <type_traits>.

Add the missing disjunction next to conjunction and negation, use the
three in the static_assert, and delete logic.hpp together with its
BUILD.bazel entry. same_sign now uses disjunction as well, which
resolves the 2022 TODO waiting for such a trait.

The static_assert accepts and rejects the same types as before. Only
names in nlohmann::detail change; behavior, public API and ABI are
unchanged.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:42:12 +02:00
Niels Lohmann 4c208728e7 Remove unused is_sax and is_detected_convertible
detail::is_sax had no user: the parser and the binary reader only use
is_sax_static_asserts, so is_sax was a second, unchecked copy of the
SAX event list. is_sax_static_asserts asserted boolean(bool) twice in
a row, and detail::is_detected_convertible was never used anywhere.

Remove all three and include <cstddef> for size_t instead of <cstdint>.
Only names in nlohmann::detail are removed; behavior, public API and ABI
are unchanged. The diagnostics for an incomplete SAX handler are the
same, apart from the duplicated boolean() message.

Part of #5708

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:38:54 +02:00
61 changed files with 944 additions and 1364 deletions
+5 -10
View File
@@ -1,15 +1,9 @@
# bugprone-use-after-move (hicpp-invalid-access-moved is its alias) still flags
# the basic_json move constructor, which forwards the whole object to its base
# class (#5724), and two forwards in the error-message construction of
# at(KeyType&&) (json.hpp, both overloads: find(std::forward<KeyType>(key))
# followed by string_t(std::forward<KeyType>(key)) in the throw), which #5689
# rewrites. Re-enable both checks once those changes have landed.
# portability-avoid-pragma-once: kept disabled on purpose. #pragma once is accepted
# by every supported compiler, and tools/amalgamate/amalgamate.py strips it from
# single_include, so there is nothing left to fix here.
# TODO: The first three checks are only removed to get the CI going. They have to be addressed at some point.
# TODO: portability-avoid-pragma-once: should be fixed eventually
Checks: '*,
-portability-template-virtual-member-function,
-bugprone-use-after-move,
-hicpp-invalid-access-moved,
@@ -43,6 +37,7 @@ Checks: '*,
-google-readability-function-size,
-google-runtime-float,
-google-runtime-int,
-google-runtime-references,
-hicpp-avoid-goto,
-hicpp-explicit-conversions,
-hicpp-function-size,
@@ -76,7 +71,6 @@ Checks: '*,
-readability-magic-numbers,
-readability-redundant-access-specifiers,
-readability-redundant-parentheses,
-readability-redundant-typename,
-readability-simplify-boolean-expr,
-readability-uppercase-literal-suffix,
-readability-use-concise-preprocessor-directives'
@@ -87,4 +81,5 @@ CheckOptions:
WarningsAsErrors: '*'
#HeaderFilterRegex: '.*nlohmann.*'
HeaderFilterRegex: '.*hpp$'
+4 -4
View File
@@ -78,13 +78,13 @@ jobs:
ci_static_analysis_clang:
runs-on: ubuntu-latest
container: silkeh/clang:22
container: silkeh/clang:dev
strategy:
matrix:
target: [ci_test_clang, ci_clang_tidy, ci_test_clang_sanitizer, ci_single_binaries]
target: [ci_test_clang, ci_clang_tidy, ci_test_clang_sanitizer, ci_clang_analyze, ci_single_binaries]
steps:
- name: Install git, iwyu (ci_single_binaries), and unzip
run: apt-get update ; apt-get install -y git iwyu unzip
- name: Install git, clang-tools, iwyu (ci_single_binaries), and unzip
run: apt-get update ; apt-get install -y git clang-tools iwyu unzip
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
-1
View File
@@ -53,7 +53,6 @@ cc_library(
"include/nlohmann/detail/meta/detected.hpp",
"include/nlohmann/detail/meta/identity_tag.hpp",
"include/nlohmann/detail/meta/is_sax.hpp",
"include/nlohmann/detail/meta/logic.hpp",
"include/nlohmann/detail/meta/std_fs.hpp",
"include/nlohmann/detail/meta/type_traits.hpp",
"include/nlohmann/detail/meta/void_t.hpp",
+20 -4
View File
@@ -8,24 +8,24 @@ set(N 10)
include(FindPython3)
find_package(Python3 COMPONENTS Interpreter)
find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-22 clang++-21 clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++)
find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-20 clang++-19 clang++-18 clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++)
execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}")
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-22 clang-tidy-21 clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy)
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-20 clang-tidy-19 clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy)
execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}")
message(STATUS "🔖 Clang-Tidy ${CLANG_TIDY_TOOL_VERSION} (${CLANG_TIDY_TOOL})")
message(STATUS "🔖 CMake ${CMAKE_VERSION} (${CMAKE_COMMAND})")
find_program(GCC_TOOL NAMES g++-latest g++-HEAD g++ g++-16 g++-15 g++-14 g++-13 g++-12 g++-11 g++-10)
find_program(GCC_TOOL NAMES g++-latest g++-HEAD g++ g++-15 g++-14 g++-13 g++-12 g++-11 g++-10)
execute_process(COMMAND ${GCC_TOOL} --version OUTPUT_VARIABLE GCC_TOOL_VERSION ERROR_VARIABLE GCC_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCC_TOOL_VERSION "${GCC_TOOL_VERSION}")
message(STATUS "🔖 GCC ${GCC_TOOL_VERSION} (${GCC_TOOL})")
find_program(GCOV_TOOL NAMES gcov-HEAD gcov gcov-16 gcov-15 gcov-14 gcov-13 gcov-12 gcov-11 gcov-10)
find_program(GCOV_TOOL NAMES gcov-HEAD gcov gcov-15 gcov-14 gcov-13 gcov-12 gcov-11 gcov-10)
execute_process(COMMAND ${GCOV_TOOL} --version OUTPUT_VARIABLE GCOV_TOOL_VERSION ERROR_VARIABLE GCOV_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCOV_TOOL_VERSION "${GCOV_TOOL_VERSION}")
message(STATUS "🔖 GCOV ${GCOV_TOOL_VERSION} (${GCOV_TOOL})")
@@ -69,6 +69,7 @@ message(STATUS "🔖 Valgrind ${VALGRIND_TOOL_VERSION} (${VALGRIND_TOOL})")
find_program(GENHTML_TOOL NAMES genhtml)
find_program(PLOG_CONVERTER_TOOL NAMES plog-converter)
find_program(PVS_STUDIO_ANALYZER_TOOL NAMES pvs-studio-analyzer)
find_program(SCAN_BUILD_TOOL NAMES scan-build-15 scan-build-14 scan-build-13 scan-build-12 scan-build-11 scan-build)
# the individual source files
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp)
@@ -425,6 +426,21 @@ add_custom_target(ci_test_valgrind
COMMENT "Compile and test with Valgrind"
)
###############################################################################
# Check code with Clang Static Analyzer.
###############################################################################
set(CLANG_ANALYZER_CHECKS "fuchsia.HandleChecker,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,optin.cplusplus.UninitializedObject,optin.cplusplus.VirtualCall,optin.mpi.MPI-Checker,optin.osx.OSObjectCStyleCast,optin.osx.cocoa.localizability.EmptyLocalizationContextChecker,optin.osx.cocoa.localizability.NonLocalizedStringChecker,optin.performance.GCDAntipattern,optin.performance.Padding,optin.portability.UnixAPI,security.FloatLoopCounter,security.insecureAPI.DeprecatedOrUnsafeBufferHandling,security.insecureAPI.bcmp,security.insecureAPI.bcopy,security.insecureAPI.bzero,security.insecureAPI.rand,security.insecureAPI.strcpy,valist.CopyToSelf,valist.Uninitialized,valist.Unterminated,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,core.CallAndMessage,core.DivideZero,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.VLASize,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.PlacementNew,cplusplus.PureVirtualCall,deadcode.DeadStores,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,osx.API,osx.MIG,osx.NumberObjectConversion,osx.OSObjectRetainCount,osx.ObjCProperty,osx.SecKeychainAPI,osx.cocoa.AtSync,osx.cocoa.AutoreleaseWrite,osx.cocoa.ClassRelease,osx.cocoa.Dealloc,osx.cocoa.IncompatibleMethodTypes,osx.cocoa.Loops,osx.cocoa.MissingSuperCall,osx.cocoa.NSAutoreleasePool,osx.cocoa.NSError,osx.cocoa.NilArg,osx.cocoa.NonNilReturnValue,osx.cocoa.ObjCGenerics,osx.cocoa.RetainCount,osx.cocoa.RunLoopAutoreleaseLeak,osx.cocoa.SelfInit,osx.cocoa.SuperDealloc,osx.cocoa.UnusedIvars,osx.cocoa.VariadicMethodTypes,osx.coreFoundation.CFError,osx.coreFoundation.CFNumber,osx.coreFoundation.CFRetainRelease,osx.coreFoundation.containers.OutOfBounds,osx.coreFoundation.containers.PointerSizedValues,security.insecureAPI.UncheckedReturn,security.insecureAPI.decodeValueOfObjCType,security.insecureAPI.getpw,security.insecureAPI.gets,security.insecureAPI.mkstemp,security.insecureAPI.mktemp,security.insecureAPI.vfork,unix.API,unix.Malloc,unix.MallocSizeof,unix.MismatchedDeallocator,unix.Vfork,unix.cstring.BadSizeArg,unix.cstring.NullArg")
add_custom_target(ci_clang_analyze
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=Debug -GNinja
-DJSON_BuildTests=ON
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_analyze
COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_analyze && ${SCAN_BUILD_TOOL} -enable-checker ${CLANG_ANALYZER_CHECKS} --use-c++=${CLANG_TOOL} -analyze-headers -o ${PROJECT_BINARY_DIR}/report ninja
COMMENT "Check code with Clang Analyzer"
)
###############################################################################
# Check code with Cppcheck.
###############################################################################
+2
View File
@@ -2,6 +2,7 @@
# -Wno-c++98-compat The library targets C++11.
# -Wno-c++98-compat-pedantic The library targets C++11.
# -Wno-deprecated-declarations The library contains annotations for deprecated functions.
# -Wno-extra-semi-stmt The library uses assert which triggers this warning.
# -Wno-padded We do not care about padding warnings.
# -Wno-covered-switch-default All switches list all cases and a default case.
# -Wno-c2y-extensions Clang 22.1 diagnoses __COUNTER__ as a C2y extension, also in
@@ -19,6 +20,7 @@ set(CLANG_CXXFLAGS
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
-Wno-deprecated-declarations
-Wno-extra-semi-stmt
-Wno-padded
-Wno-covered-switch-default
-Wno-c2y-extensions
+13 -24
View File
@@ -1,4 +1,4 @@
# Warning flags determined for GCC 16.2.0 with https://github.com/nlohmann/gcc_flags:
# Warning flags determined for GCC 15.1.0 with https://github.com/nlohmann/gcc_flags:
# Ignored GCC warnings:
# -Wno-abi-tag We do not care about ABI tags.
# -Wno-aggregate-return The library uses aggregate returns.
@@ -16,8 +16,6 @@ set(GCC_CXXFLAGS
--extra-warnings
-W
-WNSObject-attribute
-Wabbreviated-auto-in-template-arg
-Wabi
-Wno-abi-tag
-Waddress
-Waddress-of-packed-member
@@ -66,7 +64,6 @@ set(GCC_CXXFLAGS
-Wanalyzer-tainted-divisor
-Wanalyzer-tainted-offset
-Wanalyzer-tainted-size
-Wanalyzer-throw-of-unexpected-type
-Wanalyzer-too-complex
-Wanalyzer-undefined-behavior-ptrdiff
-Wanalyzer-undefined-behavior-strtok
@@ -83,13 +80,10 @@ set(GCC_CXXFLAGS
-Warith-conversion
-Warray-bounds=2
-Warray-compare
-Warray-parameter
-Warray-parameter=2
-Wattribute-alias=2
-Wattribute-warning
-Wattributes
-Wauto-profile
-Wbidi-chars=any
-Wbool-compare
-Wbool-operation
-Wbuiltin-declaration-mismatch
@@ -105,7 +99,6 @@ set(GCC_CXXFLAGS
-Wc++20-compat
-Wc++20-extensions
-Wc++23-extensions
-Wc++26-compat
-Wc++26-extensions
-Wc++2a-compat
-Wcalloc-transposed-args
@@ -149,7 +142,6 @@ set(GCC_CXXFLAGS
-Wdeprecated-enum-enum-conversion
-Wdeprecated-enum-float-conversion
-Wdeprecated-literal-operator
-Wdeprecated-openmp
-Wdeprecated-variadic-comma-omission
-Wdisabled-optimization
-Wdiv-by-zero
@@ -164,18 +156,21 @@ set(GCC_CXXFLAGS
-Wenum-conversion
-Wexceptions
-Wexpansion-to-defined
-Wexperimental-fmv-target
-Wexpose-global-module-tu-local
-Wexternal-tu-local
-Wextra
-Wextra-semi
-Wflex-array-member-not-at-end
-Wfloat-conversion
-Wfloat-equal
-Wformat-diag
-Wformat-overflow=2
-Wformat-signedness
-Wformat-truncation=2
-Wformat -Wformat-contains-nul
-Wformat -Wformat-diag
-Wformat -Wformat-extra-args
-Wformat -Wformat-nonliteral
-Wformat -Wformat-overflow=2
-Wformat -Wformat-security
-Wformat -Wformat-signedness
-Wformat -Wformat-truncation=2
-Wformat -Wformat-y2k
-Wformat -Wformat-zero-length
-Wformat=2
-Wframe-address
-Wfree-nonheap-object
@@ -202,8 +197,6 @@ set(GCC_CXXFLAGS
-Winvalid-offsetof
-Winvalid-pch
-Winvalid-utf8
-Wkeyword-macro
-Wleading-whitespace=spaces
-Wliteral-suffix
-Wlogical-not-parentheses
-Wlogical-op
@@ -234,7 +227,6 @@ set(GCC_CXXFLAGS
-Wnarrowing
-Wnoexcept
-Wnoexcept-type
-Wnon-c-typedef-for-linkage
-Wnon-template-friend
-Wnon-virtual-dtor
-Wnonnull
@@ -277,8 +269,6 @@ set(GCC_CXXFLAGS
-Wscalar-storage-order
-Wself-move
-Wsequence-point
-Wsfinae-incomplete
-Wsfinae-incomplete=2
-Wshadow=compatible-local
-Wshadow=global
-Wshadow=local
@@ -299,7 +289,6 @@ set(GCC_CXXFLAGS
-Wstrict-aliasing=3
-Wstrict-null-sentinel
-Wstrict-overflow
-Wstrict-overflow=5
-Wstring-compare
-Wstringop-overflow
-Wstringop-overflow=4
@@ -344,8 +333,8 @@ set(GCC_CXXFLAGS
-Wunreachable-code
-Wunsafe-loop-optimizations
-Wunused
-Wunused-but-set-parameter=3
-Wunused-but-set-variable=3
-Wunused-but-set-parameter
-Wunused-but-set-variable
-Wunused-const-variable=2
-Wunused-function
-Wunused-label
+2 -2
View File
@@ -60,11 +60,11 @@ measures that counter them. The measures are described in detail in [Quality ass
|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| Out-of-bounds read/write ([CWE-125](https://cwe.mitre.org/data/definitions/125.html), [CWE-787](https://cwe.mitre.org/data/definitions/787.html)) | bounds checks on all reads from the input; AddressSanitizer and Valgrind on the test suite; OSS-Fuzz |
| Integer overflow ([CWE-190](https://cwe.mitre.org/data/definitions/190.html)) | UndefinedBehaviorSanitizer with integer overflow detection; Clang-Tidy; Cppcheck |
| Use after free, double free ([CWE-416](https://cwe.mitre.org/data/definitions/416.html), [CWE-415](https://cwe.mitre.org/data/definitions/415.html)) | ownership of all memory by values; AddressSanitizer and Valgrind; Clang-Tidy (incl. Clang Static Analyzer checks) |
| Use after free, double free ([CWE-416](https://cwe.mitre.org/data/definitions/416.html), [CWE-415](https://cwe.mitre.org/data/definitions/415.html)) | ownership of all memory by values; AddressSanitizer and Valgrind; Clang Static Analyzer |
| Memory leaks ([CWE-401](https://cwe.mitre.org/data/definitions/401.html)) | Valgrind (Memcheck) on the test suite |
| Uncontrolled recursion ([CWE-674](https://cwe.mitre.org/data/definitions/674.html)) | iterative parser, binary readers, and destructor; bounded recursion in value operations; tests with deeply nested inputs |
| Uncontrolled resource consumption ([CWE-400](https://cwe.mitre.org/data/definitions/400.html)) | allocations based on announced sizes are capped; OSS-Fuzz with memory limits |
| Undefined behavior in general ([CWE-758](https://cwe.mitre.org/data/definitions/758.html)) | UndefinedBehaviorSanitizer; runtime assertions; Clang-Tidy (incl. Clang Static Analyzer checks), Cppcheck, Infer |
| Undefined behavior in general ([CWE-758](https://cwe.mitre.org/data/definitions/758.html)) | UndefinedBehaviorSanitizer; runtime assertions; Clang-Tidy, Cppcheck, Clang Static Analyzer, Infer |
In addition, every line of the library is covered by the unit tests, and all parsers are fuzz-tested around the clock
by [OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json).
@@ -183,8 +183,8 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
```
- [x] The code is checked with the latest [Cppcheck](https://cppcheck.sourceforge.io) with all warnings enabled.
- [x] The code is checked with the latest [Clang Static Analyzer](https://clang-analyzer.llvm.org) checks, run
through Clang-Tidy's `clang-analyzer-*` checks with warnings as errors.
- [x] The code is checked with the latest [Clang Static Analyzer](https://clang-analyzer.llvm.org) with 89 enabled
rules.
- [x] The code is checked with [Infer](https://fbinfer.com).
- [x] The code is checked with [Codacy](https://app.codacy.com/gh/nlohmann/json/dashboard).
+76 -124
View File
@@ -27,7 +27,6 @@
#include <nlohmann/detail/meta/identity_tag.hpp>
#include <nlohmann/detail/meta/std_fs.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/meta/logic.hpp>
#include <nlohmann/detail/string_concat.hpp>
#include <nlohmann/detail/value_t.hpp>
@@ -211,62 +210,29 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
});
}
// element is not itself a C array: read it directly
template<typename BasicJsonType, typename T>
auto from_json_c_array_element(const BasicJsonType& j, T& e)
-> decltype(e = j.template get<T>(), void())
{
e = j.template get<T>();
}
// element is itself a C array: recurse one dimension at a time, so any rank is supported
template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void())
void from_json_c_array_element(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
{
for (std::size_t i = 0; i < N; ++i)
{
arr[i] = j.at(i).template get<T>();
from_json_c_array_element(j.at(i), arr[i]);
}
}
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2>
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void())
template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<typename std::remove_all_extents<T>::type>(), void())
{
for (std::size_t i1 = 0; i1 < N1; ++i1)
{
for (std::size_t i2 = 0; i2 < N2; ++i2)
{
arr[i1][i2] = j.at(i1).at(i2).template get<T>();
}
}
}
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3>
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void())
{
for (std::size_t i1 = 0; i1 < N1; ++i1)
{
for (std::size_t i2 = 0; i2 < N2; ++i2)
{
for (std::size_t i3 = 0; i3 < N3; ++i3)
{
arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get<T>();
}
}
}
}
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3, std::size_t N4>
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void())
{
for (std::size_t i1 = 0; i1 < N1; ++i1)
{
for (std::size_t i2 = 0; i2 < N2; ++i2)
{
for (std::size_t i3 = 0; i3 < N3; ++i3)
{
for (std::size_t i4 = 0; i4 < N4; ++i4)
{
arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get<T>();
}
}
}
}
from_json_c_array_element(j, arr);
}
template<typename BasicJsonType>
@@ -286,20 +252,33 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
}
}
// reserve() is called through this pair (modeled on from_json_object_reserve)
// so from_json_array_impl below has a single body for both ConstructibleArrayType
// that support reserve() and those that don't.
template<typename ConstructibleArrayType>
auto from_json_array_reserve(ConstructibleArrayType& arr, typename ConstructibleArrayType::size_type size, priority_tag<1> /*unused*/)
-> decltype(arr.reserve(size), void())
{
arr.reserve(size);
}
template<typename ConstructibleArrayType>
inline void from_json_array_reserve(ConstructibleArrayType& /*arr*/, std::size_t /*size*/, priority_tag<0> /*unused*/)
{}
template<typename BasicJsonType, typename ConstructibleArrayType,
enable_if_t<
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
int> = 0>
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
-> decltype(
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
j.template get<typename ConstructibleArrayType::value_type>(),
void())
{
using std::end;
ConstructibleArrayType ret;
ret.reserve(j.size());
from_json_array_reserve(ret, j.size(), priority_tag<1> {});
std::transform(j.begin(), j.end(),
std::inserter(ret, end(ret)), [](const BasicJsonType & i)
{
@@ -310,27 +289,6 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
arr = std::move(ret);
}
template<typename BasicJsonType, typename ConstructibleArrayType,
enable_if_t<
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
int> = 0>
inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
priority_tag<0> /*unused*/)
{
using std::end;
ConstructibleArrayType ret;
std::transform(
j.begin(), j.end(), std::inserter(ret, end(ret)),
[](const BasicJsonType & i)
{
// get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType
return i.template get<typename ConstructibleArrayType::value_type>();
});
arr = std::move(ret);
}
template < typename BasicJsonType, typename ConstructibleArrayType,
enable_if_t <
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
@@ -354,22 +312,22 @@ void())
}
template < typename BasicJsonType, typename T, std::size_t... Idx >
std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(const BasicJsonType& j,
std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)
{
return { { j.at(Idx).template get<T>()... } };
return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };
}
template < typename BasicJsonType, typename T, std::size_t N >
auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
-> decltype(from_json_inplace_array_impl(j, tag, make_index_sequence<N> {}))
auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))
{
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
}
return from_json_inplace_array_impl(j, tag, make_index_sequence<N> {});
return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});
}
template<typename BasicJsonType>
@@ -433,9 +391,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
}
// overload for arithmetic types, not chosen for basic_json template arguments
// (BooleanType, etc.); note: Is it really necessary to provide explicit
// overloads for boolean_t etc. in case of a custom BooleanType which is not
// an arithmetic type?
// (BooleanType, etc.)
template < typename BasicJsonType, typename ArithmeticType,
enable_if_t <
std::is_arithmetic<ArithmeticType>::value&&
@@ -504,54 +460,74 @@ template<std::size_t PTagValue, typename BasicJsonType, typename... Types>
using tuple_type = std::tuple < decltype(from_json_tuple_get_impl(std::declval<BasicJsonType>(), detail::identity_tag<Types> {}, detail::priority_tag<PTagValue> {}))... >;
template<std::size_t PTagValue, typename... Args, typename BasicJsonType, std::size_t... Idx>
tuple_type<PTagValue, const BasicJsonType&, Args...> from_json_tuple_impl_base(const BasicJsonType& j, index_sequence<Idx...> /*unused*/)
tuple_type<PTagValue, BasicJsonType, Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
{
return tuple_type<PTagValue, const BasicJsonType&, Args...>(from_json_tuple_get_impl(j.at(Idx), detail::identity_tag<Args> {}, detail::priority_tag<PTagValue> {})...);
return tuple_type<PTagValue, BasicJsonType, Args...>(from_json_tuple_get_impl(std::forward<BasicJsonType>(j).at(Idx), detail::identity_tag<Args> {}, detail::priority_tag<PTagValue> {})...);
}
template<std::size_t PTagValue, typename BasicJsonType>
std::tuple<> from_json_tuple_impl_base(const BasicJsonType& /*unused*/, index_sequence<> /*unused*/)
std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/)
{
return {};
}
template < typename BasicJsonType, class A1, class A2 >
std::pair<A1, A2> from_json_tuple_impl(const BasicJsonType& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
{
return {j.at(0).template get<A1>(),
j.at(1).template get<A2>()};
return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
std::forward<BasicJsonType>(j).at(1).template get<A2>()};
}
template<typename BasicJsonType, typename A1, typename A2>
inline void from_json_tuple_impl(const BasicJsonType& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
{
p = from_json_tuple_impl(j, identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
}
template<typename BasicJsonType, typename... Args>
std::tuple<Args...> from_json_tuple_impl(const BasicJsonType& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
{
static_assert(cxpr_and<cxpr_or<cxpr_not<std::is_reference<Args>>, is_compatible_reference_type<const BasicJsonType&, Args>>...>::value,
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
return from_json_tuple_impl_base<1, Args...>(j, index_sequence_for<Args...> {});
return from_json_tuple_impl_base<1, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
}
template<typename BasicJsonType, typename... Args>
inline void from_json_tuple_impl(const BasicJsonType& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
{
t = from_json_tuple_impl_base<2, Args...>(j, index_sequence_for<Args...> {});
t = from_json_tuple_impl_base<2, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
}
template<typename BasicJsonType, typename TupleRelated>
auto from_json(const BasicJsonType& j, TupleRelated&& t)
-> decltype(from_json_tuple_impl(j, std::forward<TupleRelated>(t), priority_tag<3> {}))
auto from_json(BasicJsonType&& j, TupleRelated&& t)
-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))
{
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
}
return from_json_tuple_impl(j, std::forward<TupleRelated>(t), priority_tag<3> {});
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
}
// shared body for std::map/std::unordered_map with a non-string Key: both
// containers are read from an array of [key, value] pairs the same way
template<typename BasicJsonType, typename MapType>
inline void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
}
m.clear();
for (const auto& p : j)
{
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &p));
}
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
}
}
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
@@ -559,19 +535,7 @@ template < typename BasicJsonType, typename Key, typename Value, typename Compar
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
}
m.clear();
for (const auto& p : j)
{
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &p));
}
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
}
from_json_pair_array_to_map(j, m);
}
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
@@ -579,24 +543,12 @@ template < typename BasicJsonType, typename Key, typename Value, typename Hash,
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
}
m.clear();
for (const auto& p : j)
{
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &p));
}
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
}
from_json_pair_array_to_map(j, m);
}
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
// Workaround for MSVC 19.51 (and possibly later): in large in large cpp files, the compiler may fail to resolve with generic has_from_json (issue #4996)
// Workaround for MSVC 19.51 (and possibly later): in large cpp files, the compiler may fail to resolve with generic has_from_json (issue #4996)
template<typename BasicJsonType>
struct has_from_json<BasicJsonType, std_fs::path, void> : std::true_type {};
@@ -636,7 +588,7 @@ struct from_json_fn
/// namespace to hold default `from_json` function
/// to see why this is required:
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces,misc-anonymous-namespace-in-header)
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
{
#endif
JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
@@ -178,7 +178,7 @@ struct external_constructor<value_t::array>
template < typename BasicJsonType, typename CompatibleArrayType,
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
&& !is_compatible_range_view<CompatibleArrayType>::value
#endif
, int > = 0 >
@@ -222,9 +222,7 @@ struct external_constructor<value_t::array>
j.assert_invariant();
}
// std::ranges does not work properly on MinGW due to incomplete C++20 support
// see https://github.com/nlohmann/json/issues/4916
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
template<typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
@@ -379,7 +377,7 @@ template < typename BasicJsonType, typename CompatibleArrayType,
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
!is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value&&
!is_basic_json<CompatibleArrayType>::value
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
&& !is_compatible_range_view<CompatibleArrayType>::value
#endif
,
@@ -389,7 +387,7 @@ inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
external_constructor<value_t::array>::construct(j, arr);
}
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
template < typename BasicJsonType, typename T,
enable_if_t < is_compatible_range_view<std::remove_cvref_t<T>>::value
&& !is_compatible_string_type<BasicJsonType, std::remove_cvref_t<T>>::value
@@ -546,7 +544,7 @@ struct to_json_fn
/// namespace to hold default `to_json` function
/// to see why this is required:
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces,misc-anonymous-namespace-in-header)
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
{
#endif
JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
+21
View File
@@ -286,6 +286,27 @@ class other_error : public exception
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
};
/*!
@brief helper function to call JSON_THROW from a template
@note JSON_THROW is a macro that, depending on the JSON_THROW_USER /
JSON_TRY_USER / JSON_NOEXCEPTION configuration, may expand to code
that does not reference its argument (e.g. `std::abort()`), which
would trigger a compilation error if the argument's type depends on
a template parameter that is otherwise unused. Wrapping the call in
a templated function avoids this and gives the compiler a single
place to see the (possibly unused) parameter.
*/
template<typename ExceptionType>
void templated_json_throw(ExceptionType exception)
{
JSON_THROW(exception);
// JSON_THROW may expand to code that discards its argument (e.g. when
// exceptions are disabled) - the cast below avoids an unused-parameter
// warning with -Werror in that case
(void)exception;
}
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
@@ -407,7 +407,7 @@ class binary_reader
@brief Parses a C-style string from the BSON input.
@param[in,out] result A reference to the string variable where the read
string is to be stored.
@return `true` if the \\x00-byte indicating the end of the string was
@return `true` if the \x00-byte indicating the end of the string was
encountered before the EOF; false` indicates an unexpected EOF.
*/
bool get_bson_cstr(string_t& result)
@@ -437,7 +437,7 @@ class binary_reader
@brief read a C-style string from contiguous input in one step
@param[in,out] result the string to append to
@return whether the string was read; if the input has no \\x00-byte, nothing
@return whether the string was read; if the input has no \x00-byte, nothing
is read, and @ref get_bson_cstr reports the end of the input
*/
bool get_bson_cstr_bulk(string_t& result, std::true_type /*bulk*/)
@@ -769,9 +769,6 @@ struct container_input_adapter_factory< ContainerType,
static adapter_type create(ContainerType&& container)
{
// container is forwarded twice on purpose: the resulting begin/end
// iterator types must match adapter_type, computed the same way
// NOLINTNEXTLINE(bugprone-use-after-move)
return input_adapter(begin(std::forward<ContainerType>(container)), end(std::forward<ContainerType>(container)));
}
};
+2 -2
View File
@@ -440,7 +440,7 @@ class json_sax_dom_parser
}
default: // LCOV_EXCL_LINE
// Handle all possible types discretely, default handler should never be reached.
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE
}
}
}
@@ -903,7 +903,7 @@ class json_sax_dom_callback_parser
}
default: // LCOV_EXCL_LINE
// Handle all possible types discretely, default handler should never be reached.
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE
}
}
}
+2 -2
View File
@@ -220,9 +220,9 @@ class lexer : public lexer_base<BasicJsonType>
/////////////////////
/*!
@brief get codepoint from 4 hex characters following `\\u`
@brief get codepoint from 4 hex characters following `\u`
For input "\\u c1 c2 c3 c4" the codepoint is:
For input "\u c1 c2 c3 c4" the codepoint is:
(c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
= (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
@@ -35,7 +35,7 @@ This class implements a both iterators (iterator and const_iterator) for the
been set (e.g., by a constructor or a copy assignment). If the iterator is
default-constructed, it is *uninitialized* and most methods are undefined.
**The library uses assertions to detect calls on uninitialized iterators.**
This class satisfies the following concept requirements (REQ-JSON-01):
@requirement REQ-JSON-01 The class satisfies the following concept requirements:
-
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
The iterator that can be moved can be moved in both directions (i.e.
@@ -60,9 +60,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
"iter_impl only accepts (const) basic_json");
// superficial check for the LegacyBidirectionalIterator named requirement
static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
&& std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
// note: only array_t::iterator is checked here; object_t::iterator may be
// a forward-only iterator as long as reverse iteration and operator--
// are never used on it
static_assert(std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
"basic_json iterator assumes array type iterators satisfy the LegacyBidirectionalIterator named requirement.");
public:
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
@@ -213,11 +213,11 @@ namespace std
JSON_HEDLEY_PRAGMA(clang diagnostic ignored "-Wmismatched-tags")
#endif
template<typename IteratorType>
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification)
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
: public std::integral_constant<std::size_t, 2> {};
template<std::size_t N, typename IteratorType>
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification)
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)
{
public:
using type = decltype(
@@ -29,7 +29,7 @@ namespace detail
iterator (to create @ref reverse_iterator) and @ref const_iterator (to
create @ref const_reverse_iterator).
This class satisfies the following concept requirements (REQ-JSON-02):
@requirement REQ-JSON-02 The class satisfies the following concept requirements:
-
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
The iterator that can be moved can be moved in both directions (i.e.
+96 -123
View File
@@ -240,6 +240,72 @@ class json_pointer
}
private:
/*!
@brief result of @ref parse_array_index
@ref array_index maps each value to the corresponding parse_error/out_of_range
exception; @ref contains and @ref get_checked_or_null, which must not throw for
an out-of-range or unrepresentable index, switch on it directly instead.
*/
enum class array_index_status
{
ok, ///< @a s is a valid, representable array index
leading_zero, ///< @a s begins with '0' but has more than one character
not_a_number, ///< @a s does not begin with a digit
unresolved, ///< @a s could not be converted to an integer
exceeds_size_type ///< @a s converts to an integer that exceeds size_type
};
/*!
@param[in] s reference token to be converted into an array index
@param[out] idx the integer representation of @a s if @ref array_index_status::ok
is returned; left unchanged otherwise
@return whether @a s is a valid array index, and if not, why
@note this function never throws; @ref array_index and the callers that must not
throw (@ref contains, @ref get_checked_or_null) build on it instead of each
re-implementing the RFC 6901 digit rules and the @a size_type range check
*/
template<typename BasicJsonType>
static array_index_status parse_array_index(const string_t& s, typename BasicJsonType::size_type& idx) noexcept
{
using size_type = typename BasicJsonType::size_type;
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
{
return array_index_status::leading_zero;
}
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
{
return array_index_status::not_a_number;
}
const char* p = s.data();
char* p_end = nullptr; // NOLINT(misc-const-correctness)
errno = 0; // strtoull doesn't reset errno
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
if (p == p_end // invalid input or empty string
|| errno == ERANGE // out of range
|| JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
{
return array_index_status::unresolved;
}
// only triggered on special platforms (like 32bit), see also
// https://github.com/nlohmann/json/pull/2203
if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
{
return array_index_status::exceeds_size_type; // LCOV_EXCL_LINE
}
idx = static_cast<size_type>(res);
return array_index_status::ok;
}
/*!
@param[in] s reference token to be converted into an array index
@@ -253,39 +319,30 @@ class json_pointer
template<typename BasicJsonType>
static typename BasicJsonType::size_type array_index(const string_t& s)
{
using size_type = typename BasicJsonType::size_type;
typename BasicJsonType::size_type idx{};
const auto status = parse_array_index<BasicJsonType>(s, idx);
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
if (JSON_HEDLEY_UNLIKELY(status == array_index_status::leading_zero))
{
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
}
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
if (JSON_HEDLEY_UNLIKELY(status == array_index_status::not_a_number))
{
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
}
const char* p = s.data();
char* p_end = nullptr; // NOLINT(misc-const-correctness)
errno = 0; // strtoull doesn't reset errno
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
if (p == p_end // invalid input or empty string
|| errno == ERANGE // out of range
|| JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
if (JSON_HEDLEY_UNLIKELY(status == array_index_status::unresolved))
{
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
}
// the index does not fit into size_type; on 64-bit platforms this is
// only SIZE_MAX itself (see #2203 and #5395)
if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
if (JSON_HEDLEY_UNLIKELY(status == array_index_status::exceeds_size_type))
{
JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));
JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE
}
return static_cast<size_type>(res);
return idx;
}
JSON_PRIVATE_UNLESS_TESTED:
@@ -316,7 +373,7 @@ class json_pointer
/*!
@brief create and return a reference to the pointed to value
Complexity: Linear in the number of reference tokens.
@complexity Linear in the number of reference tokens.
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if array index is not a number
@@ -403,7 +460,7 @@ class json_pointer
@return reference to the JSON value pointed to by the JSON pointer
Complexity: Linear in the length of the JSON pointer.
@complexity Linear in the length of the JSON pointer.
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@@ -584,63 +641,6 @@ class json_pointer
return *ptr;
}
/*!
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved
*/
template<typename BasicJsonType>
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
{
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
// note: at performs range check
ptr = &ptr->at(reference_token);
break;
}
case detail::value_t::array:
{
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, detail::concat(
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
") is out of range"), ptr));
}
const auto idx = array_index<BasicJsonType>(reference_token);
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
{
JSON_THROW(detail::out_of_range::create(401, detail::concat(
"array index ", std::to_string(idx), " is out of range"), ptr));
}
ptr = &ptr->operator[](idx);
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
}
}
return *ptr;
}
/*!
@brief return a pointer to the pointed to value, or `nullptr` if the
pointer cannot be resolved because a key is missing, an array
@@ -679,18 +679,23 @@ class json_pointer
return nullptr;
}
// may throw parse_error.106/109 for a malformed index; an
// a malformed index still throws parse_error.106/109; an
// index that is syntactically valid but cannot be
// represented (out_of_range.404/410) is treated like an
// out-of-range index below
typename BasicJsonType::size_type idx{};
JSON_TRY
switch (parse_array_index<BasicJsonType>(reference_token, idx))
{
idx = array_index<BasicJsonType>(reference_token);
}
JSON_INTERNAL_CATCH (detail::out_of_range&)
{
return nullptr;
case array_index_status::leading_zero:
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
case array_index_status::not_a_number:
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr));
case array_index_status::unresolved:
case array_index_status::exceeds_size_type:
return nullptr;
case array_index_status::ok:
default:
break;
}
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
@@ -718,8 +723,8 @@ class json_pointer
}
/*!
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@note unlike array_index(), this never throws: a malformed or unrepresentable
array index reference token is treated like a missing key (see #5395)
*/
template<typename BasicJsonType>
bool contains(const BasicJsonType* ptr) const
@@ -747,49 +752,17 @@ class json_pointer
// "-" always fails the range check
return false;
}
if (JSON_HEDLEY_UNLIKELY(reference_token.empty()))
{
// an empty reference token is not an array index; array_index()
// would throw out_of_range.404 -- contains() must not throw (see #5395)
return false;
}
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !('0' <= reference_token[0] && reference_token[0] <= '9')))
{
// invalid char
return false;
}
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
{
if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
{
// the first char should be between '1' and '9'
return false;
}
for (std::size_t i = 1; i < reference_token.size(); i++)
{
if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
{
// other char should be between '0' and '9'
return false;
}
}
}
// 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.data(), &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)
// any parse failure (malformed index, or one that is syntactically
// valid but not representable as size_type) means the reference
// token cannot denote an existing array element -- contains() must
// not throw (see #5395), so it is treated as "not found"
typename BasicJsonType::size_type idx{};
if (JSON_HEDLEY_UNLIKELY(parse_array_index<BasicJsonType>(reference_token, idx) != array_index_status::ok))
{
// the array index cannot be represented as size_type
return false;
}
const auto idx = array_index<BasicJsonType>(reference_token);
if (idx >= ptr->size())
{
// index out of range
+29 -48
View File
@@ -9,7 +9,6 @@
#pragma once
#include <utility> // declval, pair
#include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/thirdparty/hedley/hedley.hpp>
// This file contains all internal macro definitions (except those affecting ABI)
@@ -140,10 +139,12 @@
// libstdc++ < 11 has incomplete C++20 ranges (issue #4440)
#elif defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 11
#define JSON_HAS_RANGES 0
// libc++ < 16 has incomplete C++20 ranges (issue #4440)
// clang < 16 with libstdc++ does not implement the ranges customization
// points libstdc++ declares, so its C++20 ranges support is incomplete (issue #5161)
#elif defined(__clang__) && !defined(__apple_build_version__) \
&& __clang_major__ < 16 && defined(__GLIBCXX__)
#define JSON_HAS_RANGES 0
// libc++ < 16 has incomplete C++20 ranges (issue #4440)
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
#define JSON_HAS_RANGES 0
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
@@ -158,6 +159,18 @@
#endif
#endif
// std::ranges view conversion (to_json/is_compatible_array_type_impl) additionally
// needs to be disabled on MinGW, whose std::ranges support is incomplete
// (issue #4916); this macro combines both conditions so the check and its
// reason are not duplicated at every use site.
#ifndef JSON_HAS_RANGE_VIEW_CONVERSION
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#define JSON_HAS_RANGE_VIEW_CONVERSION 1
#else
#define JSON_HAS_RANGE_VIEW_CONVERSION 0
#endif
#endif
#ifndef JSON_HAS_STD_FORMAT
#if defined(JSON_HAS_CPP_20) && defined(__cpp_lib_format)
#define JSON_HAS_STD_FORMAT 1
@@ -195,6 +208,13 @@
#define JSON_NO_THREAD_LOCAL 1
#endif
// disable documentation warnings on clang
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
#endif
// allow disabling exceptions
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
#define JSON_THROW(exception) throw exception
@@ -253,7 +273,7 @@
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
@@ -267,7 +287,7 @@
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
@@ -279,26 +299,11 @@
/*!
@brief function to wrap JSON_THROW_MACRO - there can be compilation errors about
there being no arguments to JSON_THROW that depend on template arguments
if this is not used to call JSON_THROW
*/
template<typename ExceptionType>
void templated_json_throw(ExceptionType exception)
{
JSON_THROW(exception);
/* JSON_THROW(exception) discards exception and aborts - void cast needed to supress
compilation error if compiled with -Werror and Wunused-parameter */
(void)exception;
}
/*!
@brief macro to briefly define a mapping between an enum and JSON with exception
on invalid input
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
@since version 3.12.0
@since version 3.13.0
*/
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
template<typename BasicJsonType> \
@@ -306,7 +311,7 @@ void templated_json_throw(ExceptionType exception)
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
@@ -314,14 +319,14 @@ void templated_json_throw(ExceptionType exception)
return ej_pair.first == e; \
}); \
if (it != std::end(m)) j = it->second; \
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \
} \
template<typename BasicJsonType> \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
{ \
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
@@ -329,7 +334,7 @@ void templated_json_throw(ExceptionType exception)
return ej_pair.second == j; \
}); \
if (it != std::end(m)) e = it->first; \
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
}
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
@@ -869,30 +874,6 @@ void templated_json_throw(ExceptionType exception)
\
template<typename... T> \
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
} \
\
namespace detail2 { \
struct std_name##_tag \
{ \
}; \
\
template<typename... T> \
std_name##_tag std_name(T&&...); \
\
template<typename... T> \
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
\
template<typename... T> \
struct would_call_std_##std_name \
{ \
static constexpr auto const value = ::nlohmann::detail:: \
is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
}; \
} /* namespace detail2 */ \
\
template<typename... T> \
struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
{ \
}
#ifndef JSON_USE_IMPLICIT_CONVERSIONS
@@ -8,6 +8,11 @@
#pragma once
// restore clang diagnostic settings
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
// clean up
#undef JSON_ASSERT
#undef JSON_INTERNAL_CATCH
@@ -34,6 +39,7 @@
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#undef JSON_HAS_THREE_WAY_COMPARISON
#undef JSON_HAS_RANGES
#undef JSON_HAS_RANGE_VIEW_CONVERSION
#undef JSON_HAS_STD_FORMAT
#undef JSON_HAS_STATIC_RTTI
#undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
@@ -12,6 +12,6 @@
NLOHMANN_JSON_NAMESPACE_BEGIN
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin)
NLOHMANN_JSON_NAMESPACE_END
@@ -12,6 +12,6 @@
NLOHMANN_JSON_NAMESPACE_BEGIN
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end)
NLOHMANN_JSON_NAMESPACE_END
@@ -62,9 +62,5 @@ using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template<class Expected, template<class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
template<class To, template<class...> class Op, class... Args>
using is_detected_convertible =
std::is_convertible<detected_t<Op, Args...>, To>;
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
+1 -34
View File
@@ -8,7 +8,7 @@
#pragma once
#include <cstdint> // size_t
#include <cstddef> // size_t
#include <utility> // declval
#include <string> // string
@@ -70,37 +70,6 @@ using parse_error_function_t = decltype(std::declval<T&>().parse_error(
std::declval<std::size_t>(), std::declval<const std::string&>(),
std::declval<const Exception&>()));
template<typename SAX, typename BasicJsonType>
struct is_sax
{
private:
static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>");
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
using exception_t = typename BasicJsonType::exception;
public:
static constexpr bool value =
is_detected_exact<bool, null_function_t, SAX>::value &&
is_detected_exact<bool, boolean_function_t, SAX>::value &&
is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
is_detected_exact<bool, start_object_function_t, SAX>::value &&
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
is_detected_exact<bool, end_object_function_t, SAX>::value &&
is_detected_exact<bool, start_array_function_t, SAX>::value &&
is_detected_exact<bool, end_array_function_t, SAX>::value &&
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
};
template<typename SAX, typename BasicJsonType>
struct is_sax_static_asserts
{
@@ -120,8 +89,6 @@ struct is_sax_static_asserts
"Missing/invalid function: bool null()");
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)");
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)");
static_assert(
is_detected_exact<bool, number_integer_function_t, SAX,
number_integer_t>::value,
-54
View File
@@ -1,54 +0,0 @@
#pragma once
#include <nlohmann/detail/macro_scope.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
#ifdef JSON_HAS_CPP_17
template<bool... Booleans>
struct cxpr_or_impl : std::integral_constant < bool, (Booleans || ...) > {};
template<bool... Booleans>
struct cxpr_and_impl : std::integral_constant < bool, (Booleans &&...) > {};
#else
template<bool... Booleans>
struct cxpr_or_impl : std::false_type {};
template<bool... Booleans>
struct cxpr_or_impl<true, Booleans...> : std::true_type {};
template<bool... Booleans>
struct cxpr_or_impl<false, Booleans...> : cxpr_or_impl<Booleans...> {};
template<bool... Booleans>
struct cxpr_and_impl : std::true_type {};
template<bool... Booleans>
struct cxpr_and_impl<true, Booleans...> : cxpr_and_impl<Booleans...> {};
template<bool... Booleans>
struct cxpr_and_impl<false, Booleans...> : std::false_type {};
#endif
template<class Boolean>
struct cxpr_not : std::integral_constant < bool, !Boolean::value > {};
template<class... Booleans>
struct cxpr_or : cxpr_or_impl<Booleans::value...> {};
template<bool... Booleans>
struct cxpr_or_c : cxpr_or_impl<Booleans...> {};
template<class... Booleans>
struct cxpr_and : cxpr_and_impl<Booleans::value...> {};
template<bool... Booleans>
struct cxpr_and_c : cxpr_and_impl<Booleans...> {};
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
+12 -23
View File
@@ -283,6 +283,13 @@ template<class B, class... Bn>
struct conjunction<B, Bn...>
: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
// https://en.cppreference.com/w/cpp/types/disjunction
template<class...> struct disjunction : std::false_type { };
template<class B> struct disjunction<B> : B { };
template<class B, class... Bn>
struct disjunction<B, Bn...>
: std::conditional<static_cast<bool>(B::value), B, disjunction<Bn...>>::type {};
// https://en.cppreference.com/w/cpp/types/negation
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
@@ -477,9 +484,7 @@ template<typename T> struct is_range_view_optional_type<std::optional<T>> : std:
template<typename T> struct is_range_view_optional_type : std::false_type {};
#endif
// std::ranges does not work properly on MinGW due to incomplete C++20 support
// see https://github.com/nlohmann/json/issues/4916
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
// SafeToCheck guards against types that trigger circular constraints when
// std::ranges::view<T> is evaluated on GCC 12 / libstdc++ 12:
@@ -518,7 +523,7 @@ struct is_compatible_array_type_impl <
// filter_view) can match BOTH this iterator-based specialization AND the view-based one
// below, causing ambiguity. Exclude views here so the two specializations are mutually
// exclusive: this one handles plain iterable containers, the other handles views.
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
&& !is_compatible_range_view<CompatibleArrayType>::value
#endif
>>
@@ -528,7 +533,7 @@ struct is_compatible_array_type_impl <
range_value_t<CompatibleArrayType>>::value;
};
#if JSON_HAS_RANGES && !defined(__MINGW32__)
#if JSON_HAS_RANGE_VIEW_CONVERSION
template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType,
@@ -604,7 +609,6 @@ struct is_compatible_integer_type_impl <
std::is_integral<CompatibleNumberIntegerType>::value&&
!std::is_same<bool, CompatibleNumberIntegerType>::value >>
{
// is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>;
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
@@ -798,20 +802,7 @@ struct has_capacity : std::integral_constant<bool, is_detected<detect_capacity,
// a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector)
template <typename T>
struct is_ordered_map
{
using one = char;
struct two
{
char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
};
template <typename C> static one test( decltype(&C::capacity) ) ;
template <typename C> static two test(...);
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg,cppcoreguidelines-use-enum-class)
};
struct is_ordered_map : has_capacity<T> {};
// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
@@ -835,10 +826,8 @@ using all_signed = conjunction<std::is_signed<Types>...>;
template<typename... Types>
using all_unsigned = conjunction<std::is_unsigned<Types>...>;
// there's a disjunction trait in another PR; replace when merged
template<typename... Types>
using same_sign = std::integral_constant < bool,
all_signed<Types...>::value || all_unsigned<Types...>::value >;
using same_sign = disjunction<all_signed<Types...>, all_unsigned<Types...>>;
template<typename OfType, typename T>
using never_out_of_range = std::integral_constant < bool,
@@ -13,7 +13,6 @@
#include <iterator> // back_inserter
#include <memory> // shared_ptr, make_shared
#include <string> // basic_string
#include <type_traits> // conditional, integral_constant, is_same
#include <utility> // move
#include <vector> // vector
@@ -118,14 +117,12 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
: stream(s)
{}
// NOLINTNEXTLINE(portability-template-virtual-member-function)
void write_character(CharType c) override
{
stream.put(c);
}
JSON_HEDLEY_NON_NULL(2)
// NOLINTNEXTLINE(portability-template-virtual-member-function)
void write_characters(const CharType* s, std::size_t length) override
{
stream.write(s, static_cast<std::streamsize>(length));
@@ -193,82 +190,7 @@ class output_adapter_sink
output_adapter_t<CharType> oa;
};
/// @brief whether std::basic_string<CharType> has a non-deprecated std::char_traits
/// specialization, and is therefore usable as output_adapter's default StringType
///
/// std::char_traits is only guaranteed (and, on some standard libraries, only
/// implemented without a deprecation warning) for the character types listed
/// below; std::char_traits<T> for any other T (e.g. std::uint8_t, as used by the
/// binary writers) is a non-standard extension some standard libraries deprecate.
/// See https://github.com/nlohmann/json/issues/5725 item 2.
template<typename CharType>
struct is_output_adapter_string_char_type : std::integral_constant < bool,
std::is_same<CharType, char>::value ||
std::is_same<CharType, wchar_t>::value ||
std::is_same<CharType, char16_t>::value ||
std::is_same<CharType, char32_t>::value
#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L)
|| std::is_same<CharType, char8_t>::value
#endif
> {};
/// @brief placeholder type for output_adapter's StringType and (with JSON_NO_IO
/// undefined) its std::basic_ostream constructor parameter, for CharType
/// with no non-deprecated std::char_traits specialization
///
/// Never actually used: the StringType- and std::basic_ostream-based
/// output_adapter constructors are neither documented nor tested for such
/// CharType (only the std::vector-based constructor is used for them, by the
/// binary writers). Naming std::basic_string<CharType> or
/// std::basic_ostream<CharType> anywhere such a constructor would otherwise be
/// declared - even as an unused default template argument or an unused,
/// never-called overload - instantiates std::char_traits<CharType> merely to
/// name the type, which is exactly what triggers the deprecation warning this
/// placeholder avoids.
template<typename CharType>
struct output_adapter_no_string_type {};
// Select output_adapter's default StringType (and, below, its ostream
// constructor's parameter type) via partial specialization, not
// std::conditional: std::conditional<B, T, F> requires both T and F to be named
// as template arguments up front, which would still instantiate (and thus name)
// std::basic_string<CharType> / std::basic_ostream<CharType> for every CharType,
// defeating the point. A bool non-type parameter with two specializations only
// ever names the type that is actually selected.
template<typename CharType, bool = is_output_adapter_string_char_type<CharType>::value>
struct output_adapter_default_string_type
{
using type = output_adapter_no_string_type<CharType>;
};
template<typename CharType>
struct output_adapter_default_string_type<CharType, true>
{
using type = std::basic_string<CharType>;
};
#ifndef JSON_NO_IO
/// distinct from output_adapter_no_string_type, so the placeholder overloads of
/// output_adapter's constructor (used when CharType is not a character type)
/// stay distinct overloads instead of colliding into a single redeclaration
template<typename CharType>
struct output_adapter_no_ostream_type {};
template<typename CharType, bool = is_output_adapter_string_char_type<CharType>::value>
struct output_adapter_ostream_type
{
using type = output_adapter_no_ostream_type<CharType>;
};
template<typename CharType>
struct output_adapter_ostream_type<CharType, true>
{
using type = std::basic_ostream<CharType>;
};
#endif // JSON_NO_IO
template < typename CharType, typename StringType =
typename output_adapter_default_string_type<CharType>::type >
template<typename CharType, typename StringType = std::basic_string<CharType>>
class output_adapter
{
public:
@@ -277,7 +199,7 @@ class output_adapter
: oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}
#ifndef JSON_NO_IO
output_adapter(typename output_adapter_ostream_type<CharType>::type& s)
output_adapter(std::basic_ostream<CharType>& s)
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
#endif // JSON_NO_IO
@@ -67,7 +67,7 @@ class serializer
@param[in] ichar indentation character to use
@param[in] pretty_print_ whether the output shall be pretty-printed
@param[in] ensure_ascii_ If @a ensure_ascii_ is true, all non-ASCII
characters in the output are escaped with `\\uXXXX` sequences, and the
characters in the output are escaped with `\uXXXX` sequences, and the
result consists of ASCII characters only.
@param[in] indent_step_ the indent level
@param[in] error_handler_ how to react on decoding errors
@@ -772,7 +772,7 @@ class serializer
@param[in] s the string to escape
Complexity: Linear in the length of string @a s.
@complexity Linear in the length of string @a s.
*/
void dump_escaped(const string_t& s)
{
@@ -1290,7 +1290,7 @@ class serializer
}
/*!
* @brief write a lowercase "\\uXXXX" escape sequence into @a string_buffer
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
*
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
@@ -1650,7 +1650,7 @@ class serializer
/// whether to pretty-print the output
const bool pretty_print;
/// whether to escape non-ASCII characters with \\uXXXX sequences
/// whether to escape non-ASCII characters with \uXXXX sequences
const bool ensure_ascii;
/// the indent level
+2 -1
View File
@@ -62,7 +62,8 @@ inline StringType escape(const StringType& s)
/*!
* @brief string unescaping as described in RFC 6901 (Sect. 4)
* @param[in,out] s string to unescape in place
* @param[in] s string to unescape
* @return unescaped string
*
* Note the order of escaping "~1" to "/" and "~0" to "~" is important.
*
+35 -36
View File
@@ -18,6 +18,16 @@
#ifndef INCLUDE_NLOHMANN_JSON_HPP_
#define INCLUDE_NLOHMANN_JSON_HPP_
// Workaround for GCC template redefinition errors in C++ modules
// When nlohmann/json.hpp is included in a C++20 module preamble after
// other module imports, GCC may report spurious redefinition errors for
// STL templates. These pragmas suppress those false positives.
// See: https://github.com/nlohmann/json/issues/5103
#if defined(__GNUC__) && !defined(__clang__) && __cplusplus >= 202002L
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
#include <algorithm> // all_of, find, for_each, none_of
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <functional> // hash, less
@@ -2340,12 +2350,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@throw what @ref json_serializer<ValueType> `from_json()` method throws
The example below shows several conversions from JSON values
@liveexample{The example below shows several conversions from JSON values
to other types. There a few things to note: (1) Floating-point numbers can
be converted to integers, (2) A JSON array can be converted to a standard
`std::vector<short>`, (3) A JSON object can be converted to C++
associative containers such as `std::unordered_map<std::string,
json>`.
be converted to integers\, (2) A JSON array can be converted to a standard
`std::vector<short>`\, (3) A JSON object can be converted to C++
associative containers such as `std::unordered_map<std::string\,
json>`.,get__ValueType_const}
@since version 2.1.0
*/
@@ -2412,7 +2422,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@return a copy of *this, converted into @a BasicJsonType
Complexity: Depending on the implementation of the called `from_json()`
@complexity Depending on the implementation of the called `from_json()`
method.
@since version 3.2.0
@@ -2436,7 +2446,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@return a copy of *this
Complexity: Constant.
@complexity Constant.
@since version 2.1.0
*/
@@ -2482,7 +2492,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@tparam ValueTypeCV the provided value type
@tparam ValueType the returned value type
@return copy of the JSON value, converted to @a ValueType if necessary
@return copy of the JSON value, converted to @tparam ValueType if necessary
@throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
@@ -2520,12 +2530,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@return pointer to the internally stored JSON value if the requested
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
Complexity: Constant.
@complexity Constant.
The example below shows how pointers to internal values of a
@liveexample{The example below shows how pointers to internal values of a
JSON value can be requested. Note that no type conversions are made and a
`nullptr` is returned if the value and the requested pointer type does not
match.
match.,get__PointerType}
@sa see @ref get_ptr() for explicit pointer-member access
@@ -2619,14 +2629,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
to the JSON value type (e.g., the JSON value is of type boolean, but a
string is requested); see example below
Complexity: Linear in the size of the JSON value.
@complexity Linear in the size of the JSON value.
The example below shows several conversions from JSON values
@liveexample{The example below shows several conversions from JSON values
to other types. There a few things to note: (1) Floating-point numbers can
be converted to integers, (2) A JSON array can be converted to a standard
`std::vector<short>`, (3) A JSON object can be converted to C++
associative containers such as `std::unordered_map<std::string,
json>`.
be converted to integers\, (2) A JSON array can be converted to a standard
`std::vector<short>`\, (3) A JSON object can be converted to C++
associative containers such as `std::unordered_map<std::string\,
json>`.,operator__ValueType}
@since version 1.0.0
*/
@@ -5049,19 +5059,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @deprecated This function is deprecated since 3.8.0 and will be removed in
/// version 4.0.0 of the library. Please use
/// sax_parse(ptr, ptr + len) instead.
//
// Clang reports "declaration is marked with '@deprecated' command but does
// not have a deprecation attribute" for this overload even though
// JSON_HEDLEY_DEPRECATED_FOR below does expand to __attribute__((deprecated));
// isolated reproductions of this exact declaration shape (doc comment,
// template<>, two stacked __attribute__ lines, an overload set of the same
// name) do not reproduce it, so this looks like a Clang comment/declaration
// association quirk specific to this overload within basic_json, not a
// genuine documentation bug. See #5725 item 2.
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation-deprecated-sync"
#endif
template <typename SAX>
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
JSON_HEDLEY_NON_NULL(2)
@@ -5078,9 +5075,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#ifndef JSON_NO_IO
/// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
@@ -6501,7 +6495,7 @@ namespace std // NOLINT(cert-dcl58-cpp)
/// @brief hash value for JSON objects
/// @sa https://json.nlohmann.me/api/basic_json/std_hash/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification)
struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
{
std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
{
@@ -6534,7 +6528,7 @@ struct less< ::nlohmann::detail::value_t> // do not remove the space after '<',
/// @brief exchanges the values of two JSON objects
/// @sa https://json.nlohmann.me/api/basic_json/std_swap/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp,bugprone-std-namespace-modification)
inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)
is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
{
@@ -6548,7 +6542,7 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
/// @brief std::formatter specialization for JSON values
/// @sa https://json.nlohmann.me/api/basic_json/std_formatter/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-cpp,bugprone-std-namespace-modification)
struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-cpp)
{
// -1 means compact output (dump()); any value >= 0 means pretty-printed
// output with that many spaces (or indent_char) per level (dump(indent, indent_char)).
@@ -6625,6 +6619,11 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
#include <nlohmann/detail/macro_unscope.hpp>
// End of GCC diagnostic pragmas for C++ modules support
#if defined(__GNUC__) && !defined(__clang__) && __cplusplus >= 202002L
#pragma GCC diagnostic pop
#endif
// The user-defined string literals are in a separate header, because their
// bodies instantiate the parser in every translation unit that includes them.
// Define JSON_NO_AUTOMATIC_UDLS to include <nlohmann/json_literals.hpp> only
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -90,11 +90,11 @@ target_compile_options(test_main PUBLIC
# https://github.com/nlohmann/json/pull/3229
$<$<CXX_COMPILER_ID:Intel>:-diag-disable=2196>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal>
$<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
$<$<CXX_COMPILER_ID:Intel>:-diag-disable=1786>)
target_include_directories(test_main SYSTEM PUBLIC
thirdparty/doctest)
target_include_directories(test_main PUBLIC
thirdparty/doctest
thirdparty/fifo_map
${PROJECT_BINARY_DIR}/include)
target_link_libraries(test_main PUBLIC ${NLOHMANN_JSON_TARGET_NAME})
+1
View File
@@ -12,6 +12,7 @@ target_compile_options(abi_compat_common INTERFACE
# https://github.com/nlohmann/json/pull/3229
$<$<CXX_COMPILER_ID:Intel>:-diag-disable=2196>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal>
$<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
$<$<CXX_COMPILER_ID:Intel>:-diag-disable=1786>)
target_include_directories(abi_compat_common SYSTEM INTERFACE
+1 -1
View File
@@ -28,7 +28,7 @@ std::string namespace_name(std::string ns, T* /*unused*/ = nullptr) // NOLINT(pe
std::smatch m;
// extract the true namespace name from the function signature
CAPTURE(ns)
CAPTURE(ns);
CHECK(std::regex_search(ns, m, std::regex("nlohmann(::[a-zA-Z0-9_]+)*::basic_json")));
return m.str();
+4 -4
View File
@@ -59,10 +59,10 @@ TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test)
INFO("type := ", type_str);
CAPTURE(val_min)
CAPTURE(min_in_range)
CAPTURE(val_max)
CAPTURE(max_in_range)
CAPTURE(val_min);
CAPTURE(min_in_range);
CAPTURE(val_max);
CAPTURE(max_in_range);
if (min_in_range)
{
+3 -3
View File
@@ -239,7 +239,7 @@ TEST_CASE("controlled bad_alloc")
// iterative path instead, part-way through its worklist.
const auto check_deep_copy = [](bool objects)
{
CAPTURE(objects)
CAPTURE(objects);
next_construct_fails = false;
@@ -315,7 +315,7 @@ struct nth_alloc_fails_allocator : std::allocator<T>
template<class BasicJsonType>
void check_deep_copy_survives_failing_allocation(bool nest_objects)
{
CAPTURE(nest_objects)
CAPTURE(nest_objects);
fail_at_alloc_call = -1;
@@ -352,7 +352,7 @@ void check_deep_copy_survives_failing_allocation(bool nest_objects)
// must come out exactly as it went in
for (std::size_t n = 0; n < total_allocations; ++n)
{
CAPTURE(n)
CAPTURE(n);
alloc_call_count = 0;
fail_at_alloc_call = static_cast<long>(n);
+1 -1
View File
@@ -18,7 +18,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wstrict-overflow")
static int assert_counter;
/// set failure variable to true instead of calling assert(x)
#define JSON_ASSERT(x) do { if (!(x)) { ++assert_counter; } } while (false)
#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; }
#include <nlohmann/json.hpp>
using nlohmann::json;
+7 -7
View File
@@ -89,7 +89,7 @@ TEST_CASE("binary writer output sinks")
// the first iteration
for (const auto& j : test_values())
{
CAPTURE(j.dump(-1, ' ', false, json::error_handler_t::replace))
CAPTURE(j.dump(-1, ' ', false, json::error_handler_t::replace));
std::vector<std::uint8_t> cbor;
json::to_cbor(j, cbor);
@@ -120,8 +120,8 @@ TEST_CASE("binary writer output sinks")
{
continue; // not a supported combination
}
CAPTURE(use_size)
CAPTURE(use_type)
CAPTURE(use_size);
CAPTURE(use_type);
std::vector<std::uint8_t> ubjson;
json::to_ubjson(j, ubjson, use_size, use_type);
CHECK(json::to_ubjson(j, use_size, use_type) == ubjson);
@@ -141,7 +141,7 @@ TEST_CASE("binary writer output sinks")
for (const auto& j : bson_values())
{
CAPTURE(j.dump())
CAPTURE(j.dump());
std::vector<std::uint8_t> bson;
json::to_bson(j, bson);
CHECK(json::to_bson(j) == bson);
@@ -152,7 +152,7 @@ TEST_CASE("binary writer output sinks")
{
for (const auto& j : test_values())
{
CAPTURE(j.dump(-1, ' ', false, json::error_handler_t::replace))
CAPTURE(j.dump(-1, ' ', false, json::error_handler_t::replace));
const std::vector<std::uint8_t> expected = json::to_cbor(j);
std::vector<char> as_char;
@@ -177,7 +177,7 @@ TEST_CASE("binary_reserve_hint never over-reserves")
{
for (const auto& j : test_values())
{
CAPTURE(j.dump(-1, ' ', false, json::error_handler_t::replace))
CAPTURE(j.dump(-1, ' ', false, json::error_handler_t::replace));
const std::size_t hint = nlohmann::detail::binary_reserve_hint(j);
@@ -194,7 +194,7 @@ TEST_CASE("binary_reserve_hint never over-reserves")
for (const auto& j : bson_values())
{
CAPTURE(j.dump())
CAPTURE(j.dump());
CHECK(nlohmann::detail::binary_reserve_hint(j) <= json::to_bson(j).size());
}
+10 -10
View File
@@ -146,10 +146,10 @@ TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test)
INFO("type := ", type_str);
CAPTURE(val_min)
CAPTURE(min_in_range)
CAPTURE(val_max)
CAPTURE(max_in_range)
CAPTURE(val_min);
CAPTURE(min_in_range);
CAPTURE(val_max);
CAPTURE(max_in_range);
if (min_in_range)
{
@@ -2641,7 +2641,7 @@ TEST_CASE("BJData")
{"uint8", "int8", "uint16", "int16", "uint32", "int32", "uint64", "int64", "char"
})
{
CAPTURE(type)
CAPTURE(type);
const std::string text = std::string(R"({"_ArrayType_":")") + type +
R"(","_ArraySize_":[2,3],"_ArrayData_":[1,2,3,4,5,6]})";
const auto from_text = json::to_bjdata(json::parse(text));
@@ -2949,7 +2949,7 @@ TEST_CASE("BJData")
R"({"_ArrayType_":"int16","_ArraySize_":[0,2],"_ArrayData_":[]})"
})
{
CAPTURE(text)
CAPTURE(text);
const json j = json::parse(text);
for (const bool use_size :
{
@@ -2983,7 +2983,7 @@ TEST_CASE("BJData")
R"({"_ArrayType_":"int16","_ArraySize_":[],"_ArrayData_":null})"
})
{
CAPTURE(text)
CAPTURE(text);
const json j = json::parse(text);
const auto out = json::to_bjdata(j);
CHECK(out.at(0) == '{');
@@ -4317,7 +4317,7 @@ TEST_CASE("BJData and UBJSON can be written to a string")
for (const auto& j : values)
{
CAPTURE(j.dump())
CAPTURE(j.dump());
for (const bool use_size :
{
false, true
@@ -4332,8 +4332,8 @@ TEST_CASE("BJData and UBJSON can be written to a string")
{
continue;
}
CAPTURE(use_size)
CAPTURE(use_type)
CAPTURE(use_size);
CAPTURE(use_type);
const auto bjdata = json::to_bjdata(j, use_size, use_type);
std::string bjdata_string;
+2 -2
View File
@@ -1788,7 +1788,7 @@ TEST_CASE("BSON: deeply nested values")
json value = "leaf";
for (std::size_t depth = 0; depth <= 300; ++depth)
{
CAPTURE(depth)
CAPTURE(depth);
const json document = {{"value", value}, {"n", depth}};
CHECK(json::from_bson(json::to_bson(document)) == document);
@@ -1836,7 +1836,7 @@ value = depth % 2 == 0 ? json{{"a", std::move(value)}, {"b", {1, "x"}}} :
false, true
})
{
CAPTURE(objects)
CAPTURE(objects);
std::string text = "{\"a\":";
for (std::size_t i = 0; i < depth; ++i)
{
+30 -30
View File
@@ -17,7 +17,7 @@ TEST_CASE("capacity")
{
SECTION("boolean")
{
json j = true;
json j = true; // NOLINT(misc-const-correctness)
const json j_const = true;
SECTION("result of empty")
@@ -35,7 +35,7 @@ TEST_CASE("capacity")
SECTION("string")
{
json j = "hello world";
json j = "hello world"; // NOLINT(misc-const-correctness)
const json j_const = "hello world";
SECTION("result of empty")
@@ -55,7 +55,7 @@ TEST_CASE("capacity")
{
SECTION("empty array")
{
json j = json::array();
json j = json::array(); // NOLINT(misc-const-correctness)
const json j_const = json::array();
SECTION("result of empty")
@@ -73,7 +73,7 @@ TEST_CASE("capacity")
SECTION("filled array")
{
json j = {1, 2, 3};
json j = {1, 2, 3}; // NOLINT(misc-const-correctness)
const json j_const = {1, 2, 3};
SECTION("result of empty")
@@ -94,7 +94,7 @@ TEST_CASE("capacity")
{
SECTION("empty object")
{
json j = json::object();
json j = json::object(); // NOLINT(misc-const-correctness)
const json j_const = json::object();
SECTION("result of empty")
@@ -112,7 +112,7 @@ TEST_CASE("capacity")
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness)
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
SECTION("result of empty")
@@ -131,7 +131,7 @@ TEST_CASE("capacity")
SECTION("number (integer)")
{
json j = -23;
json j = -23; // NOLINT(misc-const-correctness)
const json j_const = -23;
SECTION("result of empty")
@@ -149,7 +149,7 @@ TEST_CASE("capacity")
SECTION("number (unsigned)")
{
json j = 23u;
json j = 23u; // NOLINT(misc-const-correctness)
const json j_const = 23u;
SECTION("result of empty")
@@ -167,7 +167,7 @@ TEST_CASE("capacity")
SECTION("number (float)")
{
json j = 23.42;
json j = 23.42; // NOLINT(misc-const-correctness)
const json j_const = 23.42;
SECTION("result of empty")
@@ -185,7 +185,7 @@ TEST_CASE("capacity")
SECTION("null")
{
json j = nullptr;
json j = nullptr; // NOLINT(misc-const-correctness)
const json j_const = nullptr;
SECTION("result of empty")
@@ -206,7 +206,7 @@ TEST_CASE("capacity")
{
SECTION("boolean")
{
json j = true;
json j = true; // NOLINT(misc-const-correctness)
const json j_const = true;
SECTION("result of size")
@@ -226,7 +226,7 @@ TEST_CASE("capacity")
SECTION("string")
{
json j = "hello world";
json j = "hello world"; // NOLINT(misc-const-correctness)
const json j_const = "hello world";
SECTION("result of size")
@@ -248,7 +248,7 @@ TEST_CASE("capacity")
{
SECTION("empty array")
{
json j = json::array();
json j = json::array(); // NOLINT(misc-const-correctness)
const json j_const = json::array();
SECTION("result of size")
@@ -268,7 +268,7 @@ TEST_CASE("capacity")
SECTION("filled array")
{
json j = {1, 2, 3};
json j = {1, 2, 3}; // NOLINT(misc-const-correctness)
const json j_const = {1, 2, 3};
SECTION("result of size")
@@ -291,7 +291,7 @@ TEST_CASE("capacity")
{
SECTION("empty object")
{
json j = json::object();
json j = json::object(); // NOLINT(misc-const-correctness)
const json j_const = json::object();
SECTION("result of size")
@@ -311,7 +311,7 @@ TEST_CASE("capacity")
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness)
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
SECTION("result of size")
@@ -332,7 +332,7 @@ TEST_CASE("capacity")
SECTION("number (integer)")
{
json j = -23;
json j = -23; // NOLINT(misc-const-correctness)
const json j_const = -23;
SECTION("result of size")
@@ -352,7 +352,7 @@ TEST_CASE("capacity")
SECTION("number (unsigned)")
{
json j = 23u;
json j = 23u; // NOLINT(misc-const-correctness)
const json j_const = 23u;
SECTION("result of size")
@@ -372,7 +372,7 @@ TEST_CASE("capacity")
SECTION("number (float)")
{
json j = 23.42;
json j = 23.42; // NOLINT(misc-const-correctness)
const json j_const = 23.42;
SECTION("result of size")
@@ -392,7 +392,7 @@ TEST_CASE("capacity")
SECTION("null")
{
json j = nullptr;
json j = nullptr; // NOLINT(misc-const-correctness)
const json j_const = nullptr;
SECTION("result of size")
@@ -415,7 +415,7 @@ TEST_CASE("capacity")
{
SECTION("boolean")
{
json j = true;
json j = true; // NOLINT(misc-const-correctness)
const json j_const = true;
SECTION("result of max_size")
@@ -427,7 +427,7 @@ TEST_CASE("capacity")
SECTION("string")
{
json j = "hello world";
json j = "hello world"; // NOLINT(misc-const-correctness)
const json j_const = "hello world";
SECTION("result of max_size")
@@ -441,7 +441,7 @@ TEST_CASE("capacity")
{
SECTION("empty array")
{
json j = json::array();
json j = json::array(); // NOLINT(misc-const-correctness)
const json j_const = json::array();
SECTION("result of max_size")
@@ -453,7 +453,7 @@ TEST_CASE("capacity")
SECTION("filled array")
{
json j = {1, 2, 3};
json j = {1, 2, 3}; // NOLINT(misc-const-correctness)
const json j_const = {1, 2, 3};
SECTION("result of max_size")
@@ -468,7 +468,7 @@ TEST_CASE("capacity")
{
SECTION("empty object")
{
json j = json::object();
json j = json::object(); // NOLINT(misc-const-correctness)
const json j_const = json::object();
SECTION("result of max_size")
@@ -480,7 +480,7 @@ TEST_CASE("capacity")
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness)
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
SECTION("result of max_size")
@@ -493,7 +493,7 @@ TEST_CASE("capacity")
SECTION("number (integer)")
{
json j = -23;
json j = -23; // NOLINT(misc-const-correctness)
const json j_const = -23;
SECTION("result of max_size")
@@ -505,7 +505,7 @@ TEST_CASE("capacity")
SECTION("number (unsigned)")
{
json j = 23u;
json j = 23u; // NOLINT(misc-const-correctness)
const json j_const = 23u;
SECTION("result of max_size")
@@ -517,7 +517,7 @@ TEST_CASE("capacity")
SECTION("number (float)")
{
json j = 23.42;
json j = 23.42; // NOLINT(misc-const-correctness)
const json j_const = 23.42;
SECTION("result of max_size")
@@ -529,7 +529,7 @@ TEST_CASE("capacity")
SECTION("null")
{
json j = nullptr;
json j = nullptr; // NOLINT(misc-const-correctness)
const json j_const = nullptr;
SECTION("result of max_size")
+2 -2
View File
@@ -2931,7 +2931,7 @@ TEST_CASE("Tagged values")
0xD5, 0xD6, 0xD7
})
{
CAPTURE(b)
CAPTURE(b);
// add tag to value
auto v_tagged = v;
@@ -3271,7 +3271,7 @@ TEST_CASE("CBOR large strings and binaries (chunked reader)")
std::size_t{4097}, std::size_t{8192}, std::size_t{100000}
})
{
CAPTURE(len)
CAPTURE(len);
// text string
const json j_string = std::string(len, 'x');
+12 -12
View File
@@ -272,7 +272,7 @@ TEST_CASE("lexer number fast path")
std::stringstream ss(doc);
const json b = json::parse(ss);
CAPTURE(n)
CAPTURE(n);
CHECK(a == b);
CHECK(a.dump() == b.dump());
CHECK(a[0].type() == b[0].type());
@@ -310,7 +310,7 @@ TEST_CASE("lexer number fast path")
for (const auto& n : numbers)
{
CAPTURE(n)
CAPTURE(n);
const std::string doc = "[" + n + "]";
const json a = json::parse(doc); // contiguous fast path
@@ -347,7 +347,7 @@ TEST_CASE("lexer number fast path")
{"-", "1.", "1e", "1e+", "1.2e", "01", "-01", "1..2", "1.2.3"
})
{
CAPTURE(bad)
CAPTURE(bad);
// the contiguous fast path must decline and let the byte path report
const std::string doc = std::string("[") + bad + "]";
CHECK_FALSE(json::accept(doc));
@@ -415,7 +415,7 @@ TEST_CASE("lexer number fast path")
// 7 + 49 + 343 + 2401 tokens
CHECK(tokens.size() == 2401);
CAPTURE(mismatches)
CAPTURE(mismatches);
CHECK(mismatches.empty());
}
@@ -459,7 +459,7 @@ TEST_CASE("lexer number fast path")
"[1 \n2]", "[\n1\n2]", "1\n2", "[01\r\n]", "[1e\n]", "[-\n]"
})
{
CAPTURE(bad)
CAPTURE(bad);
const std::string doc = bad;
const std::string contiguous_what = contiguous_error(doc);
@@ -576,7 +576,7 @@ TEST_CASE("lexer string fast path")
// 13 + 169 + 2197 tokens, each at two offsets
CHECK(tokens.size() == 2197);
CAPTURE(mismatches)
CAPTURE(mismatches);
CHECK(mismatches.empty());
}
@@ -604,7 +604,7 @@ TEST_CASE("lexer string fast path")
}
}
}
CAPTURE(mismatches)
CAPTURE(mismatches);
CHECK(mismatches.empty());
}
#endif
@@ -649,10 +649,10 @@ TEST_CASE("lexer string fast path")
for (const auto& test_case : cases)
{
CAPTURE(test_case.description)
CAPTURE(test_case.description);
for (const std::size_t offset : offsets)
{
CAPTURE(offset)
CAPTURE(offset);
const std::string doc = "[\"" + std::string(offset, 'a') + test_case.sequence + "\"]";
CHECK(json::accept(doc) == test_case.valid);
#if !defined(JSON_NOEXCEPTION)
@@ -1236,7 +1236,7 @@ TEST_CASE("Eisel-Lemire float conversion")
for (const auto& c : known)
{
CAPTURE(c.first)
CAPTURE(c.first);
double out = 0;
if (eisel_lemire(c.first, out))
{
@@ -1277,7 +1277,7 @@ TEST_CASE("Eisel-Lemire float conversion")
std::array<char, 64> buffer{};
const char* end = nlohmann::detail::to_chars(buffer.data(), buffer.data() + buffer.size(), d);
const std::string token(buffer.data(), static_cast<std::size_t>(end - buffer.data()));
CAPTURE(token)
CAPTURE(token);
double out = 0;
REQUIRE(eisel_lemire(token, out));
CHECK(bits_of(out) == b);
@@ -1289,7 +1289,7 @@ TEST_CASE("Eisel-Lemire float conversion")
const std::size_t dot = longer.find('.');
const std::string extra = dot == std::string::npos ? ".000000000000000000001" : "000000000000000000001";
longer.insert(e == std::string::npos ? longer.size() : e, extra);
CAPTURE(longer)
CAPTURE(longer);
if (eisel_lemire(longer, out))
{
CHECK(bits_of(out) == b);
+2 -2
View File
@@ -2561,7 +2561,7 @@ TEST_CASE("last-read diagnostics are identical across input adapters")
for (const auto& s : inputs)
{
CAPTURE(s)
CAPTURE(s);
// reference: contiguous std::string -> seekable (lazy) path
const std::string reference = parse_error_message(s);
@@ -2645,7 +2645,7 @@ TEST_CASE("diagnostic positions: value lifetime, input adapters, and SAX")
SECTION("move constructor resets the moved-from value to npos")
{
// basic_json(basic_json&&) (json.hpp, around line 1951) copies
// basic_json(basic_json&&) (json.hpp, around line 1265) copies
// other's start_position/end_position into *this and then resets
// other's to npos (see the cppcheck-suppress[accessForwarded]
// annotation there, which flags this reset as worth a second
+3 -3
View File
@@ -857,7 +857,7 @@ TEST_CASE("equality of objects whose entries have no fixed order")
for (const std::size_t depth : std::vector<std::size_t> {0, 200})
{
CAPTURE(depth)
CAPTURE(depth);
const unordered_json descending = nest(make_unordered_object(true), depth);
const unordered_json ascending = nest(make_unordered_object(false), depth);
@@ -909,7 +909,7 @@ TEST_CASE("equality of an object whose comparator treats different keys as equiv
for (const std::size_t depth : std::vector<std::size_t> {0, 127, 128, 200})
{
CAPTURE(depth)
CAPTURE(depth);
const ci_json x = nest(a, depth);
const ci_json y = nest(b, depth);
@@ -935,7 +935,7 @@ TEST_CASE("containers are compared element by element")
for (const std::size_t depth : std::vector<std::size_t> {0, 200})
{
CAPTURE(depth)
CAPTURE(depth);
// objects with different keys
{
+1 -1
View File
@@ -85,7 +85,7 @@ TEST_CASE("other constructors and destructor")
CHECK(j.type() == json::value_t::object);
const json k(std::move(j));
CHECK(k.type() == json::value_t::object);
CHECK(j.type() == json::value_t::null); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved) access after move is OK here
CHECK(j.type() == json::value_t::null); // NOLINT: access after move is OK here
}
SECTION("copy assignment")
+63 -4
View File
@@ -430,6 +430,37 @@ TEST_CASE("value conversion")
CHECK(std::equal(std::begin(nbs[0][0][0]), std::end(nbs[1][1][1]), std::begin(nbs2[0][0][0])));
}
SECTION("built-in arrays: 5D")
{
// NOLINTBEGIN(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
const int nbs[1][1][1][2][2] = {{{{{0, 1}, {2, 3}}}}};
int nbs2[1][1][1][2][2] = {{{{{0, 0}, {0, 0}}}}};
// NOLINTEND(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
const json j2 = nbs;
j2.get_to(nbs2);
CHECK(std::equal(std::begin(nbs[0][0][0][0]), std::end(nbs[0][0][0][1]), std::begin(nbs2[0][0][0][0])));
}
SECTION("built-in arrays: mismatched shape")
{
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
int nbs2[2][3] = {{0, 0, 0}, {0, 0, 0}};
// NOLINTEND(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
SECTION("not an array")
{
const json j2 = 42;
CHECK_THROWS_WITH_AS(j2.get_to(nbs2), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
}
SECTION("too few elements")
{
const json j2 = {{0, 1, 2}};
CHECK_THROWS_WITH_AS(j2.get_to(nbs2), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
}
}
SECTION("std::deque<json>")
{
std::deque<json> a{"previous", "value"};
@@ -1630,7 +1661,7 @@ TEST_CASE("value conversion")
enum class cards {kreuz, pik, herz, karo};
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness) - false positive
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(cards,
{
{cards::kreuz, "kreuz"},
@@ -1648,7 +1679,7 @@ enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguid
TS_INVALID = -1,
};
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage) - false positive
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
{
{TS_INVALID, nullptr},
@@ -1698,7 +1729,7 @@ TEST_CASE("JSON to enum mapping")
enum class strict_cards {kreuz, pik, herz, karo, andere}; // andere not included in mapping
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness) - false positive
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_cards,
{
{strict_cards::kreuz, "kreuz"},
@@ -1717,7 +1748,7 @@ enum StrictTaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppco
STRICT_TS_INVALID = -1,
};
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage) - false positive
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(StrictTaskState,
{
{STRICT_TS_INVALID, nullptr},
@@ -1726,6 +1757,34 @@ NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(StrictTaskState,
{STRICT_TS_COMPLETED, "completed"},
})
// regression test for #5708 item 2: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT must not rely on
// unqualified lookup of a helper name that a user's own namespace may also declare
namespace ns_with_colliding_name
{
// NOLINTNEXTLINE(misc-use-internal-linkage) - used to shadow the library's internal helper name
inline void templated_json_throw(int /*unused*/) {}
enum class colliding_enum { a, b };
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(colliding_enum,
{
{colliding_enum::a, "a"},
{colliding_enum::b, "b"}
})
} // namespace ns_with_colliding_name
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT in a namespace with a colliding name")
{
using ns_with_colliding_name::colliding_enum;
CHECK(json(colliding_enum::a) == "a");
CHECK(colliding_enum::b == json("b"));
json _;
CHECK_THROWS_WITH_AS(_ = json("nope").get<colliding_enum>(), "[json.exception.out_of_range.410] enum value out of range for colliding_enum: \"nope\"", json::out_of_range&);
}
TEST_CASE("Strict JSON to enum mapping")
{
SECTION("enum class")
+10
View File
@@ -516,6 +516,16 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
CHECK(j_array.value("/-"_json_pointer, 42) == 42);
CHECK(j_array_const.value("/-"_json_pointer, 42) == 42);
// Test an index that is syntactically valid but exceeds size_type, and one
// with a trailing non-digit: both must yield the default value rather than
// throw, even with exceptions disabled (regression test for #5708 item 4 /
// #5672: get_checked_or_null() no longer relies on a JSON_TRY/
// JSON_INTERNAL_CATCH around array_index() to turn these into "not found")
CHECK(j_array.value("/18446744073709551615"_json_pointer, 42) == 42);
CHECK(j_array_const.value("/18446744073709551615"_json_pointer, 42) == 42);
CHECK(j_array.value("/1a"_json_pointer, 42) == 42);
CHECK(j_array_const.value("/1a"_json_pointer, 42) == 42);
#if !defined(JSON_NOEXCEPTION)
// Test malformed index (non-numeric) throws parse_error
CHECK_THROWS_WITH_AS(j_array.value("/foo"_json_pointer, 1), "[json.exception.parse_error.109] parse error: array index 'foo' is not a number", typename Json::parse_error&);
+2 -2
View File
@@ -191,7 +191,7 @@ TEST_CASE("hash of deeply nested values")
// every depth on either side of where the iterative path takes over
for (std::size_t depth = 0; depth <= (2 * nlohmann::detail::recursion_depth_limit()) + 10; ++depth)
{
CAPTURE(depth)
CAPTURE(depth);
const auto arrays = nested<json>(depth, false);
const auto objects = nested<json>(depth, true);
const auto ordered = nested<ordered_json>(depth, true);
@@ -212,7 +212,7 @@ TEST_CASE("hash of deeply nested values")
false, true
})
{
CAPTURE(objects)
CAPTURE(objects);
const auto text = nested_text(depth, objects);
const auto a = json::parse(text);
const auto b = json::parse(text);
+1 -1
View File
@@ -1893,7 +1893,7 @@ TEST_CASE("JSON patch - every operation on ordered_json")
};
for (const auto& target : targets)
{
CAPTURE(target.dump())
CAPTURE(target.dump());
CHECK(source.patch(ordered_json::diff(source, target)) == target);
}
}
+1 -1
View File
@@ -116,7 +116,7 @@ TEST_CASE("tests on deeply nested JSONs")
// are known to meet cleanly - wherever the bound is set.
for (std::size_t d = 1; d <= 300; ++d)
{
CAPTURE(d)
CAPTURE(d);
const json array = json::parse(std::string(d, '[') + '0' + std::string(d, ']'));
const json array_copy(array); // NOLINT(performance-unnecessary-copy-initialization): the copy is what is tested
+3 -3
View File
@@ -286,8 +286,8 @@ TEST_CASE("locale changes between lexer construction and number conversion (#519
for (const auto& transition : transitions)
{
CAPTURE(transition.first)
CAPTURE(transition.second)
CAPTURE(transition.first);
CAPTURE(transition.second);
if (std::setlocale(LC_NUMERIC, transition.first) == nullptr)
{
@@ -365,7 +365,7 @@ TEST_CASE("locale with a multi-byte decimal point")
{
continue;
}
CAPTURE(name)
CAPTURE(name);
tested = true;
// too many significant digits for Clinger's fast path, and an underflow
+2 -2
View File
@@ -305,10 +305,10 @@ TEST_CASE("JSON Merge Patch on deeply nested values")
// over (detail::recursion_depth_limit(), 128)
for (std::size_t depth = 0; depth <= 300; ++depth)
{
CAPTURE(depth)
CAPTURE(depth);
for (int variant = 0; variant < 3; ++variant)
{
CAPTURE(variant)
CAPTURE(variant);
const json patch = json::parse(nested_objects(depth, variant));
json result = json::parse(nested_objects(depth, (variant + 1) % 3));
+2 -2
View File
@@ -1084,10 +1084,10 @@ TEST_CASE("update() on deeply nested values")
// over (detail::recursion_depth_limit(), 128)
for (std::size_t depth = 0; depth <= 300; ++depth)
{
CAPTURE(depth)
CAPTURE(depth);
for (int variant = 0; variant < 3; ++variant)
{
CAPTURE(variant)
CAPTURE(variant);
const json source = json::parse(nested_objects(depth, variant));
json result = json::parse(nested_objects(depth, (variant + 1) % 3));
json expected = result;
+3 -3
View File
@@ -113,7 +113,7 @@ TEST_CASE("JSON_PRECISE_STREAM_POSITION")
for (const auto& test : tests)
{
CAPTURE(test.first)
CAPTURE(test.first);
std::istringstream ss(test.first);
json j;
ss >> j;
@@ -135,7 +135,7 @@ TEST_CASE("JSON_PRECISE_STREAM_POSITION")
for (const auto& test : tests)
{
CAPTURE(test.first)
CAPTURE(test.first);
std::istringstream ss(test.first);
json j;
ss >> j;
@@ -149,7 +149,7 @@ TEST_CASE("JSON_PRECISE_STREAM_POSITION")
{"1", "12", "-3.5e2", " 7 "
})
{
CAPTURE(s)
CAPTURE(s);
std::istringstream ss(s);
json j;
ss >> j;
+1 -1
View File
@@ -112,7 +112,7 @@ enum class for_1647
two
};
// NOLINTNEXTLINE(misc-const-correctness): this is a false positive
// NOLINTNEXTLINE(misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive
NLOHMANN_JSON_SERIALIZE_ENUM(for_1647,
{
{for_1647::one, "one"},
+2 -2
View File
@@ -849,13 +849,13 @@ TEST_CASE("issue #5338 - truncated CBOR tagged binary subtype is rejected")
for (const auto& data : truncated_tags)
{
CAPTURE(data)
CAPTURE(data);
for (const auto tag_handler :
{
json::cbor_tag_handler_t::ignore, json::cbor_tag_handler_t::store
})
{
CAPTURE(tag_handler)
CAPTURE(tag_handler);
const auto result = json::from_cbor(data, true, false, tag_handler);
CHECK(result.is_discarded());
}
+6 -6
View File
@@ -584,7 +584,7 @@ TEST_CASE("serialization of deeply nested values")
// value are known to meet cleanly - wherever the bound is set.
for (std::size_t d = 1; d <= 300; ++d)
{
CAPTURE(d)
CAPTURE(d);
const std::string array_text = std::string(d, '[') + '7' + std::string(d, ']');
CHECK(json::parse(array_text).dump() == array_text);
@@ -604,7 +604,7 @@ TEST_CASE("serialization of deeply nested values")
{
for (std::size_t d = 120; d <= 140; ++d)
{
CAPTURE(d)
CAPTURE(d);
const json j = json::parse(std::string(d, '[') + '7' + std::string(d, ']'));
@@ -629,7 +629,7 @@ TEST_CASE("serialization of deeply nested values")
// so it must not gain a newline when it is reached iteratively
for (std::size_t d = 125; d <= 135; ++d)
{
CAPTURE(d)
CAPTURE(d);
const std::string compact = std::string(d, '[') + "[]" + std::string(d, ']');
CHECK(json::parse(compact).dump() == compact);
@@ -711,10 +711,10 @@ TEST_CASE("serialization of every kind of value below the bound of the descent")
for (const std::size_t depth : std::vector<std::size_t> {1, 200})
{
CAPTURE(depth)
CAPTURE(depth);
for (const auto& inner : values)
{
CAPTURE(inner.dump())
CAPTURE(inner.dump());
const json j = wrap_in_arrays(inner, depth);
CHECK(j.dump() == std::string(depth, '[') + inner.dump() + std::string(depth, ']'));
CHECK(j.dump(2) == expected_pretty_in_arrays(inner, depth));
@@ -725,7 +725,7 @@ TEST_CASE("serialization of every kind of value below the bound of the descent")
{
for (std::size_t d = 120; d <= 140; ++d)
{
CAPTURE(d)
CAPTURE(d);
// built from the inside out: {"k": <level below>, "n": <level>}
json j = 7;
+12
View File
@@ -10,10 +10,14 @@
#if JSON_TEST_USING_MULTIPLE_HEADERS
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/ordered_map.hpp>
#else
#include <nlohmann/json.hpp>
#endif
#include <map>
#include <string>
TEST_CASE("type traits")
{
SECTION("is_c_string")
@@ -83,4 +87,12 @@ TEST_CASE("type traits")
}
}
}
SECTION("is_ordered_map")
{
using nlohmann::detail::is_ordered_map;
CHECK(is_ordered_map<nlohmann::ordered_map<std::string, int>>::value);
CHECK_FALSE(is_ordered_map<std::map<std::string, int>>::value);
}
}
+3 -3
View File
@@ -350,7 +350,7 @@ TEST_CASE("std::counted_iterator reaches the contiguous fast paths")
for (const auto& text : diagnostic_docs)
{
CAPTURE(text)
CAPTURE(text);
const std::counted_iterator<const char*> it(text.data(), static_cast<std::iter_difference_t<const char*>>(text.size()));
std::string counted_message;
std::string string_message;
@@ -460,8 +460,8 @@ TEST_CASE("std::counted_iterator bulk scanning stops at the counted end")
for (const auto& tc : cases)
{
CAPTURE(tc.buffer)
CAPTURE(tc.count)
CAPTURE(tc.buffer);
CAPTURE(tc.count);
const std::string buffer = tc.buffer;
CHECK(via_counted(buffer, tc.count) == via_prefix(buffer, tc.count));
}