diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6f3d0bef3..9c3bb2c04 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -205,6 +205,9 @@ API of the 3.x.y version is broken. This includes: - Changing access specifiers. - Changing default arguments. +What is and is not covered by this guarantee is described in the +[roadmap](https://json.nlohmann.me/community/roadmap/#api-stability). + Although these guidelines may seem restrictive, they are essential for maintaining the library’s utility. Breaking changes may be introduced when they are guarded with a feature macro such as diff --git a/.github/external_ci/appveyor.yml b/.github/external_ci/appveyor.yml index 805195742..21bb2e27a 100644 --- a/.github/external_ci/appveyor.yml +++ b/.github/external_ci/appveyor.yml @@ -16,6 +16,9 @@ only_commits: environment: matrix: + # The Visual Studio 2017 jobs compile everything with /std:c++17, so they + # only build the C++17 variant of each test, split into two jobs each to + # stay below AppVeyor's 60-minute limit per job. - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 configuration: Debug platform: x86 @@ -34,7 +37,13 @@ environment: configuration: Release platform: x86 CXX_FLAGS: "/permissive- /std:c++17 /utf-8 /W4 /WX" - CMAKE_OPTIONS: "" + CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=0/2" + GENERATOR: Visual Studio 15 2017 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + configuration: Release + platform: x86 + CXX_FLAGS: "/permissive- /std:c++17 /utf-8 /W4 /WX" + CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=1/2" GENERATOR: Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 @@ -55,7 +64,13 @@ environment: configuration: Release platform: x64 CXX_FLAGS: "/permissive- /std:c++17 /Zc:__cplusplus /utf-8 /W4 /WX" - CMAKE_OPTIONS: "" + CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=0/2" + GENERATOR: Visual Studio 15 2017 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + configuration: Release + platform: x64 + CXX_FLAGS: "/permissive- /std:c++17 /Zc:__cplusplus /utf-8 /W4 /WX" + CMAKE_OPTIONS: "-DJSON_TestStandards=17 -DJSON_TestShard=1/2" GENERATOR: Visual Studio 15 2017 init: @@ -66,15 +81,10 @@ install: - if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32 before_build: - - cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%" + - cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On %CMAKE_OPTIONS% build_script: - cmake --build . --config "%configuration%" --parallel 2 test_script: - - if "%configuration%"=="Release" ctest -C "%configuration%" --parallel 2 --output-on-failure - # On Debug builds, skip test-unicode_all - # as it is extremely slow to run and cause - # occasional timeouts on AppVeyor. - # More info: https://github.com/nlohmann/json/pull/1570 - - if "%configuration%"=="Debug" ctest --exclude-regex "test-unicode" -C "%configuration%" --parallel 2 --output-on-failure + - ctest -C "%configuration%" --parallel 2 --output-on-failure diff --git a/.github/workflows/check_amalgamation.yml b/.github/workflows/check_amalgamation.yml index 2f234d8be..a497b4ce4 100644 --- a/.github/workflows/check_amalgamation.yml +++ b/.github/workflows/check_amalgamation.yml @@ -149,6 +149,13 @@ jobs: VERSION_MAJOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MAJOR' $ABI_MACROS | grep -o '[0-9]\+') VERSION_MINOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MINOR' $ABI_MACROS | grep -o '[0-9]\+') VERSION_PATCH=$(grep -m1 'define NLOHMANN_JSON_VERSION_PATCH' $ABI_MACROS | grep -o '[0-9]\+') + # The template is what this check verifies the committed natvis + # file against, so take it from this PR rather than from the + # develop checkout: generate_natvis.py loads the template from its + # own directory, and with develop's copy a PR that changes the + # template could never pass. Like the macro_builder step above, + # this only renders PR content in a job without credentials. + cp tools/generate_natvis/nlohmann_json.natvis.j2 $NATVIS_TOOL_DIR/ python3 $NATVIS_TOOL_DIR/generate_natvis.py --version "$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" $MAIN_DIR - name: Build patch and check for differences diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0adaf26d5..75afc6310 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -17,11 +17,11 @@ permissions: contents: read jobs: - macos-14: - runs-on: macos-14 # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md + macos-15: + runs-on: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md strategy: matrix: - xcode: ['15.0.1', '15.1', '15.2', '15.3', '15.4'] + xcode: ['16.0', '16.1', '16.2', '16.3', '16.4', '26.0.1', '26.1.1', '26.2', '26.3'] env: DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer @@ -36,11 +36,11 @@ jobs: - name: Test run: cd build ; ctest -j 10 --output-on-failure - macos-15: - runs-on: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md + macos-26: + runs-on: macos-26 # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md strategy: matrix: - xcode: ['16.0', '16.1', '16.2', '16.3', '16.4', '26.0.1'] + xcode: ['26.4.1', '26.5', '26.6'] env: DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer @@ -71,3 +71,38 @@ jobs: run: cmake --build build --parallel 10 - name: Test run: cd build ; ctest -j 10 --output-on-failure + + swiftpm: + runs-on: macos-15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Check that Package.swift resolves without a deprecation warning + run: swift package dump-package + - name: Build the SwiftPM documentation example against this checkout + run: | + mkdir -p /tmp/json-swiftpm-consumer/Sources/MyLibrary + cp docs/mkdocs/docs/integration/swift/example.cpp /tmp/json-swiftpm-consumer/Sources/MyLibrary/example.cpp + cat > /tmp/json-swiftpm-consumer/Package.swift << EOF + // swift-tools-version: 5.9 + import PackageDescription + + let package = Package( + name: "MyPackage", + dependencies: [ + .package(path: "${{ github.workspace }}") + ], + targets: [ + .target( + name: "MyLibrary", + dependencies: [ + .product(name: "json", package: "json") + ], + publicHeadersPath: "." + ) + ] + ) + EOF + cd /tmp/json-swiftpm-consumer + swift build diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 1e4a72870..1fa2f9fc6 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -107,7 +107,7 @@ jobs: container: ubuntu:24.04 strategy: matrix: - target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local] + target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_delete_deprecated_functions, ci_test_no_thread_local] steps: - name: Install build-essential run: apt-get update ; apt-get install -y build-essential unzip wget git @@ -209,7 +209,7 @@ jobs: strategy: matrix: # older GCC docker images (4, 5, 6) fail to check out code - compiler: ['7', '8', '9', '10', '11', '12', '13', '14', '15', 'latest'] + compiler: ['7', '8', '9', '10', '11', '12', '13', '14', '15', '16', 'latest'] container: gcc:${{ matrix.compiler }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 65169eac4..855d8af95 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -178,7 +178,7 @@ jobs: - name: Build run: cmake --build build --parallel 10 - name: Test - run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure + run: cd build ; ctest -j 10 -C Debug --output-on-failure clang-cl-12: runs-on: windows-2022 @@ -195,7 +195,7 @@ jobs: - name: Build run: cmake --build build --config Debug --parallel 10 - name: Test - run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure + run: cd build ; ctest -j 10 -C Debug --output-on-failure ci_module_cpp20: runs-on: windows-2022 diff --git a/.inferconfig b/.inferconfig index 9a5a36873..21f6229e9 100644 --- a/.inferconfig +++ b/.inferconfig @@ -1,5 +1,7 @@ { "_comment": "Used by the ci_infer CMake target (#5715 item 4b). fail-on-issue makes CI fail on Infer findings; disable-issue-type is a type-level baseline for the ~174 pre-existing findings (all PULSE_UNNECESSARY_COPY*/PULSE_RESOURCE_LEAK/PULSE_CONST_REFABLE, mostly in test code) triaged in run https://github.com/nlohmann/json/actions/runs/35829411620 on commit 1054b2097, so CI fails only on a NEW issue type. Remove an entry here once its findings have been fixed or explicitly accepted.", + "_comment_pulse": "Pulse stops exploring paths after pulse-max-disjuncts (default 20). With the default, basic_json::replace_value() (destroy + assert_invariant) exceeds the limit, Pulse loses the stored type, and reports false NULLPTR_DEREFERENCE findings for get_ptr() results in tests/src/unit-pointer_access.cpp.", + "pulse-max-disjuncts": 40, "fail-on-issue": true, "disable-issue-type": [ "PULSE_UNNECESSARY_COPY_ASSIGNMENT", diff --git a/.reuse/dep5 b/.reuse/dep5 deleted file mode 100644 index d12cb816c..000000000 --- a/.reuse/dep5 +++ /dev/null @@ -1,36 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: json -Upstream-Contact: Niels Lohmann -Source: https://github.com/nlohmann/json - -Files: * -Copyright: 2013-2026 Niels Lohmann -License: MIT - -Files: include/nlohmann/thirdparty/hedley.hpp -Copyright: 2016-2021 Evan Nemerson -License: CC0 - -Files: include/nlohmann/detail/meta/cpp_future.hpp -Copyright: 2013-2026 Niels Lohmann and 2018 The Abseil Authors -License: MIT AND Apache-2.0 - -Files: tests/thirdparty/doctest/* -Copyright: 2016-2023 Viktor Kirilov -License: MIT - -Files: tests/thirdparty/fifo_map/* -Copyright: 2015-2017 Niels Lohmann -License: MIT - -Files: tests/thirdparty/imapdl/* -Copyright: 2017 Georg Sauthoff -License: GPL-3.0-only - -Files: tools/amalgamate/* -Copyright: 2012 Erik Edlund -License: BSD-3-Clause - -Files: tools/gdb_pretty_printer/* -Copyright: 2020 Hannes Domani -License: MIT diff --git a/BUILD.bazel b/BUILD.bazel index 3dfffad1e..268c3e959 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -80,6 +80,7 @@ cc_library( name = "singleheader-json", hdrs = [ "single_include/nlohmann/json.hpp", + "single_include/nlohmann/json_fwd.hpp", ], includes = ["single_include"], visibility = ["//visibility:public"], diff --git a/CITATION.cff b/CITATION.cff index 8a70c17bc..eb5118999 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -10,5 +10,5 @@ title: "JSON for Modern C++" version: 3.12.0 date-released: 2025-04-07 license: MIT -repository-code: "https://github.com/nlohmann" +repository-code: "https://github.com/nlohmann/json" url: https://json.nlohmann.me diff --git a/CMakeLists.txt b/CMakeLists.txt index b5092ae49..fed9e3171 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,11 @@ endif() ## OPTIONS ## +# Build the tests by default only for the main project and only if the tests +# directory exists (the release archive json.tar.xz does not contain it). # VERSION_GREATER_EQUAL is not available in older CMake (< 3.7) -if(${MAIN_PROJECT} AND (${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)) +if(${MAIN_PROJECT} AND (${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13) + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt") set(JSON_BuildTests_INIT ON) else() set(JSON_BuildTests_INIT OFF) @@ -62,6 +65,7 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the l option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF) option(JSON_StrictNulHandling "Build with strict NUL-byte handling enabled." OFF) option(JSON_StrictBinaryUTF8 "Build with UTF-8 checks in the CBOR, UBJSON, BJData, and BSON writers enabled." OFF) +option(JSON_DeleteDeprecatedFunctions "Delete the deprecated functions instead of only deprecating them." OFF) if (JSON_CI) include(ci) @@ -123,6 +127,10 @@ if (JSON_StrictBinaryUTF8) message(STATUS "Strict UTF-8 checks in binary writers enabled (JSON_STRICT_BINARY_UTF8=1)") endif() +if (JSON_DeleteDeprecatedFunctions) + message(STATUS "Deprecated functions are deleted (JSON_DELETE_DEPRECATED_FUNCTIONS=1)") +endif() + if (JSON_Diagnostic_Positions) message(STATUS "Diagnostic positions enabled (JSON_DIAGNOSTIC_POSITIONS=1)") endif() @@ -159,6 +167,7 @@ target_compile_definitions( $<$:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1> $<$:JSON_STRICT_NUL_HANDLING=1> $<$:JSON_STRICT_BINARY_UTF8=1> + $<$:JSON_DELETE_DEPRECATED_FUNCTIONS=1> ) target_include_directories( diff --git a/FILES.md b/FILES.md index d13be1238..861fdf610 100644 --- a/FILES.md +++ b/FILES.md @@ -196,19 +196,19 @@ Further documentation: ## REUSE -### `.reuse/dep5` +### `REUSE.toml` The file defines the licenses of certain third-party components in the repository. The root `Makefile` contains a target `reuse` that checks for compliance. Further documentation: -- [DEP5](https://reuse.software/spec-3.2/#dep5-deprecated) +- [REUSE.toml](https://reuse.software/spec-3.3/#reusetoml) - [reuse command-line tool](https://pypi.org/project/reuse/) - [documentation of linting](https://reuse.readthedocs.io/en/stable/man/reuse-lint.html) - [REUSE](http://reuse.software) > [!IMPORTANT] -> The filename `.reuse/dep5` is predetermined by REUSE. Alternatively, a `REUSE.toml` file can be used. +> The filename `REUSE.toml` is predetermined by REUSE. Alternatively, a `.reuse/dep5` file (deprecated) can be used. ### `.reuse/templates` diff --git a/Makefile b/Makefile index 3a7fa5c41..11b9227a4 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ # find GNU sed to use `-i` parameter SED:=$(shell command -v gsed || which sed) +# find GNU tar to use `--sort` and `--pax-option` parameters +TAR:=$(shell command -v gtar || which tar) + ########################################################################## # source files @@ -174,8 +177,8 @@ ChangeLog.md: # archive is created according to the advices of . json.tar.xz: mkdir json - rsync -R $(shell find LICENSE.MIT nlohmann_json.natvis CMakeLists.txt cmake/*.in include single_include -type f) json - gtar --sort=name --mtime="@$(shell git log -1 --pretty=%ct)" --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime --create --file - json | xz --compress -9e --threads=2 - > json.tar.xz + rsync -R $(shell find LICENSE.MIT nlohmann_json.natvis CMakeLists.txt cmake/*.in include single_include src/modules -type f) json + $(TAR) --sort=name --mtime="@$(shell git log -1 --pretty=%ct)" --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime --create --file - json | xz --compress -9e --threads=2 - > json.tar.xz rm -fr json # We use `-X` to make the resulting ZIP file reproducible, see diff --git a/Package.swift b/Package.swift index 2f1e654a2..09b12dea3 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "nlohmann-json", platforms: [ - .iOS(.v12), .macOS(.v10_13), .tvOS(.v12), .watchOS(.v4), .visionOS(.v1) + .iOS(.v12), .macOS(.v10_13), .tvOS(.v12), .watchOS(.v9), .visionOS(.v1) ], products: [ .library(name: "json", targets: ["json"]) diff --git a/README.md b/README.md index ae0ad12d2..c6c5613d5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://app.codacy.com/gh/nlohmann/json/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) -[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json) +[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://issues.oss-fuzz.com/issues?q=project:json) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7) [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/develop/LICENSE.MIT) @@ -361,7 +361,7 @@ std::cout << j_string << " == " << serialized_string << std::endl; [`.dump()`](https://json.nlohmann.me/api/basic_json/dump/) returns the originally stored string value. -Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. +Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace`, `json::error_handler_t::ignore`, or `json::error_handler_t::keep` are used as error handlers. #### To/from streams (e.g., files, string streams) @@ -1202,15 +1202,18 @@ language bindings, format converters, and the like. See the curated [Ecosystem]( Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.8 - 14.2 (and possibly later) -- Clang 3.4 - 21.0 (and possibly later) -- Apple Clang 9.1 - 16.0 (and possibly later) -- Intel C++ Compiler 17.0.2 (and possibly later) -- Nvidia CUDA Compiler 11.0.221 (and possibly later) -- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) -- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) -- Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later) -- Microsoft Visual C++ 2022 / Build Tools 19.30.30709.0 (and possibly later) +- GCC 4.8 - 16.2 (and possibly later) +- Clang 3.4 - 22.1 (and possibly later) +- Apple Clang 15.0 - 21.0 (and possibly later) +- Intel C++ Compiler Classic (icpc) 2021.10 +- Intel oneAPI DPC++/C++ Compiler (icpx) 2025.3 (and possibly later) +- NVIDIA CUDA Compiler (nvcc) 11.8 - 12.6 (and possibly later) +- NVIDIA HPC SDK C++ Compiler (nvc++) 25.5 (and possibly later) +- Microsoft Visual C++ 2015 / MSVC 19.0 (and possibly later) +- Microsoft Visual C++ 2017 / MSVC 19.16 (and possibly later) +- Microsoft Visual C++ 2019 / MSVC 19.29 (and possibly later) +- Microsoft Visual C++ 2022 / MSVC 19.44 (and possibly later) +- Microsoft Visual C++ 2026 / MSVC 19.51 (and possibly later) I would be happy to learn about other compilers/versions. @@ -1401,7 +1404,7 @@ The library is compliant to version 3.3 of the [**REUSE specification**](https:/ - Every source file contains an SPDX copyright header. - The full text of all licenses used in the repository can be found in the `LICENSES` folder. -- File `.reuse/dep5` contains an overview of all files' copyrights and licenses. +- File `REUSE.toml` contains an overview of all files' copyrights and licenses. - Run `pipx run reuse lint` to verify the project's REUSE compliance and `pipx run reuse spdx` to generate a SPDX SBOM. ## Contact @@ -1914,7 +1917,7 @@ The library supports **Unicode input** as follows: - [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. -- When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. +- When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace`, `json::error_handler_t::ignore`, or `json::error_handler_t::keep` are used as error handlers. - To store wide strings (e.g., `std::wstring`), you need to convert them to a UTF-8 encoded `std::string` before, see [an example](https://json.nlohmann.me/home/faq/#wide-string-handling). ### Comments in JSON diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 000000000..47bcab16a --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,52 @@ +version = 1 +SPDX-PackageName = "json" +SPDX-PackageSupplier = "Niels Lohmann " +SPDX-PackageDownloadLocation = "https://github.com/nlohmann/json" + +[[annotations]] +path = "**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2013-2026 Niels Lohmann " +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "include/nlohmann/thirdparty/hedley.hpp" +precedence = "aggregate" +SPDX-FileCopyrightText = "2016-2021 Evan Nemerson " +SPDX-License-Identifier = "CC0" + +[[annotations]] +path = "include/nlohmann/detail/meta/cpp_future.hpp" +precedence = "aggregate" +SPDX-FileCopyrightText = "2013-2026 Niels Lohmann and 2018 The Abseil Authors" +SPDX-License-Identifier = "MIT AND Apache-2.0" + +[[annotations]] +path = "tests/thirdparty/doctest/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2016-2023 Viktor Kirilov" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "tests/thirdparty/fifo_map/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2015-2017 Niels Lohmann" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "tests/thirdparty/imapdl/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2017 Georg Sauthoff " +SPDX-License-Identifier = "GPL-3.0-only" + +[[annotations]] +path = "tools/amalgamate/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2012 Erik Edlund " +SPDX-License-Identifier = "BSD-3-Clause" + +[[annotations]] +path = "tools/gdb_pretty_printer/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2020 Hannes Domani " +SPDX-License-Identifier = "MIT" diff --git a/cmake/ci.cmake b/cmake/ci.cmake index d0af68786..15345c5d6 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -249,6 +249,20 @@ add_custom_target(ci_test_strict_nul_handling COMMENT "Compile and test with strict NUL-byte handling enabled" ) +############################################################################### +# Delete the deprecated functions. +############################################################################### + +add_custom_target(ci_test_delete_deprecated_functions + COMMAND ${CMAKE_COMMAND} + -DCMAKE_BUILD_TYPE=Debug -GNinja + -DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DeleteDeprecatedFunctions=ON + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_delete_deprecated_functions + COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_delete_deprecated_functions + COMMAND cd ${PROJECT_BINARY_DIR}/build_delete_deprecated_functions && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure + COMMENT "Compile and test with the deprecated functions deleted" +) + ############################################################################### # Disable global UDLs. ############################################################################### @@ -362,7 +376,7 @@ add_custom_target(ci_test_coverage # Sanitizers. ############################################################################### -set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base") +set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base -fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/cmake/clang_sanitizer_ignorelist.txt") add_custom_target(ci_test_clang_sanitizer COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXX_FLAGS_SANITIZER} ${CMAKE_COMMAND} @@ -442,13 +456,14 @@ add_custom_target(ci_test_single_header # Valgrind. ############################################################################### +# The Unicode test (~17M assertions) is too slow under Valgrind. add_custom_target(ci_test_valgrind COMMAND CXX=${GCC_TOOL} ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -DJSON_Valgrind=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_valgrind COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_valgrind - COMMAND cd ${PROJECT_BINARY_DIR}/build_valgrind && ${CMAKE_CTEST_COMMAND} -L valgrind --parallel ${N} --output-on-failure + COMMAND cd ${PROJECT_BINARY_DIR}/build_valgrind && ${CMAKE_CTEST_COMMAND} -L valgrind --exclude-regex "test-unicode" --parallel ${N} --output-on-failure COMMENT "Compile and test with Valgrind" ) @@ -705,7 +720,7 @@ ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY) # the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0 set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind - JSON_StrictNulHandling JSON_StrictBinaryUTF8) + JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions) set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) @@ -773,7 +788,7 @@ foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 g++-11 cla -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} ${ADDITIONAL_FLAGS} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} - COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode" --output-on-failure + COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure COMMENT "Compile and test with ${COMPILER}" ) endif() @@ -787,7 +802,7 @@ add_custom_target(ci_test_compiler_default -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_default ${ADDITIONAL_FLAGS} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_default --parallel ${N} - COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_default && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode" -LE git_required --output-on-failure + COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_default && ${CMAKE_CTEST_COMMAND} --parallel ${N} -LE git_required --output-on-failure COMMENT "Compile and test with default C++ compiler" ) @@ -825,7 +840,7 @@ add_custom_target(ci_icpc -DJSON_BuildTests=ON -DJSON_FastTests=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_icpc COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_icpc - COMMAND cd ${PROJECT_BINARY_DIR}/build_icpc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode" --output-on-failure + COMMAND cd ${PROJECT_BINARY_DIR}/build_icpc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure COMMENT "Compile and test with ICPC" ) @@ -836,7 +851,7 @@ add_custom_target(ci_icpx -DJSON_BuildTests=ON -DJSON_FastTests=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_icpx COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_icpx - COMMAND cd ${PROJECT_BINARY_DIR}/build_icpx && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode" --output-on-failure + COMMAND cd ${PROJECT_BINARY_DIR}/build_icpx && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure COMMENT "Compile and test with ICPX (Intel oneAPI DPC++/C++)" ) @@ -872,7 +887,7 @@ add_custom_target(ci_nvhpc COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_nvhpc # the pipes are escaped so the surrounding shell passes them to ctest verbatim # instead of treating them as shell pipe operators - COMMAND cd ${PROJECT_BINARY_DIR}/build_nvhpc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode\\|test-comparison_cpp20\\|test-comparison_legacy_cpp20\\|test-constructor1_cpp11\\|test-deserialization_cpp20" --output-on-failure + COMMAND cd ${PROJECT_BINARY_DIR}/build_nvhpc && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-comparison_cpp20\\|test-comparison_legacy_cpp20\\|test-constructor1_cpp11\\|test-deserialization_cpp20" --output-on-failure COMMENT "Compile and test with NVIDIA HPC SDK (nvc++)" ) diff --git a/cmake/clang_sanitizer_ignorelist.txt b/cmake/clang_sanitizer_ignorelist.txt new file mode 100644 index 000000000..153b6a76d --- /dev/null +++ b/cmake/clang_sanitizer_ignorelist.txt @@ -0,0 +1,8 @@ +# Sanitizer ignore list for ci_test_clang_sanitizer (-fsanitize-ignorelist). +# +# libstdc++ 14's declares `_Scanner(basic_string_view<_CharT>, size_t __nargs = -1)`, so every std::format +# call converts -1 to size_t, which -fsanitize=integer reports as implicit-integer-sign-change. This is +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119429, not a bug in this library. Only that check and only are +# excluded, so implicit sign changes in the library and the tests are still reported. +[implicit-integer-sign-change] +src:*/include/c++/*/format diff --git a/cmake/scripts/gen_bazel_build_file.cmake b/cmake/scripts/gen_bazel_build_file.cmake index a781a2e3f..ca5069cb0 100644 --- a/cmake/scripts/gen_bazel_build_file.cmake +++ b/cmake/scripts/gen_bazel_build_file.cmake @@ -48,6 +48,7 @@ cc_library( name = "singleheader-json", hdrs = [ "single_include/nlohmann/json.hpp", + "single_include/nlohmann/json_fwd.hpp", ], includes = ["single_include"], visibility = ["//visibility:public"], diff --git a/cmake/scripts/gen_hedley_undef_check.cmake b/cmake/scripts/gen_hedley_undef_check.cmake index fc8cfec2c..f796588c6 100644 --- a/cmake/scripts/gen_hedley_undef_check.cmake +++ b/cmake/scripts/gen_hedley_undef_check.cmake @@ -64,7 +64,7 @@ if(MODE STREQUAL "undef") # recipe is self-contained and its output is byte-stable across reruns. # The embedded SPDX tags below are part of the *generated* file's # content, not a REUSE header for this .cmake script itself (which is - # already covered by the blanket "Files: *" rule in .reuse/dep5) -- keep + # already covered by the blanket path = "**" rule in REUSE.toml) -- keep # them wrapped in REUSE-IgnoreStart/End so `reuse lint` does not try to # parse "MIT\n")" as this file's own SPDX-License-Identifier value. # REUSE-IgnoreStart diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index 801ade93a..5549b55d0 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -131,6 +131,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_string', 'Meth INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::to_ubjson', 'Function', 'api/basic_json/to_ubjson/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::value', 'Method', 'api/basic_json/value/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::value_t', 'Enum', 'api/basic_json/value_t/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::with_t', 'Type', 'api/basic_json/with_t/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::~basic_json', 'Method', 'api/basic_json/~basic_json/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json', 'Class', 'api/json/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer', 'Class', 'api/json_pointer/index.html'); @@ -219,6 +220,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', ' INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DELETE_DEPRECATED_FUNCTIONS', 'Macro', 'api/macros/json_delete_deprecated_functions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html'); @@ -249,6 +251,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_TRY_USER', 'Macro', 'api INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS', 'Macro', 'api/macros/json_use_objects_for_enum_keyed_maps/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); diff --git a/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md b/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md index dfeb5d693..55a7954d5 100644 --- a/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md +++ b/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md @@ -9,10 +9,10 @@ enum class cbor_tag_handler_t }; ``` -This enumeration is used in the [`from_cbor`](from_cbor.md) function to choose how to treat tags: +This enumeration is used in [`from_cbor`](from_cbor.md) and [`sax_parse`](sax_parse.md) to choose how to treat tags: error -: throw a `parse_error` exception in case of a tag +: report a parse error in case of a tag (the `from_cbor` overloads throw a `parse_error` exception by default) ignore : ignore tags diff --git a/docs/mkdocs/docs/api/basic_json/diff.md b/docs/mkdocs/docs/api/basic_json/diff.md index fb6683ec8..ae22454dd 100644 --- a/docs/mkdocs/docs/api/basic_json/diff.md +++ b/docs/mkdocs/docs/api/basic_json/diff.md @@ -8,7 +8,7 @@ static basic_json diff(const basic_json& source, Creates a [JSON Patch](http://jsonpatch.com) so that value `source` can be changed into the value `target` by calling [`patch`](patch.md) function. -For two JSON values `source` and `target`, the following code yields always `#!cpp true`: +For two JSON values `source` and `target`, the following code always yields `#!cpp true`: ```cpp source.patch(diff(source, target)) == target; ``` @@ -27,7 +27,7 @@ a JSON patch to convert the `source` to `target` ## Exception safety -Strong guarantee: if an exception is thrown, there are no changes in the JSON value. +Strong guarantee: `source` and `target` are never modified. ## Complexity diff --git a/docs/mkdocs/docs/api/basic_json/from_bjdata.md b/docs/mkdocs/docs/api/basic_json/from_bjdata.md index a45e00ad5..f19f9e4a9 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bjdata.md +++ b/docs/mkdocs/docs/api/basic_json/from_bjdata.md @@ -120,3 +120,12 @@ Linear in the size of the input. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0. - Added `error_handler` parameter in version 3.13.0. + +!!! warning "Deprecation" + + - Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been + deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like + `#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. diff --git a/docs/mkdocs/docs/api/basic_json/from_bon8.md b/docs/mkdocs/docs/api/basic_json/from_bon8.md index 2f9d1e749..cac6b31eb 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bon8.md +++ b/docs/mkdocs/docs/api/basic_json/from_bon8.md @@ -106,3 +106,12 @@ Linear in the size of the input. ## Version history - Added in version 3.13.0. + +!!! warning "Deprecation" + + - Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been + deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like + `#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. diff --git a/docs/mkdocs/docs/api/basic_json/index.md b/docs/mkdocs/docs/api/basic_json/index.md index fc934ca93..fdb57105c 100644 --- a/docs/mkdocs/docs/api/basic_json/index.md +++ b/docs/mkdocs/docs/api/basic_json/index.md @@ -109,6 +109,9 @@ The class satisfies the following concept requirements: - **initializer_list_t** - type for initializer lists of `basic_json` values - [**input_format_t**](input_format_t.md) - type to choose the format to parse - [**json_sax_t**](../json_sax/index.md) - type for SAX events +- [**with_object_t, with_array_t, with_string_t, with_boolean_t, with_integers_t, with_float_t, with_allocator_t, + with_json_serializer_t, with_binary_t, with_base_class_t**](with_t.md) - types to create a `basic_json` type with + one (or two) replaced template parameters ### Exceptions diff --git a/docs/mkdocs/docs/api/basic_json/number_float_t.md b/docs/mkdocs/docs/api/basic_json/number_float_t.md index 8419a392d..282bb6123 100644 --- a/docs/mkdocs/docs/api/basic_json/number_float_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_float_t.md @@ -55,6 +55,10 @@ This implementation does exactly follow this approach, as it uses double precisi smaller than `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` will be stored as NaN internally and be serialized to `null`. +During deserialization (from JSON text or any of the binary formats), a finite number that does not fit into +`number_float_t` is rejected with [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406), for +example a double-precision number in a binary format when `number_float_t` is `#!cpp float`. + ### Storage Floating-point number values are stored directly inside a `basic_json` type. diff --git a/docs/mkdocs/docs/api/basic_json/number_integer_t.md b/docs/mkdocs/docs/api/basic_json/number_integer_t.md index d77c6a24d..48d2873ed 100644 --- a/docs/mkdocs/docs/api/basic_json/number_integer_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_integer_t.md @@ -47,8 +47,9 @@ With the default values for `NumberIntegerType` (`std::int64_t`), the default va When the default type is used, the maximal integer number that can be stored is `9223372036854775807` (INT64_MAX) and the minimal integer number that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of -range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers -will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [`number_float_t`](number_float_t.md). +range will yield over/underflow when used in a constructor. During deserialization (from JSON text or any of the binary +formats), too large or small integer numbers will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) +or [`number_float_t`](number_float_t.md). [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are in the range [-253+1, 253-1] are diff --git a/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md b/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md index 774fda638..81cc00f77 100644 --- a/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md @@ -48,8 +48,9 @@ With the default values for `NumberUnsignedType` (`std::uint64_t`), the default When the default type is used, the maximal integer number that can be stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number that can be stored is `0`. Integer numbers that are out of range will yield over/underflow -when used in a constructor. During deserialization, too large or small integer numbers will automatically be stored -as [`number_integer_t`](number_integer_t.md) or [`number_float_t`](number_float_t.md). +when used in a constructor. During deserialization (from JSON text or any of the binary formats), too large or small +integer numbers will automatically be stored as [`number_integer_t`](number_integer_t.md) or +[`number_float_t`](number_float_t.md). [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are in the range [-253+1, 253-1] are diff --git a/docs/mkdocs/docs/api/basic_json/sax_parse.md b/docs/mkdocs/docs/api/basic_json/sax_parse.md index 0d4b8da8a..fc48c9e12 100644 --- a/docs/mkdocs/docs/api/basic_json/sax_parse.md +++ b/docs/mkdocs/docs/api/basic_json/sax_parse.md @@ -8,7 +8,8 @@ static bool sax_parse(InputType&& i, input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false); + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error); // (2) template @@ -17,13 +18,14 @@ static bool sax_parse(IteratorType first, SentinelType last, input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false); + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error); ``` Read from input and generate SAX events 1. Read from a compatible input. -2. Read from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support) +2. Read from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support). The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to @@ -82,6 +84,10 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index : whether trailing commas in arrays or objects should be ignored and treated like whitespace (`#!cpp true`) or yield a parse error (`#!cpp false`); (optional, `#!cpp false` by default) +`tag_handler` (in) +: how to handle CBOR tags; see [`cbor_tag_handler_t`](cbor_tag_handler_t.md). Ignored for formats other than CBOR + (optional, `cbor_tag_handler_t::error` by default). + `first` (in) : iterator to the start of a character range @@ -137,6 +143,7 @@ A UTF-8 byte order mark is silently ignored. - Added in version 3.2.0. - Ignoring comments via `ignore_comments` added in version 3.9.0. - Added `ignore_trailing_commas` in version 3.13.0. +- Added `tag_handler` in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0. - `JSON_PRECISE_STREAM_POSITION` added in version 3.13.0 to optionally leave a `#!cpp std::istream` positioned right diff --git a/docs/mkdocs/docs/api/basic_json/std_hash.md b/docs/mkdocs/docs/api/basic_json/std_hash.md index aaa49ed68..7be7772cc 100644 --- a/docs/mkdocs/docs/api/basic_json/std_hash.md +++ b/docs/mkdocs/docs/api/basic_json/std_hash.md @@ -7,8 +7,14 @@ namespace std { ``` Return a hash value for a JSON object. The hash function tries to rely on `std::hash` where possible. Furthermore, the -type of the JSON value is taken into account to have different hash values for `#!json null`, `#!cpp 0`, `#!cpp 0U`, and -`#!cpp false`, etc. +type of the JSON value is taken into account, so `#!json null`, `#!cpp false`, and numbers may hash differently from +each other. Numbers that compare equal under [`operator==`](operator_eq.md) always hash equally, regardless of +whether they are stored as signed integer, unsigned integer, or floating-point number. + +Numbers are hashed by their value converted to `number_float_t`. Converting an integer to `number_float_t` therefore +keeps its hash, but converting a floating-point number to an integer type is lossy and can change it: `#!cpp 0.5` +converts to `#!cpp 0`, which need not have the same hash. Unequal numbers can also share a hash value, for example two +large integers that convert to the same `number_float_t`. ## Examples @@ -26,7 +32,8 @@ type of the JSON value is taken into account to have different hash values for ` --8<-- "examples/std_hash.output" ``` - Note the output is platform-dependent. + The hash values shown are examples only. They depend on the platform, the compiler, and the compiler version, and + they can change between versions of this library. Do not persist them or rely on specific values. ## See also @@ -36,3 +43,5 @@ type of the JSON value is taken into account to have different hash values for ` - Added in version 1.0.0. - Extended for arbitrary basic_json types in version 3.10.5. +- Numbers that compare equal hash equally since version 3.13.0; before, `#!cpp 0`, `#!cpp 0U`, and `#!cpp 0.0` had + different hash values. diff --git a/docs/mkdocs/docs/api/basic_json/to_bjdata.md b/docs/mkdocs/docs/api/basic_json/to_bjdata.md index df3b69004..583139068 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bjdata.md +++ b/docs/mkdocs/docs/api/basic_json/to_bjdata.md @@ -68,6 +68,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va - Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is not valid UTF-8 and `error_handler` is `strict` (the default only if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) +- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if `j` or a value nested in it is + discarded; example: `"cannot serialize discarded value to BJData"` ## Complexity @@ -119,4 +121,6 @@ Linear in the size of the JSON value `j`. - BJData version parameter (for draft3 binary encoding) added in version 3.12.0. - Added `error_handler` parameter in version 3.13.0. Its default, `keep`, writes the bytes of a string or object key that is not valid UTF-8 unchanged, as before; `strict` (the default if - [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`. \ No newline at end of file + [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`. +- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an + array or object was silently skipped, producing invalid BJData. \ No newline at end of file diff --git a/docs/mkdocs/docs/api/basic_json/to_bson.md b/docs/mkdocs/docs/api/basic_json/to_bson.md index ad974e048..05f8b8548 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bson.md +++ b/docs/mkdocs/docs/api/basic_json/to_bson.md @@ -58,6 +58,9 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va - Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key is not valid UTF-8 and `error_handler` is `strict` (the default only if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) +- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if a value nested in `j` is discarded + (the top-level value itself is covered by `type_error.317` above, since it must be an object); example: + `"cannot serialize discarded value to BSON"` ## Complexity @@ -110,6 +113,8 @@ pass before anything is written. - Throws `out_of_range.412` and `out_of_range.415` since version 3.13.0. - Linear in the size of `j`, and no longer limited by the call stack for deeply nested values, since version 3.13.0. - `out_of_range.415` is now detected before anything is written, like the other exceptions above, since version 3.13.0. +- Throws `type_error.321` for a discarded value nested in `j` since version 3.13.0; previously, it was silently + skipped, producing a document whose declared size did not match what was actually written. - Added `error_handler` parameter in version 3.13.0. Its default, `keep`, writes the bytes of a string or object key that is not valid UTF-8 unchanged, as before; `strict` (the default if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316` before anything diff --git a/docs/mkdocs/docs/api/basic_json/to_cbor.md b/docs/mkdocs/docs/api/basic_json/to_cbor.md index c72f310bb..f5b6a07bb 100644 --- a/docs/mkdocs/docs/api/basic_json/to_cbor.md +++ b/docs/mkdocs/docs/api/basic_json/to_cbor.md @@ -49,6 +49,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va - Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is not valid UTF-8 and `error_handler` is `strict` (the default only if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) +- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if `j` or a value nested in it is + discarded; example: `"cannot serialize discarded value to CBOR"` ## Complexity @@ -86,3 +88,5 @@ Linear in the size of the JSON value `j`. - Added `error_handler` parameter in version 3.13.0. Its default, `keep`, writes the bytes of a string or object key that is not valid UTF-8 unchanged, as before; `strict` (the default if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`. +- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an + array or object was silently skipped, producing invalid CBOR. diff --git a/docs/mkdocs/docs/api/basic_json/to_msgpack.md b/docs/mkdocs/docs/api/basic_json/to_msgpack.md index 17b9fe29c..2e32208bf 100644 --- a/docs/mkdocs/docs/api/basic_json/to_msgpack.md +++ b/docs/mkdocs/docs/api/basic_json/to_msgpack.md @@ -54,6 +54,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va `"subtype 70000 is too large for the MessagePack ext type (max 255)"` - Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is not valid UTF-8 and `error_handler` is `strict` +- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if `j` or a value nested in it is + discarded; example: `"cannot serialize discarded value to MessagePack"` ## Complexity @@ -108,3 +110,5 @@ Linear in the size of the JSON value `j`. - Fixed in version 3.13.0 to serialize `number_integer_t`/`number_unsigned_t` pairs of different width correctly; before, integers could be serialized with the wrong value if `number_integer_t` was narrower than `number_unsigned_t`. +- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an + array or object was silently skipped, producing invalid MessagePack. diff --git a/docs/mkdocs/docs/api/basic_json/to_ubjson.md b/docs/mkdocs/docs/api/basic_json/to_ubjson.md index 6860c01c6..6aad86683 100644 --- a/docs/mkdocs/docs/api/basic_json/to_ubjson.md +++ b/docs/mkdocs/docs/api/basic_json/to_ubjson.md @@ -61,6 +61,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va - Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is not valid UTF-8 and `error_handler` is `strict` (the default only if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) +- Throws [type_error.321](../../home/exceptions.md#jsonexceptiontype_error321) if `j` or a value nested in it is + discarded; example: `"cannot serialize discarded value to UBJSON"` ## Complexity @@ -112,3 +114,5 @@ Linear in the size of the JSON value `j`. - Added `error_handler` parameter in version 3.13.0. Its default, `keep`, writes the bytes of a string or object key that is not valid UTF-8 unchanged, as before; `strict` (the default if [`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled) throws `type_error.316`. +- Throws `type_error.321` for a discarded value since version 3.13.0; previously, a discarded value nested in an + array or object was silently skipped, producing invalid UBJSON. diff --git a/docs/mkdocs/docs/api/basic_json/with_t.md b/docs/mkdocs/docs/api/basic_json/with_t.md new file mode 100644 index 000000000..2e8fee663 --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json/with_t.md @@ -0,0 +1,136 @@ +# nlohmann::basic_json::with_t + +Member alias templates `with_object_t`, `with_array_t`, `with_string_t`, `with_boolean_t`, `with_integers_t`, +`with_float_t`, `with_allocator_t`, `with_json_serializer_t`, `with_binary_t`, and `with_base_class_t`. + +```cpp +template class ObjectType2> +using with_object_t = basic_json; + +template class ArrayType2> +using with_array_t = basic_json; + +template +using with_string_t = basic_json; + +template +using with_boolean_t = basic_json; + +template +using with_integers_t = basic_json; + +template +using with_float_t = basic_json; + +template class AllocatorType2> +using with_allocator_t = basic_json; + +template class JSONSerializer2> +using with_json_serializer_t = basic_json; + +template +using with_binary_t = basic_json; + +template +using with_base_class_t = basic_json; +``` + +These member alias templates make it easier to create a `basic_json` type that is identical to the current type except +for one (or, in the case of `with_integers_t`, two) of its [template parameters](index.md#template-parameters). +Spelling out all 11 template parameters of `basic_json` just to change a single one is verbose and error-prone; these +aliases only require the replacement type(s). + +with_object_t<ObjectType2> +: replaces `ObjectType` + +with_array_t<ArrayType2> +: replaces `ArrayType` + +with_string_t<StringType2> +: replaces `StringType` + +with_boolean_t<BooleanType2> +: replaces `BooleanType` + +with_integers_t<NumberIntegerType2, NumberUnsignedType2> +: replaces both `NumberIntegerType` and `NumberUnsignedType`; the two are combined into a single alias because they + are usually changed together (for instance, when switching to fixed-width integer types) + +with_float_t<NumberFloatType2> +: replaces `NumberFloatType` + +with_allocator_t<AllocatorType2> +: replaces `AllocatorType` + +with_json_serializer_t<JSONSerializer2> +: replaces `JSONSerializer` + +with_binary_t<BinaryType2> +: replaces `BinaryType` + +with_base_class_t<CustomBaseClass2> +: replaces `CustomBaseClass`; see also [`json_base_class_t`](json_base_class_t.md) + +## Notes + +All other template parameters are kept unchanged, so the resulting type still uses, for instance, the same +`ObjectType` unless `with_object_t` itself is used. + +The aliases are members of every `basic_json` specialization, including [`ordered_json`](../ordered_json.md), and the +type they produce is again a `basic_json` specialization. They can therefore be chained to replace several template +parameters at once: + +```cpp +using my_json = nlohmann::json::with_integers_t::with_float_t; +using my_ordered_json = nlohmann::ordered_json::with_string_t; +``` + +The result is the same type as spelling out all template parameters, so the order of the chained aliases does not +matter. For instance, `nlohmann::json::with_object_t` is `nlohmann::ordered_json`. + +## Examples + +??? example + + The following code shows how `with_object_t` can be used to create a JSON type that stores object elements in a + `std::map` and therefore keeps them sorted by key, unlike the default type which preserves insertion order + only when `nlohmann::ordered_json` is used. + + ```cpp + --8<-- "examples/with_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/with_t.output" + ``` + +## See also + +- [basic_json](index.md#template-parameters) - the template parameters that can be replaced +- [json_base_class_t](json_base_class_t.md) - the type used for `CustomBaseClass` + +## Version history + +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index 872d6cb8c..eb2807b69 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -58,6 +58,13 @@ header. See also the [macro overview page](../../features/macros.md). - [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums - [**JSON_DISABLE_TUPLE_REFERENCE_CONVERSION**](json_disable_tuple_reference_conversion.md) - switch off conversion from a one-element tuple of a JSON reference - [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions +- [**JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS**](json_use_objects_for_enum_keyed_maps.md) - opt in to storing maps with enum + keys as objects + +## Deprecated functions + +- [**JSON_DELETE_DEPRECATED_FUNCTIONS**](json_delete_deprecated_functions.md) - opt in to deleting the deprecated + functions ahead of their removal in version 4.0.0 ## Comparison behavior diff --git a/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md b/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md index 71b8bb28f..a038f8435 100644 --- a/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md +++ b/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md @@ -50,9 +50,11 @@ The default value is `0` (disabled — existing behavior is preserved). ``` Code that relies on these producing arrays must use `json::array()` instead (see below). Lists with more than one - element, and a single `[string, value]` pair such as `{{"key", "value"}}`, which still creates an object, are not - affected. The library's own conversions are not affected either: for example, `std::tuple{5}` still becomes - `[5]`. + element, and a single `[string, value]` pair *written as a braced list*, such as `{{"key", "value"}}`, which still + creates an object, are not affected. This exception is based on how the pair is written, not on the shape of its + value: an existing JSON value that happens to be a two-element array with a string as its first element, such as + `json arr = {"key", 42};`, is still copied by `json j{arr};` rather than turned into an object. The library's own + conversions are not affected either: for example, `std::tuple{5}` still becomes `[5]`. !!! note "ABI compatibility" diff --git a/docs/mkdocs/docs/api/macros/json_delete_deprecated_functions.md b/docs/mkdocs/docs/api/macros/json_delete_deprecated_functions.md new file mode 100644 index 000000000..20f0ead0c --- /dev/null +++ b/docs/mkdocs/docs/api/macros/json_delete_deprecated_functions.md @@ -0,0 +1,96 @@ +# JSON_DELETE_DEPRECATED_FUNCTIONS + +```cpp +#define JSON_DELETE_DEPRECATED_FUNCTIONS /* value */ +``` + +When defined to `1`, all [deprecated functions](../../community/roadmap.md#removal-of-deprecated-functions) of the +library are declared as deleted (`= delete`) instead of only being marked as deprecated. Code that still calls one of +them no longer compiles. This way, you can find all calls that need to be replaced before version 4.0.0 removes these +functions; the [migration guide](../../integration/migration_guide.md#replace-deprecated-functions) describes how. + +A deleted function, unlike a removed one, still takes part in overload resolution. A call that would select it +therefore fails to compile instead of silently selecting another overload. This matters for the deprecated +`from_*(ptr, len)` overloads of [`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md), +[`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md), +[`from_bon8`](../basic_json/from_bon8.md), and [`from_bson`](../basic_json/from_bson.md): without them, a call like +`from_cbor(ptr, len)` would compile, read `ptr` as a NUL-terminated string, and convert `len` to the `strict` parameter. + +The macro does not affect the deprecated legacy comparison of discarded values, which is controlled by +[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](json_use_legacy_discarded_value_comparison.md). + +## Default definition + +The default value is `0` (disabled, the deprecated functions can still be called, and the compiler warns about it). + +```cpp +#define JSON_DELETE_DEPRECATED_FUNCTIONS 0 +``` + +## Notes + +!!! info "CMake option" + + The macro can also be set with the CMake option + [`JSON_DeleteDeprecatedFunctions`](../../integration/cmake.md#json_deletedeprecatedfunctions) (`OFF` by default). + +!!! warning "Opt-in only" + + This macro must be defined **before** including ``. Defining it after the include has no + effect. Define it for the whole project to avoid different declarations of the same class in different + translation units. + +!!! note "ABI compatibility" + + The macro only turns calls that compile into calls that do not; it does not change the layout or the behavior of + any type. Its value is therefore not encoded in the [namespace](../../features/namespace.md). + +## Examples + +??? example "Example: default behavior (macro not defined)" + + Without the macro, the deprecated overload is called, and the compiler warns about it: + + ```cpp + #include + + using json = nlohmann::json; + + int main() + { + const std::vector v = {0x82, 0x01, 0x02}; + auto j = json::from_cbor(v.data(), v.size()); + // warning: 'from_cbor' is deprecated: Since 3.8.0; use from_cbor(ptr, ptr + len) + } + ``` + +??? example "Example: deleted deprecated functions (macro defined to 1)" + + With the macro, the call does not compile: + + ```cpp + #define JSON_DELETE_DEPRECATED_FUNCTIONS 1 + #include + + using json = nlohmann::json; + + int main() + { + const std::vector v = {0x82, 0x01, 0x02}; + auto j = json::from_cbor(v.data(), v.size()); + // error: call to deleted function 'from_cbor' + } + ``` + +## See also + +- [Roadmap: removal of deprecated functions](../../community/roadmap.md#removal-of-deprecated-functions) - the + deprecated functions and the version they were deprecated in +- [Migration guide: replace deprecated functions](../../integration/migration_guide.md#replace-deprecated-functions) - + how to replace each deprecated function + +## Version history + +- Added in version 3.13.0. +- Planned to be removed in version 4.0.0, which removes the deprecated functions. The deprecated `from_*(ptr, len)` + overloads stay deleted in version 4.0.0. diff --git a/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md b/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md index c69240726..0a2216b57 100644 --- a/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md +++ b/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md @@ -112,3 +112,4 @@ The default value is `0` (disabled — existing behavior is preserved). ## Version history - Added in version 3.13.0. +- Planned to become the default (with the macro removed) in version 4.0.0. diff --git a/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md b/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md index 113344412..675a8acee 100644 --- a/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md +++ b/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md @@ -44,7 +44,7 @@ By default, implicit conversions are enabled. ## Examples -??? example "Example: implicit conversion" +??? example "Example: implicit and explicit conversions" This is an example for an implicit conversion: diff --git a/docs/mkdocs/docs/api/macros/json_use_objects_for_enum_keyed_maps.md b/docs/mkdocs/docs/api/macros/json_use_objects_for_enum_keyed_maps.md new file mode 100644 index 000000000..ca4139c48 --- /dev/null +++ b/docs/mkdocs/docs/api/macros/json_use_objects_for_enum_keyed_maps.md @@ -0,0 +1,139 @@ +# JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + +```cpp +#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS /* value */ +``` + +When defined to `1`, maps whose keys are enums (such as `std::map` or `std::unordered_map`) are stored as +JSON objects, using the enum's own conversion for the keys. By default, they are stored as arrays of `[key, value]` +pairs. + +## Default definition + +The default value is `0` (disabled — existing behavior is preserved). + +```cpp +#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0 +``` + +## Notes + +!!! note "Background" + + JSON object keys are strings, so a map is only stored as an object if its keys can be converted to a string type. + Enums are not, even if [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) maps them to strings, so a + map with enum keys becomes an array of `[key, value]` pairs: + + ```json + [["stopped", "aa"], ["completed", "bb"]] + ``` + + With this macro, the same map becomes an object + (see [#4378](https://github.com/nlohmann/json/issues/4378)): + + ```json + {"completed": "bb", "stopped": "aa"} + ``` + +!!! note "Maps with non-unique keys" + + Maps that allow duplicate keys, such as `std::multimap` or `std::unordered_multimap`, are not affected + by the macro and are still stored as arrays of `[key, value]` pairs, as an object cannot hold duplicate keys. + +!!! note "Reading" + + Reading is not affected by the macro: a map with enum keys can always be read from both an array of pairs and an + object. For the latter, each key is converted to the enum with its `from_json` function, e.g., the one defined by + [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md). Data written without the macro can therefore + still be read after enabling it. + +!!! warning "Keys must serialize to distinct strings" + + Each key is converted with the enum's `to_json` function. If a key is not converted to a string (for instance, an + enum without [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md), which is stored as an integer, or an + enumerator mapped to `nullptr`), [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) is thrown. + If two keys are converted to the same string (for instance, because + [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) maps an unlisted enumerator to the first entry), + [`type_error.318`](../../home/exceptions.md#jsonexceptiontype_error318) is thrown. In both cases, the target value + is not changed. + +!!! warning "Opt-in only" + + This macro must be defined **before** including ``. Defining it after the include has no effect. + +!!! note "ABI compatibility" + + The value of this macro is encoded in the [namespace](../../features/namespace.md) (tag `_ekmo`), resulting in + distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program + without One Definition Rule (ODR) violations, but they cannot exchange instances of library types. + +## Examples + +??? example "Example: default behavior (macro not defined)" + + Without the macro, a map with enum keys is stored as an array of pairs: + + ```cpp + #include + #include + + using json = nlohmann::json; + + enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED }; + + NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, { + {TS_STOPPED, "stopped"}, + {TS_RUNNING, "running"}, + {TS_COMPLETED, "completed"}, + }) + + int main() + { + std::map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}}; + + json j = m; + // j is [["stopped","aa"],["completed","bb"]] + } + ``` + +??? example "Example: objects for enum-keyed maps (macro defined to 1)" + + With the macro, the same map is stored as an object: + + ```cpp + #define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 1 + #include + #include + + using json = nlohmann::json; + + enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED }; + + NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, { + {TS_STOPPED, "stopped"}, + {TS_RUNNING, "running"}, + {TS_COMPLETED, "completed"}, + }) + + int main() + { + std::map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}}; + + json j = m; + // j is {"completed":"bb","stopped":"aa"} + + auto m2 = j.get>(); + // m2 == m + } + ``` + +## See also + +- [Specializing enum conversion](../../features/enum_conversion.md) +- [**NLOHMANN_JSON_SERIALIZE_ENUM**](nlohmann_json_serialize_enum.md) - serialize/deserialize an enum +- [**NLOHMANN_JSON_SERIALIZE_ENUM_STRICT**](nlohmann_json_serialize_enum_strict.md) - serialize/deserialize an enum with + exceptions + +## Version history + +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md index 626055fdf..4af3b07b8 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md @@ -41,6 +41,9 @@ inline void from_json(const BasicJsonType& j, type& e); conversion. Select this default pair carefully. See example 1 below. - If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the list will be returned when converting to or from JSON. See example 2 below. + - Maps with enum keys (e.g., `std::map`) are stored as arrays of `[key, value]` pairs by default. + Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects + with the converted keys. Such maps can be read from both forms. ## Examples @@ -80,6 +83,7 @@ inline void from_json(const BasicJsonType& j, type& e); - [Specializing enum conversion](../../features/enum_conversion.md) - [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](./nlohmann_json_serialize_enum_strict.md) - [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md) +- [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) ## Version history diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md index 4697c5a95..f5806a490 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md @@ -44,6 +44,9 @@ inline void from_json(const BasicJsonType& j, type& e); `"enum value out of range for "`. - If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the list will be returned when converting to or from JSON. See example 2 below. + - Maps with enum keys (e.g., `std::map`) are stored as arrays of `[key, value]` pairs by default. + Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects + with the converted keys. Such maps can be read from both forms. ## Examples @@ -99,6 +102,7 @@ inline void from_json(const BasicJsonType& j, type& e); - [Specializing enum conversion](../../features/enum_conversion.md) - [`NLOHMANN_JSON_SERIALIZE_ENUM`](./nlohmann_json_serialize_enum.md) - [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md) +- [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) ## Version history diff --git a/docs/mkdocs/docs/community/quality_assurance.md b/docs/mkdocs/docs/community/quality_assurance.md index d44135bf2..bd8f55790 100644 --- a/docs/mkdocs/docs/community/quality_assurance.md +++ b/docs/mkdocs/docs/community/quality_assurance.md @@ -21,17 +21,18 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa | Compiler | Architecture | Operating System | CI | |----------------------------------------------|--------------|-----------------------------------|-----------| - | AppleClang 15.0.0.15000040; Xcode 15.0.1 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | - | AppleClang 15.0.0.15000100; Xcode 15.1 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | - | AppleClang 15.0.0.15000100; Xcode 15.2 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | - | AppleClang 15.0.0.15000309; Xcode 15.3 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | - | AppleClang 15.0.0.15000309; Xcode 15.4 | arm64 | macOS 14.7.2 (Sonoma) | GitHub | | AppleClang 16.0.0.16000026; Xcode 16 | arm64 | macOS 15.2 (Sequoia) | GitHub | | AppleClang 16.0.0.16000026; Xcode 16.1 | arm64 | macOS 15.2 (Sequoia) | GitHub | | AppleClang 16.0.0.16000026; Xcode 16.2 | arm64 | macOS 15.2 (Sequoia) | GitHub | | AppleClang 17.0.0.17000013; Xcode 16.3 | arm64 | macOS 15.5 (Sequoia) | GitHub | | AppleClang 17.0.0.17000013; Xcode 16.4 | arm64 | macOS 15.5 (Sequoia) | GitHub | | AppleClang 17.0.0.17000319; Xcode 26.0.1 | arm64 | macOS 15.5 (Sequoia) | GitHub | + | AppleClang 17.0.0.17000404; Xcode 26.1.1 | arm64 | macOS 15.7.9 (Sequoia) | GitHub | + | AppleClang 17.0.0.17000603; Xcode 26.2 | arm64 | macOS 15.7.9 (Sequoia) | GitHub | + | AppleClang 17.0.0.17000604; Xcode 26.3 | arm64 | macOS 15.7.9 (Sequoia) | GitHub | + | AppleClang 21.0.0.21000099; Xcode 26.4.1 | arm64 | macOS 26.6.2 (Tahoe) | GitHub | + | AppleClang 21.0.0.21000101; Xcode 26.5 | arm64 | macOS 26.6.2 (Tahoe) | GitHub | + | AppleClang 21.0.0.21000101; Xcode 26.6 | arm64 | macOS 26.6.2 (Tahoe) | GitHub | | Clang 3.4.2 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 3.5.2 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 3.6.2 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | @@ -89,7 +90,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa | GNU 13.3.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 14.2.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 15.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | - | GNU 16.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | GNU 16.2.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 16.1.0 | arm64 | Ubuntu 24.04 | GitHub | | icpc (ICC) 2021.10.0 20230609 | x86_64 | Ubuntu 22.04 LTS | GitHub | | icpx (Intel oneAPI DPC++/C++) 2025.3.2 | x86_64 | Ubuntu 24.04 LTS | GitHub | diff --git a/docs/mkdocs/docs/community/roadmap.md b/docs/mkdocs/docs/community/roadmap.md index 48977b295..27afeb4c5 100644 --- a/docs/mkdocs/docs/community/roadmap.md +++ b/docs/mkdocs/docs/community/roadmap.md @@ -25,9 +25,7 @@ work items are tracked in the [GitHub milestones](https://github.com/nlohmann/js ## What the project will not do -- **Break the public API of version 3.x.** See the - [contribution guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#break-the-public-api) - for what counts as a breaking change. +- **Break the public API of version 3.x.** See [API stability](#api-stability) for what this covers. - **Require a newer C++ standard than C++11.** - **Break JSON conformance** or enable non-standard extensions by default. - **Add dependencies** or require a build step. The library remains header-only, and the single header @@ -35,6 +33,32 @@ work items are tracked in the [GitHub milestones](https://github.com/nlohmann/js - **Trade simplicity for speed or memory efficiency.** Performance improvements are welcome, but the library is not meant to compete with the fastest JSON libraries, see [Design goals](../home/design_goals.md). +## API stability + +Releases follow [semantic versioning](https://semver.org): a minor or patch release of version 3.x does not break code +that uses the public API. In particular, a 3.x release does not: + +- change the signature of a function (its parameter types, return type, number of parameters, or the const-ness of a + member function); +- remove or rename a function or class; +- change which exceptions a function throws, or the [exception ids](../home/exceptions.md); +- change access specifiers or default arguments. + +Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are +documented in the [release notes](../home/releases.md). + +The following are **not** part of the public API and may change in any release, including patch releases: + +- The text of exception messages returned by `what()`. Use the [exception id](../home/exceptions.md) to tell errors + apart. +- The ABI, including `sizeof(basic_json)` and the memory layout of its values. Recompile your code when you upgrade the + library. The [versioned inline namespace](../features/namespace.md) turns mixing versions into a link error. +- Everything in namespace `nlohmann::detail`, and macros and type traits that are not documented in the + [API reference](../api/basic_json/index.md). + +Changes that would break the public API are only added behind a macro whose default keeps the 3.x behavior, see +[Version 4.0](#version-40). + ## Version 4.0 There is no release date for version 4.0 yet. Proposals that need a major version, for instance stricter type @@ -64,6 +88,8 @@ The following macros guard changes that are planned to become the default in ver | [`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md) | `0` | `1`: reading from a stream does not consume the character after a number | – | 3.13.0 | | [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) | `0` | `1`: a NUL byte in the input is a parse error instead of the end of input | [`JSON_StrictNulHandling`](../integration/cmake.md#json_strictnulhandling) | 3.13.0 | | [`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) | `0` | `1`: `to_cbor`, `to_ubjson`, `to_bjdata`, and `to_bson` throw for strings that are not valid UTF-8 by default | [`JSON_StrictBinaryUTF8`](../integration/cmake.md#json_strictbinaryutf8) | 3.13.0 | +| [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md) | `0` | `1`: a `basic_json` value can no longer be created from a one-element tuple of a reference to it, such as `std::forward_as_tuple(j)`| [`JSON_DisableTupleReferenceConversion`](../integration/cmake.md#json_disabletuplereferenceconversion) | 3.13.0 | +| [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) | `0` | removed: the deprecated functions are removed (see below); the `from_*(ptr, len)` overloads stay deleted | [`JSON_DeleteDeprecatedFunctions`](../integration/cmake.md#json_deletedeprecatedfunctions) | 3.13.0 | For example, the following makes a 3.x release behave like version 4.0 with respect to these changes: @@ -75,6 +101,8 @@ For example, the following makes a 3.x release behave like version 4.0 with resp #define JSON_PRECISE_STREAM_POSITION 1 #define JSON_STRICT_NUL_HANDLING 1 #define JSON_STRICT_BINARY_UTF8 1 +#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1 +#define JSON_DELETE_DEPRECATED_FUNCTIONS 1 #include ``` @@ -84,8 +112,13 @@ way to achieve this. ### Removal of deprecated functions Version 4.0 will remove all deprecated functions. Compiling with deprecation warnings enabled shows which of them your -code still uses. The [migration guide](../integration/migration_guide.md#replace-deprecated-functions) shows how to -replace each of them. +code still uses. Defining [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) to +`1` turns these warnings into errors, as the deprecated functions are then deleted. The +[migration guide](../integration/migration_guide.md#replace-deprecated-functions) shows how to replace each of them. + +The `from_*` overloads taking a pointer and a length are not removed in version 4.0, but stay deleted. Without them, a +call like `from_cbor(ptr, len)` would still compile: it would read `ptr` as a NUL-terminated string and convert `len` +to the `strict` parameter. | Deprecated | Since | Migration | |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|----------------------------------------------------------------------------------| @@ -97,6 +130,7 @@ replace each of them. | [`json_pointer::operator string_t`](../api/json_pointer/operator_string_t.md) | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) | | [`json_pointer`](../api/json_pointer/index.md) with a `basic_json` type as template argument, and the overloads of `value`, `contains`, `operator[]`, and `at` accepting such a pointer | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) | | Comparing a [`json_pointer`](../api/json_pointer/index.md) with a string via [`operator==`](../api/json_pointer/operator_eq.md) or [`operator!=`](../api/json_pointer/operator_ne.md) | 3.11.2 | [JSON Pointers](../integration/migration_guide.md#json-pointers) | +| [`from_bjdata`](../api/basic_json/from_bjdata.md) and [`from_bon8`](../api/basic_json/from_bon8.md) with `(ptr, len)` | 3.13.0 | [Parsing](../integration/migration_guide.md#parsing) | The deprecated legacy comparison of discarded values is controlled by a macro and therefore listed in the table above. diff --git a/docs/mkdocs/docs/examples/json_base_class_t.cpp b/docs/mkdocs/docs/examples/json_base_class_t.cpp index 3fb2d46a2..1dafd417f 100644 --- a/docs/mkdocs/docs/examples/json_base_class_t.cpp +++ b/docs/mkdocs/docs/examples/json_base_class_t.cpp @@ -13,19 +13,7 @@ class visitor_adaptor_with_metadata void do_visit(const Ptr& ptr, const Fnc& fnc) const; }; -using json = nlohmann::basic_json < - std::map, - std::vector, - std::string, - bool, - std::int64_t, - std::uint64_t, - double, - std::allocator, - nlohmann::adl_serializer, - std::vector, - visitor_adaptor_with_metadata - >; +using json = nlohmann::json::with_base_class_t; template void visitor_adaptor_with_metadata::visit(const Fnc& fnc) const diff --git a/docs/mkdocs/docs/examples/std_hash.cpp b/docs/mkdocs/docs/examples/std_hash.cpp index 9721910eb..184ddbbb3 100644 --- a/docs/mkdocs/docs/examples/std_hash.cpp +++ b/docs/mkdocs/docs/examples/std_hash.cpp @@ -11,6 +11,7 @@ int main() << "hash(false) = " << std::hash {}(json(false)) << '\n' << "hash(0) = " << std::hash {}(json(0)) << '\n' << "hash(0U) = " << std::hash {}(json(0U)) << '\n' + << "hash(0.0) = " << std::hash {}(json(0.0)) << '\n' << "hash(\"\") = " << std::hash {}(json("")) << '\n' << "hash({}) = " << std::hash {}(json::object()) << '\n' << "hash([]) = " << std::hash {}(json::array()) << '\n' diff --git a/docs/mkdocs/docs/examples/std_hash.output b/docs/mkdocs/docs/examples/std_hash.output index 521d2b4b8..ca3207c0a 100644 --- a/docs/mkdocs/docs/examples/std_hash.output +++ b/docs/mkdocs/docs/examples/std_hash.output @@ -1,8 +1,9 @@ hash(null) = 2654435769 hash(false) = 2654436030 -hash(0) = 2654436095 -hash(0U) = 2654436156 -hash("") = 6142509191626859748 +hash(0) = 2654436221 +hash(0U) = 2654436221 +hash(0.0) = 2654436221 +hash("") = 11160318156688833227 hash({}) = 2654435832 hash([]) = 2654435899 -hash({"hello": "world"}) = 4469488738203676328 +hash({"hello": "world"}) = 3701319991624763853 diff --git a/docs/mkdocs/docs/examples/with_t.cpp b/docs/mkdocs/docs/examples/with_t.cpp new file mode 100644 index 000000000..665efde3e --- /dev/null +++ b/docs/mkdocs/docs/examples/with_t.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +// a JSON type that stores objects in a std::map (which keeps keys sorted) +// instead of the default ordered associative container +using sorted_json = nlohmann::json::with_object_t; + +int main() +{ + sorted_json j; + j["c"] = 1; + j["a"] = 2; + j["b"] = 3; + + // keys are sorted, because std::map is used to store the object + std::cout << j.dump() << std::endl; +} diff --git a/docs/mkdocs/docs/examples/with_t.output b/docs/mkdocs/docs/examples/with_t.output new file mode 100644 index 000000000..0886cda01 --- /dev/null +++ b/docs/mkdocs/docs/examples/with_t.output @@ -0,0 +1 @@ +{"a":2,"b":3,"c":1} diff --git a/docs/mkdocs/docs/features/binary_formats/bjdata.md b/docs/mkdocs/docs/features/binary_formats/bjdata.md index 3e3d8e885..12ef19d59 100644 --- a/docs/mkdocs/docs/features/binary_formats/bjdata.md +++ b/docs/mkdocs/docs/features/binary_formats/bjdata.md @@ -141,8 +141,14 @@ The library uses the following mapping from JSON values types to BJData types ac parsed back as a regular array, - every entry of `"_ArraySize_"` is a positive integer, and their product is representable as a `std::size_t`, - `"_ArrayData_"` is an array holding exactly that many elements, and - - every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"` (a floating-point number for - `single` and `double`, an integer otherwise). + - every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"`: for the integer types, a + value that fits the named width; for `double`, any value; for `single`, a value that survives narrowing to + `float` and back without change (for instance, `0.1` does not, since it is not exactly representable as + `float`). + + An annotated object is always read back with its keys in the order shown above, `"_ArrayType_"`, `"_ArraySize_"`, + `"_ArrayData_"`, regardless of the order the ND-array's header stores them in on the wire. This matters for + `ordered_json`, whose comparison takes key order into account. The current version of this library does not yet support automatic detection of and conversion from a nested JSON array input to a BJData ND-array. diff --git a/docs/mkdocs/docs/features/binary_formats/cbor.md b/docs/mkdocs/docs/features/binary_formats/cbor.md index 7b5be4631..a0a0ed8d0 100644 --- a/docs/mkdocs/docs/features/binary_formats/cbor.md +++ b/docs/mkdocs/docs/features/binary_formats/cbor.md @@ -131,6 +131,7 @@ The library maps CBOR types to JSON value types as follows: | Byte string | binary | 0x59 | | Byte string | binary | 0x5A | | Byte string | binary | 0x5B | +| Byte string | binary | 0x5F | | UTF-8 string | string | 0x60..0x77 | | UTF-8 string | string | 0x78 | | UTF-8 string | string | 0x79 | @@ -156,6 +157,9 @@ The library maps CBOR types to JSON value types as follows: | Single-Precision Float | number_float | 0xFA | | Double-Precision Float | number_float | 0xFB | +Indefinite-length UTF-8 strings (0x7F) and byte strings (0x5F) are supported. Each chunk must be a definite-length +string of the same major type, as required by [RFC 8949, Section 3.2.3](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.3). + !!! warning "Incomplete mapping" The mapping is **incomplete** in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors: @@ -168,9 +172,9 @@ The library maps CBOR types to JSON value types as follows: !!! warning "Negative integer overflow" CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the - result to fit into `number_integer_t` (`std::int64_t` by default), parsing fails with a - [`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) exception rather than overflowing - silently. + result to fit into `number_integer_t` (`std::int64_t` by default), the result is stored as `number_float_t`, like + a too small integer in JSON text. For example, `-18446744073709551616` (`0x3B` followed by eight `0xFF` bytes) is + stored as `-1.8446744073709552e+19`. !!! warning "Object keys" diff --git a/docs/mkdocs/docs/features/enum_conversion.md b/docs/mkdocs/docs/features/enum_conversion.md index 3efd8e818..1b6e2b874 100644 --- a/docs/mkdocs/docs/features/enum_conversion.md +++ b/docs/mkdocs/docs/features/enum_conversion.md @@ -58,6 +58,23 @@ assert(jPi.get() == TS_INVALID ); --8<-- "examples/nlohmann_json_serialize_enum.output" ``` +## Maps with enum keys + +By default, maps with enum keys, such as `std::map`, are stored as arrays of `[key, value]` +pairs, because JSON object keys must be strings. Define +[`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md) before including the +library to store them as objects, with the keys converted by the enum's `to_json()` function: + +```cpp +std::map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}}; + +json j = m; +// default: [["stopped","aa"],["completed","bb"]] +// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS: {"completed":"bb","stopped":"aa"} +``` + +Either form can be read back, with or without the macro. + ## Notes Just as in [Arbitrary Type Conversions](arbitrary_types.md) above, diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md index 681980315..ef41ce0d5 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -23,6 +23,17 @@ This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/ See [full documentation of `JSON_CATCH_USER(exception)`](../api/macros/json_throw_user.md). +## `JSON_DELETE_DEPRECATED_FUNCTIONS` + +When defined to `1`, all deprecated functions are declared as deleted instead of only being marked as deprecated, so +code that still calls them no longer compiles. This way, you can find all calls that need to be replaced before version +4.0.0 removes these functions. + +The macro can also be set with the CMake option +[`JSON_DeleteDeprecatedFunctions`](../integration/cmake.md#json_deletedeprecatedfunctions) (`OFF` by default). + +See [full documentation of `JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md). + ## `JSON_DIAGNOSTICS` This macro enables extended diagnostics for exception messages. Possible values are `1` to enable or `0` to disable @@ -86,7 +97,8 @@ See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json ## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION` When defined to `1`, a JSON value can no longer be created from a one-element `std::tuple` holding a reference to a JSON -value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise. +value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise. This +is planned to become the default in version 4.0.0. See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md). @@ -198,6 +210,13 @@ default. See [full documentation of `JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../api/macros/json_use_legacy_discarded_value_comparison.md). +## `JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS` + +When defined to `1`, maps with enum keys (e.g., `std::map`) are stored as objects, using the enum's conversion for +the keys, instead of arrays of `[key, value]` pairs. It is switched off (`0`) by default. + +See [full documentation of `JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md). + ## `JSON_USE_SIMDUTF` When defined, UTF-8 validation of JSON strings read from contiguous byte input is delegated to the diff --git a/docs/mkdocs/docs/features/namespace.md b/docs/mkdocs/docs/features/namespace.md index dbddac13d..26e89d09c 100644 --- a/docs/mkdocs/docs/features/namespace.md +++ b/docs/mkdocs/docs/features/namespace.md @@ -21,6 +21,8 @@ The complete default namespace name is derived as follows: - [`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md) defined non-zero appends `_psp`. - [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) defined non-zero appends `_snul`. - [`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) defined non-zero appends `_sbu8`. + - [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md) defined non-zero + appends `_ekmo`. - The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component) below. diff --git a/docs/mkdocs/docs/features/serialization.md b/docs/mkdocs/docs/features/serialization.md index d9802bf08..1190c9005 100644 --- a/docs/mkdocs/docs/features/serialization.md +++ b/docs/mkdocs/docs/features/serialization.md @@ -64,6 +64,7 @@ serialization fails by default. The fourth argument of `dump` selects an - `strict` (default) — throw a [`type_error.316`](../home/exceptions.md#jsonexceptiontype_error316) exception. - `replace` — replace invalid bytes with the Unicode replacement character U+FFFD (`�`). - `ignore` — silently drop invalid bytes. +- `keep` — copy invalid bytes to the output unchanged; the result is not valid UTF-8. ??? example "Example: serialize invalid UTF-8 with different error handlers" diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md index e7eb8fd03..d6fdce37a 100644 --- a/docs/mkdocs/docs/home/exceptions.md +++ b/docs/mkdocs/docs/home/exceptions.md @@ -331,9 +331,6 @@ An unexpected byte was read in a [binary format](../features/binary_formats/inde [json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1 ``` ``` - [json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: negative integer overflow - ``` - ``` [json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: document size 6 does not match the number of bytes read (5) ``` @@ -599,6 +596,9 @@ During implicit or explicit value conversion, the JSON type must be compatible w [json.exception.type_error.302] type must be string, but is object ``` +This exception is also thrown with [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md) +if a key of a map with enum keys is not converted to a string, for instance, because the enum is stored as an integer. + ### json.exception.type_error.303 To retrieve a reference to a value stored in a `basic_json` object with `get_ref`, the type of the reference must match the value type. For instance, for a JSON array, the `ReferenceType` must be `array_t &`. @@ -771,6 +771,7 @@ as well for a string value or object key that is not valid UTF-8 if their `error - Pass an error handler as last parameter to the `dump()` function to avoid this exception: - `json::error_handler_t::replace` will replace invalid bytes sequences with `U+FFFD` - `json::error_handler_t::ignore` will silently ignore invalid byte sequences + - `json::error_handler_t::keep` will copy invalid byte sequences to the output unchanged ### json.exception.type_error.317 @@ -791,6 +792,33 @@ The dynamic type of the object cannot be represented in the requested serializat Encapsulate the JSON value in an object. That is, instead of serializing `#!json true`, serialize `#!json {"value": true}` +### json.exception.type_error.318 + +With [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md), a map with enum +keys is stored as an object. This exception is thrown if two of its keys are converted to the same string, so one of the +entries would be lost. This happens, for instance, if [`NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md) +does not list an enumerator and it is therefore converted like the first listed one. + +!!! failure "Example message" + + ``` + [json.exception.type_error.318] duplicate object key 'red' + ``` + +### json.exception.type_error.321 + +A discarded value (one created by [`parse()`](../api/basic_json/parse.md) with a callback that returns `false` for the +value, or by default-constructing a [`basic_json`](../api/basic_json/index.md) with +[`value_t::discarded`](../api/basic_json/value_t.md)) was passed to a binary serialization function, either directly or +nested in an array or object. There is no way to represent a discarded value in CBOR, MessagePack, UBJSON, BJData, or BSON. + +!!! failure "Example message" + + Serializing `#!json [1, 2]` to CBOR, where the second element was discarded by a parser callback: + ``` + [json.exception.type_error.321] cannot serialize discarded value to CBOR + ``` + ## Out of range This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance, in the case of array indices or nonexisting object keys. @@ -863,13 +891,18 @@ The JSON Patch operations 'remove' and 'add' cannot be applied to the root eleme ### json.exception.out_of_range.406 -A parsed number could not be stored as without changing it to NaN or INF. +A parsed number could not be stored without changing it to NaN or INF. For the binary formats, this happens when a +finite floating-point number does not fit into [`number_float_t`](../api/basic_json/number_float_t.md), for example a +double-precision number when `number_float_t` is `#!cpp float`. -!!! failure "Example message" +!!! failure "Example messages" ``` number overflow parsing '10E1000' ``` + ``` + [json.exception.out_of_range.406] syntax error while parsing CBOR value: number overflow + ``` ### json.exception.out_of_range.407 diff --git a/docs/mkdocs/docs/home/faq.md b/docs/mkdocs/docs/home/faq.md index 852fd8ffd..eec13a481 100644 --- a/docs/mkdocs/docs/home/faq.md +++ b/docs/mkdocs/docs/home/faq.md @@ -85,7 +85,7 @@ The library supports **Unicode input** as follows: - The library will not replace [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1). - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. -- When you store strings with different encodings in the library, calling [`dump()`](../api/basic_json/dump.md) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. +- When you store strings with different encodings in the library, calling [`dump()`](../api/basic_json/dump.md) may throw an exception unless `json::error_handler_t::replace`, `json::error_handler_t::ignore`, or `json::error_handler_t::keep` are used as error handlers. In most cases, the parser is right to complain, because the input is not UTF-8 encoded. This is especially true for Microsoft Windows, where Latin-1 or ISO 8859-1 is often the standard encoding. diff --git a/docs/mkdocs/docs/integration/cmake.md b/docs/mkdocs/docs/integration/cmake.md index 9151d12be..9492efe9f 100644 --- a/docs/mkdocs/docs/integration/cmake.md +++ b/docs/mkdocs/docs/integration/cmake.md @@ -126,12 +126,18 @@ automatically download a release as a dependency at configure time. ### `JSON_BuildTests` -Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/command/enable_testing.html) is enabled. This option is `ON` by default if the library's CMake project is the top project. That is, when integrating the library as described above, the test suite is not built unless explicitly switched on with this option. +Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/command/enable_testing.html) is enabled. This option is `ON` by default if the library's CMake project is the top project and the `tests` directory exists (the release archive `json.tar.xz` does not contain it). That is, when integrating the library as described above, the test suite is not built unless explicitly switched on with this option. ### `JSON_CI` Enable CI build targets. The exact targets are used during the several CI steps and are subject to change without notice. This option is `OFF` by default. +### `JSON_DeleteDeprecatedFunctions` + +Delete the deprecated functions instead of only deprecating them by defining the macro +[`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md). This option is `OFF` by +default. + ### `JSON_Diagnostics` Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default. diff --git a/docs/mkdocs/docs/integration/migration_guide.md b/docs/mkdocs/docs/integration/migration_guide.md index 8a07d48a3..17b2eb360 100644 --- a/docs/mkdocs/docs/integration/migration_guide.md +++ b/docs/mkdocs/docs/integration/migration_guide.md @@ -14,6 +14,13 @@ deprecations are annotated with [`HEDLEY_DEPRECATED_FOR`](https://nemequ.github.io/hedley/api-reference.html#HEDLEY_DEPRECATED_FOR) to report which function to use instead. +!!! tip "Find all calls of deprecated functions" + + Define [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) to `1` (or set the + CMake option [`JSON_DeleteDeprecatedFunctions`](cmake.md#json_deletedeprecatedfunctions)) to delete all deprecated + functions. Every remaining call then fails to compile, even if deprecation warnings are disabled, so your code is + ready for version 4.0.0 once it compiles with the macro. + ### Parsing - Function `friend std::istream& operator<<(basic_json&, std::istream&)` is deprecated since 3.0.0. Please use @@ -41,8 +48,10 @@ function to use instead. [`from_ubjson`](../api/basic_json/from_ubjson.md), and [`from_bson`](../api/basic_json/from_bson.md)) via initializer lists is deprecated since 3.8.0. Instead, pass two iterators; for instance, call `from_cbor(ptr, ptr+len)` instead of `from_cbor({ptr, len})`. Likewise, passing a pointer and a length as two separate arguments to `from_cbor`, - `from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0; call `from_cbor(ptr, ptr+len)` instead of - `from_cbor(ptr, len)`. + `from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0, and to + [`from_bjdata`](../api/basic_json/from_bjdata.md) and [`from_bon8`](../api/basic_json/from_bon8.md) since 3.13.0; call + `from_cbor(ptr, ptr+len)` instead of `from_cbor(ptr, len)`. These overloads will not be removed in version 4.0.0, but + deleted, so a call like `from_cbor(ptr, len)` cannot compile and convert `len` to the `strict` parameter. === "Deprecated" diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index dcb94864d..f38d70038 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -232,6 +232,7 @@ nav: - 'update': api/basic_json/update.md - 'value': api/basic_json/value.md - 'value_t': api/basic_json/value_t.md + - 'with_t': api/basic_json/with_t.md - byte_container_with_subtype: - 'Overview': api/byte_container_with_subtype/index.md - '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md @@ -292,6 +293,7 @@ nav: - 'JSON_BRACE_INIT_COPY_SEMANTICS': api/macros/json_brace_init_copy_semantics.md - 'JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER': api/macros/json_throw_user.md - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md + - 'JSON_DELETE_DEPRECATED_FUNCTIONS': api/macros/json_delete_deprecated_functions.md - 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md - 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md - 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md @@ -313,6 +315,7 @@ nav: - 'JSON_USE_GLOBAL_UDLS': api/macros/json_use_global_udls.md - 'JSON_USE_IMPLICIT_CONVERSIONS': api/macros/json_use_implicit_conversions.md - 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md + - 'JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS': api/macros/json_use_objects_for_enum_keyed_maps.md - 'JSON_USE_SIMDUTF': api/macros/json_use_simdutf.md - 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md - 'NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_intrusive.md diff --git a/docs/mkdocs/requirements.txt b/docs/mkdocs/requirements.txt index 6396ec500..d9e7098ed 100644 --- a/docs/mkdocs/requirements.txt +++ b/docs/mkdocs/requirements.txt @@ -6,7 +6,7 @@ mkdocs-material==9.7.7 # theme for mkdocs mkdocs-material-extensions==1.3.1 # extensions mkdocs-minify-plugin==0.8.0 # plugin "minify" mkdocs-redirects==1.2.3 # plugin "redirects" -mkdocs-htmlproofer-plugin==1.5.0 # plugin "htmlproofer" +mkdocs-htmlproofer-plugin==1.6.0 # plugin "htmlproofer" mkdocs-llmstxt==0.5.0 # plugin "llmstxt" PyYAML==6.0.3 # linter diff --git a/docs/mkdocs/scripts/mermaid/package-lock.json b/docs/mkdocs/scripts/mermaid/package-lock.json index 7fbbf6226..4f9dc0395 100644 --- a/docs/mkdocs/scripts/mermaid/package-lock.json +++ b/docs/mkdocs/scripts/mermaid/package-lock.json @@ -1454,9 +1454,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" diff --git a/include/nlohmann/detail/abi_macros.hpp b/include/nlohmann/detail/abi_macros.hpp index 0153c8706..063b9a0d9 100644 --- a/include/nlohmann/detail/abi_macros.hpp +++ b/include/nlohmann/detail/abi_macros.hpp @@ -50,6 +50,10 @@ #define JSON_STRICT_BINARY_UTF8 0 #endif +#ifndef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0 +#endif + #if JSON_DIAGNOSTICS #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag #else @@ -92,14 +96,20 @@ #define NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8 #endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS _ekmo +#else + #define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS +#endif + #ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) json_abi ## a ## b ## c ## d ## e ## f ## g -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h) json_abi ## a ## b ## c ## d ## e ## f ## g ## h +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ @@ -109,7 +119,8 @@ NLOHMANN_JSON_ABI_TAG_BRACE_INIT_COPY_SEMANTICS, \ NLOHMANN_JSON_ABI_TAG_PRECISE_STREAM_POSITION, \ NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING, \ - NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8) + NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8, \ + NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 5274b9857..884ff014a 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -172,7 +172,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e) typename BasicJsonType::number_unsigned_t, underlying_type>::type; value_type val; get_arithmetic_value(j, val); - e = static_cast(static_cast(val)); + e = static_cast(bool_aware_static_cast(val)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -530,11 +530,40 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m) } } +// read a map with enum keys from an object, using the enum's own from_json for +// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written +// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +template +inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/) +{ + if (!j.is_object()) + { + return false; + } + m.clear(); + for (const auto& p : *j.template get_ptr()) + { + m.emplace(BasicJsonType(p.first).template get(), p.second.template get()); + } + return true; +} + +template +inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/) +{ + return false; +} + template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, typename = enable_if_t < !std::is_constructible < typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::map& m) { + // NOLINTNEXTLINE(modernize-type-traits) we use C++11 + if (from_json_enum_keyed_object(j, m, std::is_enum {})) + { + return; + } from_json_pair_array_to_map(j, m); } @@ -543,6 +572,11 @@ template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::unordered_map& m) { + // NOLINTNEXTLINE(modernize-type-traits) we use C++11 + if (from_json_enum_keyed_object(j, m, std::is_enum {})) + { + return; + } from_json_pair_array_to_map(j, m); } diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index c0945ab9e..52342db40 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -308,8 +308,8 @@ boundaries compute_boundaries(FloatType value) // // -e <= 60 or e >= -60 := alpha -constexpr int kAlpha = -60; -constexpr int kGamma = -32; +JSON_INLINE_VARIABLE constexpr int kAlpha = -60; +JSON_INLINE_VARIABLE constexpr int kGamma = -32; struct cached_power // c = f * 2^e ~= 10^k { diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 2dba6c163..8edaee2fe 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -13,7 +13,6 @@ #include // optional #endif -#include // copy #include // begin, end #include // allocator_traits #include // basic_string, char_traits @@ -23,6 +22,7 @@ #include // valarray #include // vector +#include #include #include #include @@ -38,10 +38,14 @@ namespace detail ////////////////// /* - * Note all external_constructor<>::construct functions need to call - * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an - * allocated value (e.g., a string). See bug issue + * Note all external_constructor<>::construct functions need to store the new + * value with j.replace_value(), which destroys the old one to avoid a memory + * leak in case j contains an allocated value (e.g., a string). See bug issue * https://github.com/nlohmann/json/issues/2865 for more information. + * + * A value that has to be allocated is created before the old one is destroyed: + * were it the other way around, an exception while creating the new value would + * leave j with the type of the new value, but the pointer to the destroyed old one. */ template struct external_constructor; @@ -52,10 +56,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::boolean; - j.m_data.m_value = b; - j.assert_invariant(); + j.replace_value(value_t::boolean, b); } }; @@ -65,19 +66,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value = s; - j.assert_invariant(); + const typename BasicJsonType::json_value value(s); + j.replace_value(value_t::string, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value = std::move(s); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(s)); + j.replace_value(value_t::string, value); } template < typename BasicJsonType, typename CompatibleStringType, @@ -85,10 +82,8 @@ struct external_constructor int > = 0 > static void construct(BasicJsonType& j, const CompatibleStringType& str) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value.string = j.template create(str); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(str)); + j.replace_value(value_t::string, value); } }; @@ -98,19 +93,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::binary; - j.m_data.m_value = typename BasicJsonType::binary_t(b); - j.assert_invariant(); + const typename BasicJsonType::json_value value(b); + j.replace_value(value_t::binary, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::binary; - j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b)); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(b)); + j.replace_value(value_t::binary, value); } }; @@ -120,10 +111,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_float; - j.m_data.m_value = val; - j.assert_invariant(); + j.replace_value(value_t::number_float, val); } }; @@ -133,10 +121,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_unsigned; - j.m_data.m_value = val; - j.assert_invariant(); + j.replace_value(value_t::number_unsigned, val); } }; @@ -146,10 +131,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_integer; - j.m_data.m_value = val; - j.assert_invariant(); + j.replace_value(value_t::number_integer, val); } }; @@ -159,21 +141,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = arr; - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(arr); + j.replace_value(value_t::array, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = std::move(arr); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(arr)); + j.replace_value(value_t::array, value); } template < typename BasicJsonType, typename CompatibleArrayType, @@ -187,39 +163,23 @@ struct external_constructor using std::begin; using std::end; - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value.array = j.template create(begin(arr), end(arr)); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(begin(arr), end(arr))); + j.replace_value(value_t::array, value); } template static void construct(BasicJsonType& j, const std::vector& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; - j.m_data.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_data.m_value.array->push_back(x); - j.set_parent(j.m_data.m_value.array->back()); - } - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(arr.begin(), arr.end())); + j.replace_value(value_t::array, value); } template::value, int> = 0> static void construct(BasicJsonType& j, const std::valarray& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; - j.m_data.m_value.array->resize(arr.size()); - std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin()); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(std::begin(arr), std::end(arr))); + j.replace_value(value_t::array, value); } #if JSON_HAS_RANGE_VIEW_CONVERSION @@ -227,18 +187,15 @@ struct external_constructor enable_if_t>::value, int> = 0> static void construct(BasicJsonType& j, CompatibleArrayType && arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; + // no range constructor: a view's begin() and end() may have different + // types, and the view may only be iterable once + typename BasicJsonType::array_t elements; for (auto&& x : std::forward(arr)) { - j.m_data.m_value.array->push_back(x); + elements.push_back(x); } - // set the parents only once all elements are in place: a push_back - // that reallocates moves the earlier elements, which does not keep - // their parent pointers - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(elements)); + j.replace_value(value_t::array, value); } #endif }; @@ -249,21 +206,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value = obj; - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(obj); + j.replace_value(value_t::object, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value = std::move(obj); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(obj)); + j.replace_value(value_t::object, value); } template < typename BasicJsonType, typename CompatibleObjectType, @@ -273,11 +224,8 @@ struct external_constructor using std::begin; using std::end; - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value.object = j.template create(begin(obj), end(obj)); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(begin(obj), end(obj))); + j.replace_value(value_t::object, value); } }; @@ -286,9 +234,20 @@ struct external_constructor ///////////// #ifdef JSON_HAS_CPP_17 +// whether storing the value of a std::optional cannot throw; MSVC 2017 +// evaluates std::is_nothrow_assignable as true even if T's to_json throws, so +// the exception would call std::terminate (#5642) +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920 + template + using is_nothrow_optional_to_json = std::false_type; +#else + template + using is_nothrow_optional_to_json = std::is_nothrow_assignable; +#endif + template::value, int> = 0> -void to_json(BasicJsonType& j, const std::optional& opt) noexcept(std::is_nothrow_assignable::value) +void to_json(BasicJsonType& j, const std::optional& opt) noexcept(is_nothrow_optional_to_json::value) { if (opt.has_value()) { @@ -364,7 +323,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept { using underlying_type = typename std::underlying_type::type; static constexpr value_t integral_value_t = std::is_unsigned::value ? value_t::number_unsigned : value_t::number_integer; - external_constructor::construct(j, static_cast(e)); + external_constructor::construct(j, bool_aware_static_cast(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -384,6 +343,9 @@ template < typename BasicJsonType, typename CompatibleArrayType, !is_basic_json::value #if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value +#endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + && !is_enum_keyed_map::value #endif , int > = 0 > @@ -438,6 +400,33 @@ inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) external_constructor::construct(j, obj); } +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +// store a map with enum keys as an object, using the enum's own to_json for the +// keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); without the macro, such maps +// are stored as arrays of [key, value] pairs +template < typename BasicJsonType, typename EnumKeyedMap, + enable_if_t < is_enum_keyed_map::value&& !is_basic_json::value, int > = 0 > +inline void to_json(BasicJsonType& j, const EnumKeyedMap& map) +{ + typename BasicJsonType::object_t obj; + for (const auto& p : map) + { + BasicJsonType key = p.first; + if (JSON_HEDLEY_UNLIKELY(!key.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", key.type_name()), &key)); + } + + auto& key_string = *key.template get_ptr(); + if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second)) + { + JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key)); + } + } + external_constructor::construct(j, std::move(obj)); +} +#endif + template inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { diff --git a/include/nlohmann/detail/hash.hpp b/include/nlohmann/detail/hash.hpp index 20a971886..fd1326b5d 100644 --- a/include/nlohmann/detail/hash.hpp +++ b/include/nlohmann/detail/hash.hpp @@ -35,8 +35,10 @@ std::size_t hash_iteratively(const BasicJsonType& j); @brief hash a JSON value The hash function tries to rely on std::hash where possible. Furthermore, the -type of the JSON value is taken into account to have different hash values for -null, 0, 0U, and false, etc. +type of the JSON value is taken into account, so null, false, and numbers may +hash differently from each other, but any two numbers that compare equal +under operator== hash equally regardless of which of number_integer, +number_unsigned, or number_float actually holds the value. Hashing an array or an object hashes its elements, which used to call this function again once per nesting level, so a value nested deeply enough @@ -55,8 +57,6 @@ template std::size_t hash(const BasicJsonType& j, const std::size_t depth = 0) { using string_t = typename BasicJsonType::string_t; - 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; const auto type = static_cast(j.type()); @@ -113,21 +113,24 @@ std::size_t hash(const BasicJsonType& j, const std::size_t depth = 0) } case BasicJsonType::value_t::number_integer: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - case BasicJsonType::value_t::number_unsigned: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - case BasicJsonType::value_t::number_float: { - const auto h = std::hash {}(j.template get()); - return combine(type, h); + // operator== compares numbers by their mathematical value across + // number_integer, number_unsigned, and number_float, so equal + // numbers of different internal types (0, 0U, 0.0) must hash the + // same. Two equal numbers have the same value, which converts to + // the same number_float_t, so all numbers share one type tag and + // hash that converted value. Adding zero turns -0.0 (equal to 0) + // into 0.0, as std::hash need not map both to the same hash. + // The converse does not hold: converting a number_float_t value + // to an integer type is lossy, so the result can hash + // differently, and unequal numbers that convert to the same + // number_float_t (e.g., 2^53 and 2^53 + 1) share a hash. + const auto number_type = static_cast(BasicJsonType::value_t::number_float); + const auto value = j.template get() + static_cast(0); + const auto h = std::hash {}(value); + return combine(number_type, h); } case BasicJsonType::value_t::binary: diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index d6b45909a..3dfff13b9 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -197,7 +197,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current != char_traits::eof())) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, - exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); + exception_message(concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); } } @@ -320,7 +320,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast(document_size) != chars_read - document_start)) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr)); + exception_message(concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr)); } return true; } @@ -335,7 +335,7 @@ class binary_reader // check_bson_document_size() measures the document from here const std::size_t document_start = chars_read; std::int32_t document_size{}; - if (!get_number(input_format_t::bson, document_size)) + if (!get_number(document_size)) { return false; } @@ -400,7 +400,7 @@ class binary_reader continue; } - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("element list"))) { return false; } @@ -444,7 +444,7 @@ class binary_reader while (true) { get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("cstring"))) { return false; } @@ -514,10 +514,10 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); + exception_message(concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); } - if (JSON_HEDLEY_UNLIKELY(!get_string(input_format_t::bson, len - static_cast(1), result))) + if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast(1), result))) { return false; } @@ -526,8 +526,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, - "BSON string is not null-terminated", + exception_message("BSON string is not null-terminated", "string"), nullptr)); } @@ -550,18 +549,18 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); + exception_message(concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); } // All BSON binary values have a subtype std::uint8_t subtype{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::bson, subtype))) + if (JSON_HEDLEY_UNLIKELY(!get_number(subtype))) { return false; } result.set_subtype(subtype); - return get_binary(input_format_t::bson, len, result); + return get_binary(len, result); } /*! @@ -582,14 +581,14 @@ class binary_reader case 0x01: // double { double number{}; - return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0x02: // string { std::int32_t len{}; string_t value; - return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + return get_number(len) && get_bson_string(len, value) && sax->string(value); } case 0x03: // object @@ -606,13 +605,13 @@ class binary_reader { std::int32_t len{}; binary_t value; - return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + return get_number(len) && get_bson_binary(len, value) && sax->binary(value); } case 0x08: // boolean { std::uint8_t value{}; - return get_number(input_format_t::bson, value) && sax->boolean(value != 0); + return get_number(value) && sax->boolean(value != 0); } case 0x0A: // null @@ -623,19 +622,19 @@ class binary_reader case 0x10: // int32 { std::int32_t value{}; - return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value)); + return get_number(value) && emit_signed(value); } case 0x12: // int64 { std::int64_t value{}; - return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value)); + return get_number(value) && emit_signed(value); } case 0x11: // uint64 { std::uint64_t value{}; - return get_number(input_format_t::bson, value) && sax->number_unsigned(value); + return get_number(value) && emit_unsigned(value); } default: // anything else is not supported (yet) @@ -657,18 +656,24 @@ class binary_reader bool get_cbor_negative_integer() { NumberType number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } - const auto max_val = static_cast((std::numeric_limits::max)()); - if (number > max_val) + + // the value is -1 - number, which fits into number_integer_t + // whenever number does; the outer cast undoes the integral promotion + // for number_integer_t types narrower than int + if (JSON_HEDLEY_LIKELY(value_in_range_of(number))) { - return sax->parse_error(chars_read, get_token_string(), - parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, "negative integer overflow", "value"), nullptr)); + return sax->number_integer(conditional_static_cast(static_cast(-1) - static_cast(number))); } - return sax->number_integer(conditional_static_cast(static_cast(-1) - static_cast(number))); + + // like the lexer does for JSON text, store a value too small for + // number_integer_t as number_float_t; compute it as long double so + // that emit_float sees a finite value and can detect an overflow of + // number_float_t + return emit_float(static_cast(-1) - static_cast(number)); } /*! @@ -693,7 +698,7 @@ class binary_reader { // EOF case char_traits::eof(): - return unexpect_eof(input_format_t::cbor, "value"); + return unexpect_eof("value"); // Integer 0x00..0x17 (0..23) case 0x00: @@ -725,25 +730,25 @@ class binary_reader case 0x18: // Unsigned integer (one-byte uint8_t follows) { std::uint8_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0x19: // Unsigned integer (two-byte uint16_t follows) { std::uint16_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0x1A: // Unsigned integer (four-byte uint32_t follows) { std::uint32_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0x1B: // Unsigned integer (eight-byte uint64_t follows) { std::uint64_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } // Negative integer -1-0x00..-1-0x17 (-1..-24) @@ -964,7 +969,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } // ignore and store: the tag value is already in the head, so @@ -986,7 +991,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } case cbor_tag_handler_t::ignore: @@ -1044,29 +1049,43 @@ class binary_reader return sax->null(); case 0xF9: // Half-Precision Float (two-byte IEEE 754) - return get_half_float(input_format_t::cbor, false); + return get_half_float(false); case 0xFA: // Single-Precision Float (four-byte IEEE 754) { float number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { double number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } default: // anything else (0xFF is handled inside the other types) { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } } } + /*! + @brief reports a nested indefinite-length CBOR string or byte array + @param[in] type_name name of the rejected string type + @param[in] context parsing context for the error message + @return whether the SAX consumer accepts the parse error + */ + bool cbor_indefinite_string_error(const char* type_name, const char* context) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(concat("indefinite-length ", type_name, + " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", last_token), context), nullptr)); + } + /*! @brief reads a definite-length CBOR string @@ -1076,12 +1095,13 @@ class binary_reader into the same string. @param[out] result string the bytes are appended to + @param[in] inside_indefinite whether the bytes belong to an indefinite-length string @return whether string creation completed @pre @a current is not EOF */ - bool get_cbor_string_chunk(string_t& result) + bool get_cbor_string_chunk(string_t& result, const bool inside_indefinite) { switch (current) { @@ -1111,38 +1131,38 @@ class binary_reader case 0x76: case 0x77: { - return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + return get_string(static_cast(current) & 0x1Fu, result); } case 0x78: // UTF-8 string (one-byte uint8_t for n follows) { std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } case 0x79: // UTF-8 string (two-byte uint16_t for n follow) { std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) { std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) { std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); + exception_message(concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", last_token), "string"), nullptr)); } } } @@ -1160,46 +1180,41 @@ class binary_reader */ bool get_cbor_string(string_t& result, const char* context = "string") { - // number of indefinite-length strings that have been opened and not - // closed yet. RFC 8949, Section 3.2.3 does not permit nesting them, - // but this reader has always accepted it, so the open levels are - // counted instead of recursed through, which overflowed the stack for - // an input of repeated 0x7F bytes (see #5104). Every chunk is appended - // to the same result, so no per-level state is needed. - std::size_t open = 0; + // read chunks iteratively, but reject a second indefinite-length + // level as required by RFC 8949, Section 3.2.3 + bool indefinite = false; while (true) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("string"))) { return false; } if (current == 0x7F) // UTF-8 string (indefinite length) { - ++open; - get(); - continue; - } - - // a break marker closes the innermost indefinite-length string; - // outside of one it is not a string and falls through to the error - if (open != 0 && current == 0xFF) - { - if (--open == 0) + if (JSON_HEDLEY_UNLIKELY(indefinite)) { - return check_string_utf8(result, context); + return cbor_indefinite_string_error("string", "string"); } + indefinite = true; get(); continue; } - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result))) + // a break marker closes the indefinite-length string; outside + // of one it falls through to the error below + if (indefinite && current == 0xFF) + { + return check_string_utf8(result, context); + } + + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result, indefinite))) { return false; } - if (open == 0) + if (!indefinite) { return check_string_utf8(result, context); } @@ -1279,7 +1294,7 @@ class binary_reader auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); + exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); } /*! @@ -1291,12 +1306,13 @@ class binary_reader read into the same byte array. @param[out] result byte array the bytes are appended to + @param[in] inside_indefinite whether the bytes belong to an indefinite-length string @return whether byte array creation completed @pre @a current is not EOF */ - bool get_cbor_binary_chunk(binary_t& result) + bool get_cbor_binary_chunk(binary_t& result, const bool inside_indefinite) { switch (current) { @@ -1326,42 +1342,42 @@ class binary_reader case 0x56: case 0x57: { - return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + return get_binary(static_cast(current) & 0x1Fu, result); } case 0x58: // Binary data (one-byte uint8_t for n follows) { std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } case 0x59: // Binary data (two-byte uint16_t for n follow) { std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } case 0x5A: // Binary data (four-byte uint32_t for n follow) { std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } case 0x5B: // Binary data (eight-byte uint64_t for n follow) { std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); + exception_message(concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", last_token), "binary"), nullptr)); } } } @@ -1379,42 +1395,41 @@ class binary_reader */ bool get_cbor_binary(binary_t& result) { - // the open indefinite-length byte arrays are counted rather than - // recursed through, for the reason given in @ref get_cbor_string - std::size_t open = 0; + // read chunks iteratively, but reject a second indefinite-length + // level as required by RFC 8949, Section 3.2.3 + bool indefinite = false; while (true) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("binary"))) { return false; } if (current == 0x5F) // Binary data (indefinite length) { - ++open; - get(); - continue; - } - - // a break marker closes the innermost indefinite-length byte - // array; outside of one it falls through to the error below - if (open != 0 && current == 0xFF) - { - if (--open == 0) + if (JSON_HEDLEY_UNLIKELY(indefinite)) { - return true; + return cbor_indefinite_string_error("binary array", "binary"); } + indefinite = true; get(); continue; } - if (JSON_HEDLEY_UNLIKELY(!get_cbor_binary_chunk(result))) + // a break marker closes the indefinite-length string; outside + // of one it falls through to the error below + if (indefinite && current == 0xFF) + { + return true; + } + + if (JSON_HEDLEY_UNLIKELY(!get_cbor_binary_chunk(result, indefinite))) { return false; } - if (open == 0) + if (!indefinite) { return true; } @@ -1443,7 +1458,7 @@ class binary_reader case 0x18: // 1 byte { std::uint8_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -1454,7 +1469,7 @@ class binary_reader case 0x19: // 2 bytes { std::uint16_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -1465,7 +1480,7 @@ class binary_reader case 0x1A: // 4 bytes { std::uint32_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -1476,7 +1491,7 @@ class binary_reader case 0x1B: // 8 bytes { std::uint64_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -1509,7 +1524,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(len) || len == detail::unknown_size())) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format_t::cbor, concat("excessive ", context, " size"), "size"), nullptr)); + exception_message(concat("excessive ", context, " size"), "size"), nullptr)); } result = conditional_static_cast(len); return true; @@ -1638,7 +1653,7 @@ class binary_reader { // EOF case char_traits::eof(): - return unexpect_eof(input_format_t::msgpack, "value"); + return unexpect_eof("value"); // positive fixint case 0x00: @@ -1878,85 +1893,85 @@ class binary_reader case 0xCA: // float 32 { float number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xCB: // float 64 { double number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xCC: // uint 8 { std::uint8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xCD: // uint 16 { std::uint16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xCE: // uint 32 { std::uint32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xCF: // uint 64 { std::uint64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xD0: // int 8 { std::int8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xD1: // int 16 { std::int16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xD2: // int 32 { std::int32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xD3: // int 64 { std::int64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xDC: // array 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && enter_array(static_cast(len)); + return get_number(len) && enter_array(static_cast(len)); } case 0xDD: // array 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && enter_array(conditional_static_cast(len)); + return get_number(len) && enter_array(conditional_static_cast(len)); } case 0xDE: // map 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && enter_object(static_cast(len)); + return get_number(len) && enter_object(static_cast(len)); } case 0xDF: // map 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && enter_object(conditional_static_cast(len)); + return get_number(len) && enter_object(conditional_static_cast(len)); } // negative fixint @@ -1998,7 +2013,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } } } @@ -2015,7 +2030,7 @@ class binary_reader */ bool get_msgpack_string(string_t& result, const char* context = "string") { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("string"))) { return false; } @@ -2056,32 +2071,32 @@ class binary_reader case 0xBE: case 0xBF: { - return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result) && check_string_utf8(result, context); + return get_string(static_cast(current) & 0x1Fu, result) && check_string_utf8(result, context); } case 0xD9: // str 8 { std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 0xDA: // str 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 0xDB: // str 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); + exception_message(concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); } } } @@ -2175,7 +2190,7 @@ class binary_reader auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::msgpack, concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); + exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); } /*! @@ -2202,31 +2217,31 @@ class binary_reader case 0xC4: // bin 8 { std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); + return get_number(len) && + get_binary(len, result); } case 0xC5: // bin 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); + return get_number(len) && + get_binary(len, result); } case 0xC6: // bin 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); + return get_number(len) && + get_binary(len, result); } case 0xC7: // ext 8 { std::uint8_t len{}; std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && + return get_number(len) && + get_number(subtype) && + get_binary(len, result) && assign_and_return_true(subtype); } @@ -2234,9 +2249,9 @@ class binary_reader { std::uint16_t len{}; std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && + return get_number(len) && + get_number(subtype) && + get_binary(len, result) && assign_and_return_true(subtype); } @@ -2244,49 +2259,49 @@ class binary_reader { std::uint32_t len{}; std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && + return get_number(len) && + get_number(subtype) && + get_binary(len, result) && assign_and_return_true(subtype); } case 0xD4: // fixext 1 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 1, result) && + return get_number(subtype) && + get_binary(1, result) && assign_and_return_true(subtype); } case 0xD5: // fixext 2 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 2, result) && + return get_number(subtype) && + get_binary(2, result) && assign_and_return_true(subtype); } case 0xD6: // fixext 4 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 4, result) && + return get_number(subtype) && + get_binary(4, result) && assign_and_return_true(subtype); } case 0xD7: // fixext 8 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 8, result) && + return get_number(subtype) && + get_binary(8, result) && assign_and_return_true(subtype); } case 0xD8: // fixext 16 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 16, result) && + return get_number(subtype) && + get_binary(16, result) && assign_and_return_true(subtype); } @@ -2485,7 +2500,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(len < 0)) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "string length must not be negative", "string"), nullptr)); + exception_message("string length must not be negative", "string"), nullptr)); } return true; } @@ -2515,7 +2530,7 @@ class binary_reader get(); } - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("value"))) { return false; } @@ -2525,31 +2540,31 @@ class binary_reader case 'U': { std::uint8_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 'i': { std::int8_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'I': { std::int16_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'l': { std::int32_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'L': { std::int64_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'u': @@ -2559,7 +2574,7 @@ class binary_reader break; } std::uint16_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 'm': @@ -2569,7 +2584,7 @@ class binary_reader break; } std::uint32_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 'M': @@ -2579,7 +2594,7 @@ class binary_reader break; } std::uint64_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } default: @@ -2596,7 +2611,7 @@ class binary_reader { message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; } - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "string"), nullptr)); } /*! @@ -2675,19 +2690,19 @@ class binary_reader bool get_ubjson_signed_count(std::size_t& result) { SignedType number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } if (JSON_HEDLEY_UNLIKELY(number < 0)) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + exception_message("count in an optimized container must be positive", "size"), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(number))) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "integer value overflow", "size"), nullptr)); + exception_message("integer value overflow", "size"), nullptr)); } result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char return true; @@ -2701,10 +2716,15 @@ class binary_reader is_ndarray can only return `true` when its initial value is `false` @param[in] prefix type marker if already read, otherwise set to 0 + @param[in] ndarray_dtype the element type marker of the enclosing bjdata ndarray if + already known (it precedes the dimension vector read here), + otherwise 0; used to emit the "_ArrayType_" annotation key + before "_ArraySize_" if a dimension vector turns out to + describe an ndarray @return whether size determination completed */ - bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0, char_int_type ndarray_dtype = 0) { if (prefix == 0) { @@ -2716,7 +2736,7 @@ class binary_reader case 'U': { std::uint8_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } @@ -2743,7 +2763,7 @@ class binary_reader break; } std::uint16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } @@ -2758,7 +2778,7 @@ class binary_reader break; } std::uint32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } @@ -2773,14 +2793,14 @@ class binary_reader break; } std::uint64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } if (!value_in_range_of(number)) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "integer value overflow", "size"), nullptr)); + exception_message("integer value overflow", "size"), nullptr)); } result = detail::conditional_static_cast(number); return true; @@ -2794,7 +2814,7 @@ class binary_reader } if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message("ndarray dimensional vector is not allowed", "size"), nullptr)); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -2817,8 +2837,34 @@ class binary_reader } } + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3))) + { + return false; + } + + // the element type precedes the dimension vector (see get_ubjson_size_type) + // and is passed down as ndarray_dtype; emit it here so the annotation keys + // follow the documented _ArrayType_, _ArraySize_, _ArrayData_ order + if (ndarray_dtype != 0) + { + const char* type_name = bjd_type_name(ndarray_dtype); + if (JSON_HEDLEY_UNLIKELY(type_name == nullptr)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message("invalid byte: 0x" + last_token, "type"), nullptr)); + } + + string_t type_key = "_ArrayType_"; + string_t type = type_name; // sax->string() takes a reference + if (JSON_HEDLEY_UNLIKELY(!sax->key(type_key) || !sax->string(type))) + { + return false; + } + } + string_t key = "_ArraySize_"; - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(dim.size()))) { return false; } @@ -2834,7 +2880,7 @@ class binary_reader // or SIZE_MAX. if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits::max)() / i)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } result *= i; // the pre-check above already rules out result becoming 0 @@ -2843,9 +2889,9 @@ class binary_reader // unknown-size container (see get_ubjson_size_type()) if (result == npos) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } - if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast(i)))) + if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i))) { return false; } @@ -2871,7 +2917,7 @@ class binary_reader { message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; } - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "size"), nullptr)); } /*! @@ -2906,10 +2952,10 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + exception_message(concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); } - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type"))) { return false; } @@ -2917,16 +2963,16 @@ class binary_reader get_ignore_noop(); if (JSON_HEDLEY_UNLIKELY(current != '#')) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("value"))) { return false; } auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); + exception_message(concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); } - const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + const bool is_error = get_ubjson_size_value(result.first, is_ndarray, 0, result.second); // an ndarray was read here only if the flag flipped; when it was // seeded true, get_ubjson_size_value() already rejected the nested // dimension vector @@ -2943,7 +2989,7 @@ class binary_reader if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, - exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); + exception_message("ndarray requires both type and size", "size"), nullptr)); } return is_error; } @@ -2960,7 +3006,7 @@ class binary_reader switch (prefix) { case char_traits::eof(): // EOF - return unexpect_eof(input_format, "value"); + return unexpect_eof("value"); case 'T': // true return sax->boolean(true); @@ -2977,37 +3023,37 @@ class binary_reader break; } std::uint8_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'U': { std::uint8_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'i': { std::int8_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'I': { std::int16_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'l': { std::int32_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'L': { std::int64_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'u': @@ -3017,7 +3063,7 @@ class binary_reader break; } std::uint16_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'm': @@ -3027,7 +3073,7 @@ class binary_reader break; } std::uint32_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'M': @@ -3037,7 +3083,7 @@ class binary_reader break; } std::uint64_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'h': @@ -3046,19 +3092,19 @@ class binary_reader { break; } - return get_half_float(input_format, true); + return get_half_float(true); } case 'd': { float number{}; - return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 'D': { double number{}; - return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 'H': @@ -3069,7 +3115,7 @@ class binary_reader case 'C': // char { get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("char"))) { return false; } @@ -3077,7 +3123,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); + exception_message(concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); } string_t s(1, static_cast(current)); return sax->string(s); @@ -3099,7 +3145,7 @@ class binary_reader break; } auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message("invalid byte: 0x" + last_token, "value"), nullptr)); } /*! @@ -3119,27 +3165,17 @@ class binary_reader if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) { size_and_type.second &= ~(static_cast(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker - const char* type_name = bjd_type_name(size_and_type.second); - string_t key = "_ArrayType_"; - if (JSON_HEDLEY_UNLIKELY(type_name == nullptr)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); - } - - string_t type = type_name; // sax->string() takes a reference - if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) - { - return false; - } + // the "_ArrayType_" and "_ArraySize_" annotation keys were already emitted by + // get_ubjson_size_value() (the type marker is known before the dimension vector + // that determines size_and_type.first is read, so it is emitted first there to + // match the documented _ArrayType_, _ArraySize_, _ArrayData_ key order) if (size_and_type.second == 'C' || size_and_type.second == 'B') { size_and_type.second = 'U'; } - key = "_ArrayData_"; + string_t key = "_ArrayData_"; if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) { return false; @@ -3160,7 +3196,7 @@ class binary_reader if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B') { binary_t result; - return get_binary(input_format, size_and_type.first, result) && sax->binary(result); + return get_binary(size_and_type.first, result) && sax->binary(result); } if (size_and_type.first != npos) @@ -3173,7 +3209,7 @@ class binary_reader && size_and_type.first > max_valueless_container_size)) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "excessive array size", "size"), nullptr)); + exception_message("excessive array size", "size"), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!enter_array(size_and_type.first, size_and_type.second))) @@ -3210,7 +3246,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); + exception_message("BJData object does not support ND-array size in optimized format", "object"), nullptr)); } if (size_and_type.first != npos) @@ -3240,10 +3276,16 @@ class binary_reader for (std::size_t i = 0; i < size; ++i) { get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } + // the lexer would stop at a NUL and accept the digits before it + if (JSON_HEDLEY_UNLIKELY(current == '\0')) + { + return sax->parse_error(chars_read, "00", parse_error::create(115, chars_read, + exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr)); + } number_vector.push_back(static_cast(current)); } @@ -3259,7 +3301,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) { return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, - exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } switch (result_number) @@ -3299,7 +3341,7 @@ class binary_reader case token_type::literal_or_value: default: return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, - exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } } @@ -3368,7 +3410,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bon8, concat(detail, ": 0x", last_token), context), nullptr)); + exception_message(concat(detail, ": 0x", last_token), context), nullptr)); } /*! @@ -3472,7 +3514,7 @@ class binary_reader if (byte == char_traits::eof()) { - return unexpect_eof(input_format_t::bon8, "value"); + return unexpect_eof("value"); } // string: ASCII character @@ -3509,25 +3551,25 @@ class binary_reader case 0x8C: // int32 { std::int32_t number{}; - return get_number(input_format_t::bon8, number) && emit_bon8_integer(number); + return get_number(number) && emit_bon8_integer(number); } case 0x8D: // int64 { std::int64_t number{}; - return get_number(input_format_t::bon8, number) && emit_bon8_integer(number); + return get_number(number) && emit_bon8_integer(number); } case 0x8E: // binary32 { float number{}; - return get_number(input_format_t::bon8, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0x8F: // binary64 { double number{}; - return get_number(input_format_t::bon8, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xF8: @@ -3593,7 +3635,9 @@ class binary_reader @brief pass an integer to the SAX parser Non-negative integers are passed as unsigned, negative integers as signed - numbers, like the other binary formats do. + numbers, like the other binary formats do. A value that does not fit the + number type is passed as described for @ref emit_unsigned and + @ref emit_signed. @param[in] number the integer @return whether the SAX parser accepted the value @@ -3602,9 +3646,9 @@ class binary_reader { if (number >= 0) { - return sax->number_unsigned(static_cast(number)); + return emit_unsigned(static_cast(number)); } - return sax->number_integer(static_cast(number)); + return emit_signed(number); } /*! @@ -3624,7 +3668,7 @@ class binary_reader */ bool get_bon8_integer(const char_int_type lead, const char_int_type second) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bon8, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } @@ -3656,13 +3700,12 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(get_bon8() == char_traits::eof())) { - return unexpect_eof(input_format_t::bon8, "number"); + return unexpect_eof("number"); } value = (value << 8) | static_cast(current); } - return negative ? sax->number_integer(static_cast(-(value + offset))) - : sax->number_unsigned(static_cast(value + offset)); + return emit_bon8_integer(negative ? -(value + offset) : value + offset); } /*! @@ -3680,7 +3723,7 @@ class binary_reader if (byte == char_traits::eof()) { - return unexpect_eof(input_format_t::bon8, "key"); + return unexpect_eof("key"); } if (byte == 0xFF) @@ -3700,7 +3743,7 @@ class binary_reader if (second == char_traits::eof()) { // the input ends inside a character or an integer - return unexpect_eof(input_format_t::bon8, "key"); + return unexpect_eof("key"); } unget_bon8(second); if (is_bon8_continuation(second)) @@ -3773,7 +3816,7 @@ class binary_reader if (byte == char_traits::eof()) { - return unexpect_eof(input_format_t::bon8, "string"); + return unexpect_eof("string"); } // end of string @@ -3804,7 +3847,7 @@ class binary_reader { // the input ends inside a character or an integer: either // way, the message is incomplete - return unexpect_eof(input_format_t::bon8, "string"); + return unexpect_eof("string"); } if (!is_bon8_continuation(second)) { @@ -3845,7 +3888,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(get_bon8() == char_traits::eof())) { - return unexpect_eof(input_format_t::bon8, "string"); + return unexpect_eof("string"); } if (JSON_HEDLEY_UNLIKELY(!is_bon8_continuation(current))) { @@ -3884,7 +3927,7 @@ class binary_reader @return bool, whether the read was successful */ template - bool get_to(T& dest, const input_format_t format, const char* context) + bool get_to(T& dest, const char* context) { // false positive: new_chars_read is read on the next lines // @infer-ignore DEAD_STORE @@ -3894,7 +3937,7 @@ class binary_reader { // in case of failure, advance position by 1 to report the failing location ++chars_read; - sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); return false; } return true; @@ -3945,7 +3988,6 @@ class binary_reader @brief read a number from the input @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) @param[out] result number of type @a NumberType @return whether conversion completed @@ -3957,42 +3999,122 @@ class binary_reader should reorder on big endian systems. */ template - bool get_number(const input_format_t format, NumberType& result) + bool get_number(NumberType& result) { // read in the original format - if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!get_to(result, "number"))) { return false; } - if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + if (is_little_endian != (InputIsLittleEndian || input_format == input_format_t::bjdata)) { byte_swap(result); } return true; } + /*! + @brief pass a signed integer read from the input to the SAX parser + + Like the lexer does for JSON text, a value that does not fit into + number_integer_t is passed as number_unsigned_t if it is non-negative and + fits there, and as number_float_t otherwise. With the default number + types, every integer the binary formats can encode fits, so this only + matters for narrower custom number types. + + @tparam NumberType a signed integer type + @param[in] number the integer + @return whether the SAX parser accepted the value + + @throw out_of_range.406 if @a number overflows number_float_t (see + @ref emit_float) + */ + template + bool emit_signed(const NumberType number) + { + if (JSON_HEDLEY_LIKELY(value_in_range_of(number))) + { + return sax->number_integer(static_cast(number)); + } + if (value_in_range_of(number)) + { + return sax->number_unsigned(static_cast(number)); + } + // std::isfinite has no integer overloads in MSVC's + return emit_float(static_cast(number)); + } + + /*! + @brief pass an unsigned integer read from the input to the SAX parser + + Like the lexer does for JSON text, a value that does not fit into + number_unsigned_t is passed as number_float_t. + + @tparam NumberType an unsigned integer type + @param[in] number the integer + @return whether the SAX parser accepted the value + + @throw out_of_range.406 if @a number overflows number_float_t (see + @ref emit_float) + */ + template + bool emit_unsigned(const NumberType number) + { + if (JSON_HEDLEY_LIKELY(value_in_range_of(number))) + { + return sax->number_unsigned(static_cast(number)); + } + // std::isfinite has no integer overloads in MSVC's + return emit_float(static_cast(number)); + } + + /*! + @brief pass a floating-point number read from the input to the SAX parser + + Like the lexer does for JSON text, a finite value that overflows + number_float_t is rejected instead of silently becoming infinity. Infinity + and NaN in the input are passed on unchanged. Integers only overflow if + number_float_t cannot represent 2^64, e.g., a half-precision type. + + @tparam NumberType a floating-point type (emit_signed and emit_unsigned + convert integers to long double first) + @param[in] number the number + @return whether the SAX parser accepted the value + + @throw out_of_range.406 if a finite @a number overflows number_float_t + */ + template + bool emit_float(const NumberType number) + { + const auto result = static_cast(number); + if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result))) + { + return sax->parse_error(chars_read, get_token_string(), + out_of_range::create(406, exception_message("number overflow", "value"), nullptr)); + } + return sax->number_float(result, ""); + } + /*! @brief read and decode an IEEE 754 half-precision (16-bit) float Used by CBOR (big endian) and BJData (little endian); the two formats only differ in the byte order of the two bytes that make up the half. - - @param[in] format the current format (for diagnostics) @param[in] little_endian whether the two bytes are little endian (BJData) or big endian (CBOR) @return whether reading and decoding succeeded */ - bool get_half_float(const input_format_t format, const bool little_endian) + bool get_half_float(const bool little_endian) { const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } @@ -4038,7 +4160,6 @@ class binary_reader @brief create a string by reading characters from the input @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) @param[in] len number of characters to read @param[out] result string created by reading @a len bytes @@ -4049,8 +4170,7 @@ class binary_reader the input before we run out of string memory. */ template - bool get_string(const input_format_t format, - const NumberType len, + bool get_string(const NumberType len, string_t& result) { // Strings are taken as is by default: none of CBOR (RFC 8949 §3.1 @@ -4062,7 +4182,7 @@ class binary_reader // @ref error_handler, applied once the whole string (all chunks of // an indefinite-length CBOR string included) has been assembled, by // @ref check_string_utf8 at the call site. - return get_bytes(format, len, "string", result); + return get_bytes(len, "string", result); } /*! @@ -4093,7 +4213,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, "invalid string: ill-formed UTF-8 byte", context), nullptr)); + exception_message("invalid string: ill-formed UTF-8 byte", context), nullptr)); } result = sanitize_utf8(result, error_handler); @@ -4104,7 +4224,6 @@ class binary_reader @brief create a byte array by reading bytes from the input @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) @param[in] len number of bytes to read @param[out] result byte array created by reading @a len bytes @@ -4115,11 +4234,10 @@ class binary_reader the input before we run out of memory. */ template - bool get_binary(const input_format_t format, - const NumberType len, + bool get_binary(const NumberType len, binary_t& result) { - return get_bytes(format, len, "binary", result); + return get_bytes(len, "binary", result); } /*! @@ -4127,7 +4245,6 @@ class binary_reader @tparam NumberType the type of the length @tparam ContainerType the destination container (string_t or binary_t) - @param[in] format the current format (for diagnostics) @param[in] len number of bytes to read @param[in] context further context information (for diagnostics) @param[out] result container the bytes are appended to @@ -4142,8 +4259,7 @@ class binary_reader detects a premature end of input. */ template - bool get_bytes(const input_format_t format, - NumberType len, + bool get_bytes(NumberType len, const char* context, ContainerType& result) { @@ -4174,7 +4290,7 @@ class binary_reader result.resize(old_size + bytes_read); ++chars_read; current = char_traits::eof(); - return unexpect_eof(format, context); + return unexpect_eof(context); } // a full chunk was read; get_elements() never returns more than requested JSON_ASSERT(bytes_read == wanted); @@ -4184,17 +4300,16 @@ class binary_reader } /*! - @param[in] format the current format (for diagnostics) @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF */ - JSON_HEDLEY_NON_NULL(3) - bool unexpect_eof(const input_format_t format, const char* context) const + JSON_HEDLEY_NON_NULL(2) + bool unexpect_eof(const char* context) const { if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) { return sax->parse_error(chars_read, "", - parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); } return true; } @@ -4210,18 +4325,16 @@ class binary_reader } /*! - @param[in] format the current format @param[in] detail a detailed error message @param[in] context further context information @return a message string to use in the parse_error exceptions */ - std::string exception_message(const input_format_t format, - const std::string& detail, + std::string exception_message(const std::string& detail, const std::string& context) const { std::string error_msg = "syntax error while parsing "; - switch (format) + switch (input_format) { case input_format_t::cbor: error_msg += "CBOR"; diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 052bc4de9..361baa642 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -2021,6 +2021,39 @@ scan_number_done: // read the next character and ignore whitespace skip_whitespace(); + return scan_after_whitespace(); + } + + /*! + @brief scan the next token when the caller expects a separator (':' or + ',') most of the time + + After an object key the next token is almost always ':', after a value + inside an object or array almost always ','. Testing for that character + first is a compare and a well-predicted branch, where the switch in + scan_after_whitespace() is an indirect jump through a table. Anything else + goes through the switch, so the result is the same as scan()'s. + + May only be called after scan() has run once (the BOM check is skipped). + */ + token_type scan_expecting(token_type expected_type) + { + JSON_ASSERT(expected_type == token_type::name_separator || expected_type == token_type::value_separator); + JSON_ASSERT(position.chars_read_total > 0); + const char_int_type expected_char = static_cast((expected_type == token_type::name_separator) ? ':' : ','); + skip_whitespace(); + if (JSON_HEDLEY_LIKELY(current == expected_char)) + { + return expected_type; + } + return scan_after_whitespace(); + } + + private: + /// the part of scan() after the leading whitespace: skip comments and + /// scan the token that starts with current + token_type scan_after_whitespace() + { // ignore comments while (ignore_comments && current == '/') { @@ -2100,7 +2133,6 @@ scan_number_done: } } - private: /// input adapter InputAdapterType ia; diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 7998dc6dd..aa2b30fd7 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -260,7 +260,7 @@ class parser } // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator))) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -423,7 +423,7 @@ class parser { // comma -> next value // or end of array (ignore_trailing_commas = true) - if (get_token() == token_type::value_separator) + if (get_token_expecting(token_type::value_separator)) { // parse a new value get_token(); @@ -463,7 +463,7 @@ class parser // comma -> next value // or end of object (ignore_trailing_commas = true) - if (get_token() == token_type::value_separator) + if (get_token_expecting(token_type::value_separator)) { get_token(); @@ -484,7 +484,7 @@ class parser } // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator))) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -528,6 +528,13 @@ class parser return last_token = m_lexer.scan(); } + /// get next token from lexer; true if it is the separator @a expected_type + /// (name_separator or value_separator), which it usually is + bool get_token_expecting(token_type expected_type) + { + return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type; + } + std::string exception_message(const token_type expected, const std::string& context) { std::string error_msg = "syntax error "; diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 29d601e93..c59687709 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -81,9 +81,13 @@ class json_pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/ JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) operator string_t() const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return to_string(); } +#endif #ifndef JSON_NO_IO /// @brief write string representation of the JSON pointer to stream @@ -1026,9 +1030,13 @@ class json_pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) bool operator==(const string_t& rhs) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return *this == json_pointer(rhs); } +#endif /// @brief 3-way compares two JSON pointers template @@ -1106,18 +1114,26 @@ template& lhs, const StringType& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return lhs == json_pointer(rhs); } +#endif template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) inline bool operator==(const StringType& lhs, const json_pointer& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return json_pointer(lhs) == rhs; } +#endif template inline bool operator!=(const json_pointer& lhs, @@ -1131,18 +1147,26 @@ template& lhs, const StringType& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return !(lhs == rhs); } +#endif template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) inline bool operator!=(const StringType& lhs, const json_pointer& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return !(lhs == rhs); } +#endif template inline bool operator<(const json_pointer& lhs, diff --git a/include/nlohmann/detail/json_ref.hpp b/include/nlohmann/detail/json_ref.hpp index 0d52b0a62..b270c9c54 100644 --- a/include/nlohmann/detail/json_ref.hpp +++ b/include/nlohmann/detail/json_ref.hpp @@ -34,6 +34,7 @@ class json_ref json_ref(std::initializer_list init) : owned_value(init) + , braced_list(true) {} template < @@ -69,9 +70,17 @@ class json_ref return &** this; } + /// whether the value was written as a braced list, such as {"key", 1}, + /// rather than given as a value + bool is_braced_list() const noexcept + { + return braced_list; + } + private: mutable value_type owned_value = nullptr; value_type const* value_ref = nullptr; + bool braced_list = false; }; } // namespace detail diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 17118927c..1a847e1a9 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -888,6 +888,10 @@ #define JSON_DISABLE_ENUM_SERIALIZATION 0 #endif +#ifndef JSON_DELETE_DEPRECATED_FUNCTIONS + #define JSON_DELETE_DEPRECATED_FUNCTIONS 0 +#endif + #ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 #endif diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 55b2ac99e..494cba0d8 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -43,6 +43,8 @@ #undef JSON_PRECISE_STREAM_POSITION #undef JSON_STRICT_NUL_HANDLING #undef JSON_STRICT_BINARY_UTF8 + #undef JSON_DELETE_DEPRECATED_FUNCTIONS + #undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS #endif #include diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 68bf4ad2c..4c90c68a3 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -438,6 +438,30 @@ template struct is_compatible_object_type : is_compatible_object_type_impl {}; +template +using insert_result_t = decltype(std::declval().insert(std::declval&>())); + +template +using insert_result_second_t = decltype(std::declval().insert(std::declval&>()).second); + +// a map-like type (std::map, std::unordered_map, ...) whose keys are enums; see +// JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +template +struct is_enum_keyed_map : std::false_type {}; + +template +struct is_enum_keyed_map < + T, enable_if_t < is_detected::value&& + is_detected::value >> +{ + // maps with non-unique keys (std::multimap, std::unordered_multimap, ...) + // are excluded, because an object cannot hold duplicate keys; they are + // detected by insert() returning an iterator instead of a pair + // NOLINTNEXTLINE(modernize-type-traits) we use C++11 + static constexpr bool value = std::is_enum::value && + !(is_detected::value && !is_detected::value); +}; + template struct is_constructible_object_type_impl : std::false_type {}; @@ -882,6 +906,21 @@ T conditional_static_cast(U value) return value; } +// like conditional_static_cast, but converts to bool by comparing with zero, +// because MSVC 2015 warns about any conversion to bool (C4800), even with an +// explicit cast; used for enums whose underlying type is bool +template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > +T bool_aware_static_cast(U value) +{ + return conditional_static_cast(value); +} + +template::value, int> = 0> +bool bool_aware_static_cast(U value) +{ + return value != U(); +} + template using all_integral = conjunction...>; diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index a4921f217..1cb64f08d 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,7 @@ class binary_writer @throw type_error.316 if a string value or an object key is not valid UTF-8 @throw type_error.317 if @a j is not an object + @throw type_error.321 if a value nested in @a j is discarded */ void write_bson(const BasicJsonType& j) { @@ -155,12 +157,30 @@ class binary_writer } /*! - @param[in] j JSON value to serialize + @param[in] j JSON value to serialize + @param[in] depth nesting level of @a j, counted from the top-level value + passed to @ref basic_json::to_cbor @throw type_error.316 if a string value or an object key is not valid UTF-8 + @throw type_error.321 if @a j or a value nested in it is discarded + + Serializing a container descends into its elements, so a value nested deeply + enough used to exhaust the call stack and terminate the process with no + exception to catch. The descent is bounded here: once @ref recursion_depth_limit + levels have been entered, @ref write_cbor_iterative writes out what is left + without the call stack. A value nested less deeply than that - all but a + vanishing minority - is written by exactly the code that always wrote it. + + @sa https://github.com/nlohmann/json/issues/5392 */ - void write_cbor(const BasicJsonType& j) + void write_cbor(const BasicJsonType& j, const std::size_t depth = 0) { + if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object())) + { + write_cbor_iterative(j); + return; + } + switch (j.type()) { case value_t::null: @@ -242,10 +262,9 @@ class binary_writer // step 1: write control byte and the array size write_cbor_head(0x80, j.m_data.m_value.array->size()); - // step 2: write each element for (const auto& el : *j.m_data.m_value.array) { - write_cbor(el); + write_cbor(el, depth + 1); } break; } @@ -300,7 +319,6 @@ class binary_writer // step 1: write control byte and the object size write_cbor_head(0xA0, j.m_data.m_value.object->size()); - // step 2: write each element for (const auto& el : *j.m_data.m_value.object) { // el.first is checked here, against the object as @@ -315,14 +333,14 @@ class binary_writer check_utf8(el.first, j); } write_cbor(el.first); - write_cbor(el.second); + write_cbor(el.second, depth + 1); } break; } case value_t::discarded: default: - break; + throw_on_discarded(j, "CBOR"); } } @@ -381,10 +399,22 @@ class binary_writer } /*! - @param[in] j JSON value to serialize + @param[in] j JSON value to serialize + @param[in] depth nesting level of @a j, counted from the top-level value + passed to @ref basic_json::to_msgpack + @throw type_error.321 if @a j or a value nested in it is discarded + + @sa @ref write_cbor + @sa https://github.com/nlohmann/json/issues/5392 */ - void write_msgpack(const BasicJsonType& j) + void write_msgpack(const BasicJsonType& j, const std::size_t depth = 0) { + if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object())) + { + write_msgpack_iterative(j); + return; + } + switch (j.type()) { case value_t::null: // nil @@ -500,29 +530,11 @@ class binary_writer case value_t::array: { // step 1: write control byte and the array size - const auto N = to_msgpack_length(j.m_data.m_value.array->size(), j); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // array 16 - oa.write_character(to_char_type(0xDC)); - write_number(static_cast(N)); - } - else - { - // array 32 - oa.write_character(to_char_type(0xDD)); - write_number(static_cast(N)); - } + write_msgpack_array_prefix(j.m_data.m_value.array->size(), j); - // step 2: write each element for (const auto& el : *j.m_data.m_value.array) { - write_msgpack(el); + write_msgpack(el, depth + 1); } break; } @@ -618,26 +630,8 @@ class binary_writer case value_t::object: { // step 1: write control byte and the object size - const auto N = to_msgpack_length(j.m_data.m_value.object->size(), j); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xF))); - } - else if (N <= (std::numeric_limits::max)()) - { - // map 16 - oa.write_character(to_char_type(0xDE)); - write_number(static_cast(N)); - } - else - { - // map 32 - oa.write_character(to_char_type(0xDF)); - write_number(static_cast(N)); - } + write_msgpack_object_prefix(j.m_data.m_value.object->size(), j); - // step 2: write each element for (const auto& el : *j.m_data.m_value.object) { // as in write_cbor, el.first is checked here against the @@ -648,14 +642,14 @@ class binary_writer check_utf8(el.first, j); } write_msgpack(el.first); - write_msgpack(el.second); + write_msgpack(el.second, depth + 1); } break; } case value_t::discarded: default: - break; + throw_on_discarded(j, "MessagePack"); } } @@ -666,13 +660,26 @@ class binary_writer @param[in] add_prefix whether prefixes need to be used for this value @param[in] use_bjdata whether write in BJData format, default is false @param[in] bjdata_version which BJData version to use, default is draft2 + @param[in] depth nesting level of @a j, counted from the top-level value + passed to @ref basic_json::to_ubjson or @ref basic_json::to_bjdata @throw type_error.316 if a string value or an object key is not valid UTF-8 + @throw type_error.321 if @a j or a value nested in it is discarded + + @sa @ref write_cbor + @sa https://github.com/nlohmann/json/issues/5392 */ void write_ubjson(const BasicJsonType& j, const bool use_count, const bool use_type, const bool add_prefix = true, - const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2) + const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2, + const std::size_t depth = 0) { + if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object())) + { + write_ubjson_iterative(j, use_count, use_type, add_prefix, use_bjdata, bjdata_version); + return; + } + const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3; switch (j.type()) @@ -733,55 +740,15 @@ class binary_writer case value_t::array: { - if (add_prefix) - { - oa.write_character(to_char_type('[')); - } - bool prefix_required = true; - if (use_type && !j.m_data.m_value.array->empty()) - { - if (!use_count) - { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); - } - const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); - const bool same_prefix = std::all_of(j.begin() + 1, j.end(), - [this, first_prefix, use_bjdata](const BasicJsonType & v) - { - return ubjson_prefix(v, use_bjdata) == first_prefix; - }); - - // an optimized array of a valueless type carries no payload, so a - // reader has nothing but the declared count to bound the allocation - // by and refuses an excessive one. Write the unoptimized form for - // those, at one byte per element, so the result can be read back. - // Objects are not affected: every element is preceded by its key. - const bool valueless_type = (first_prefix == 'Z' || first_prefix == 'T' || first_prefix == 'F'); - const bool excessive_valueless = valueless_type - && j.m_data.m_value.array->size() > detail::max_valueless_container_size; - - if (same_prefix && !excessive_valueless - && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) - { - prefix_required = false; - oa.write_character(to_char_type('$')); - oa.write_character(first_prefix); - } - } - - if (use_count) - { - oa.write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata); - } + const bool write_closer = write_ubjson_start_array(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); for (const auto& el : *j.m_data.m_value.array) { - write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version); + write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1); } - if (!use_count) + if (write_closer) { oa.write_character(to_char_type(']')); } @@ -839,7 +806,7 @@ class binary_writer case value_t::object: { - if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end()) + if (use_bjdata && is_bjdata_ndarray(j)) { if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) { @@ -847,38 +814,8 @@ class binary_writer } } - if (add_prefix) - { - oa.write_character(to_char_type('{')); - } - bool prefix_required = true; - if (use_type && !j.m_data.m_value.object->empty()) - { - if (!use_count) - { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); - } - const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); - const bool same_prefix = std::all_of(j.begin(), j.end(), - [this, first_prefix, use_bjdata](const BasicJsonType & v) - { - return ubjson_prefix(v, use_bjdata) == first_prefix; - }); - - if (same_prefix && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) - { - prefix_required = false; - oa.write_character(to_char_type('$')); - oa.write_character(first_prefix); - } - } - - if (use_count) - { - oa.write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata); - } + const bool write_closer = write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); for (const auto& el : *j.m_data.m_value.object) { @@ -888,10 +825,10 @@ class binary_writer oa.write_characters( reinterpret_cast(key.data()), key.size()); - write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version); + write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1); } - if (!use_count) + if (write_closer) { oa.write_character(to_char_type('}')); } @@ -901,7 +838,7 @@ class binary_writer case value_t::discarded: default: - break; + throw_on_discarded(j, use_bjdata ? "BJData" : "UBJSON"); } } @@ -921,6 +858,528 @@ class binary_writer } private: + /*! + @brief throws because @a j is discarded and cannot be serialized + @throw type_error.321 always + */ + JSON_HEDLEY_NO_RETURN static void throw_on_discarded(const BasicJsonType& j, const char* format_name) + { + static_cast(j); // unused when JSON_NOEXCEPTION is defined + static_cast(format_name); + JSON_THROW(type_error::create(321, concat("cannot serialize discarded value to ", format_name), &j)); + } + + void write_msgpack_array_prefix(const std::size_t N, const BasicJsonType& j) + { + const auto n = to_msgpack_length(N, j); + if (n <= 15) + { + // fixarray + write_number(static_cast(0x90 | n)); + } + else if (n <= (std::numeric_limits::max)()) + { + // array 16 + oa.write_character(to_char_type(0xDC)); + write_number(static_cast(n)); + } + else + { + // array 32 + oa.write_character(to_char_type(0xDD)); + write_number(static_cast(n)); + } + } + + void write_msgpack_object_prefix(const std::size_t N, const BasicJsonType& j) + { + const auto n = to_msgpack_length(N, j); + if (n <= 15) + { + // fixmap + write_number(static_cast(0x80 | (n & 0xF))); + } + else if (n <= (std::numeric_limits::max)()) + { + // map 16 + oa.write_character(to_char_type(0xDE)); + write_number(static_cast(n)); + } + else + { + // map 32 + oa.write_character(to_char_type(0xDF)); + write_number(static_cast(n)); + } + } + + /// @brief a CBOR or MessagePack array or object whose elements + /// @ref write_cbor_iterative or @ref write_msgpack_iterative is + /// still writing + struct binary_container_frame + { + explicit binary_container_frame(const BasicJsonType* value_) noexcept + : value(value_) + { + if (value->is_object()) + { + object_it = value->m_data.m_value.object->cbegin(); + } + else + { + array_it = value->m_data.m_value.array->cbegin(); + } + } + + // declared for GCC's -Weffc++, which asks for them in a class with + // pointer members and a non-trivial destructor; the exception + // specifications are left implicit, as GCC 4.8 rejects explicit ones + // that differ from them + binary_container_frame(const binary_container_frame&) = default; + binary_container_frame(binary_container_frame&&) = default; + binary_container_frame& operator=(const binary_container_frame&) = default; + binary_container_frame& operator=(binary_container_frame&&) = default; + ~binary_container_frame() = default; + + /// the array or object being written + const BasicJsonType* value; + /// value's elements still to write; which of the two is live follows + /// from the type of value. They are kept side by side rather than in + /// a union, which would need its special members written out by + /// hand, see detail/iterators/internal_iterator.hpp + typename BasicJsonType::object_t::const_iterator object_it{}; + typename BasicJsonType::array_t::const_iterator array_it{}; + }; + + /*! + @brief write @a j with @ref write_cbor, or write its header and push a + frame for @ref write_cbor_iterative to continue with its elements + + A scalar, and an empty array or object, are written out in full: there is + nothing below them for @ref write_cbor_iterative to come back to, so + nothing is pushed for them. + */ + void write_cbor_value_or_push(const BasicJsonType& j, std::vector& stack) + { + if (j.is_array()) + { + write_cbor_head(0x80, j.m_data.m_value.array->size()); + if (!j.m_data.m_value.array->empty()) + { + stack.emplace_back(&j); + } + return; + } + + if (j.is_object()) + { + write_cbor_head(0xA0, j.m_data.m_value.object->size()); + if (!j.m_data.m_value.object->empty()) + { + stack.emplace_back(&j); + } + return; + } + + write_cbor(j); + } + + /*! + @brief write out @a root and everything below it without the call stack + + Emits the same bytes as @ref write_cbor, keeping the containers it has + entered on an explicit stack instead of descending into them. Only reached + for values nested deeper than @ref recursion_depth_limit, which is why it + is not written for speed. + */ + void write_cbor_iterative(const BasicJsonType& root) + { + // only a container with elements is ever pushed; see write_cbor_value_or_push + std::vector stack; + write_cbor_value_or_push(root, stack); + + while (!stack.empty()) + { + const binary_container_frame current = stack.back(); + + if (current.value->is_array()) + { + const auto& array = *current.value->m_data.m_value.array; + if (current.array_it == array.cend()) + { + stack.pop_back(); + continue; + } + + // read the child before pushing: entering it can move every frame + const BasicJsonType* child = &(*current.array_it); + ++stack.back().array_it; + write_cbor_value_or_push(*child, stack); + } + else + { + const auto& object = *current.value->m_data.m_value.object; + if (current.object_it == object.cend()) + { + stack.pop_back(); + continue; + } + + // el.first is checked here, against the object as diagnostics + // context, like the matching check in write_cbor's object case + if (error_handler == error_handler_t::strict) + { + check_utf8(current.object_it->first, *current.value); + } + write_cbor(current.object_it->first); + const BasicJsonType* child = &(current.object_it->second); + ++stack.back().object_it; + write_cbor_value_or_push(*child, stack); + } + } + } + + /*! + @brief write @a j with @ref write_msgpack, or write its header and push a + frame for @ref write_msgpack_iterative to continue with its elements + + @sa @ref write_cbor_value_or_push + */ + void write_msgpack_value_or_push(const BasicJsonType& j, std::vector& stack) + { + if (j.is_array()) + { + write_msgpack_array_prefix(j.m_data.m_value.array->size(), j); + if (!j.m_data.m_value.array->empty()) + { + stack.emplace_back(&j); + } + return; + } + + if (j.is_object()) + { + write_msgpack_object_prefix(j.m_data.m_value.object->size(), j); + if (!j.m_data.m_value.object->empty()) + { + stack.emplace_back(&j); + } + return; + } + + write_msgpack(j); + } + + /*! + @brief write out @a root and everything below it without the call stack + + @sa @ref write_cbor_iterative + */ + void write_msgpack_iterative(const BasicJsonType& root) + { + std::vector stack; + write_msgpack_value_or_push(root, stack); + + while (!stack.empty()) + { + const binary_container_frame current = stack.back(); + + if (current.value->is_array()) + { + const auto& array = *current.value->m_data.m_value.array; + if (current.array_it == array.cend()) + { + stack.pop_back(); + continue; + } + + const BasicJsonType* child = &(*current.array_it); + ++stack.back().array_it; + write_msgpack_value_or_push(*child, stack); + } + else + { + const auto& object = *current.value->m_data.m_value.object; + if (current.object_it == object.cend()) + { + stack.pop_back(); + continue; + } + + if (error_handler == error_handler_t::strict) + { + check_utf8(current.object_it->first, *current.value); + } + write_msgpack(current.object_it->first); + const BasicJsonType* child = &(current.object_it->second); + ++stack.back().object_it; + write_msgpack_value_or_push(*child, stack); + } + } + } + + /// @return true when a closing ']' still has to be written after the elements + bool write_ubjson_start_array(const BasicJsonType& j, const bool use_count, const bool use_type, + const bool add_prefix, const bool use_bjdata, bool& prefix_required) + { + prefix_required = true; + if (add_prefix) + { + oa.write_character(to_char_type('[')); + } + + if (use_type && !j.m_data.m_value.array->empty()) + { + if (!use_count) + { + JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + } + const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix, use_bjdata](const BasicJsonType & v) + { + return ubjson_prefix(v, use_bjdata) == first_prefix; + }); + + // an optimized array of a valueless type carries no payload, so a + // reader has nothing but the declared count to bound the allocation + // by and refuses an excessive one. Write the unoptimized form for + // those, at one byte per element, so the result can be read back. + // Objects are not affected: every element is preceded by its key. + const bool valueless_type = (first_prefix == 'Z' || first_prefix == 'T' || first_prefix == 'F'); + const bool excessive_valueless = valueless_type + && j.m_data.m_value.array->size() > detail::max_valueless_container_size; + + if (same_prefix && !excessive_valueless + && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) + { + prefix_required = false; + oa.write_character(to_char_type('$')); + oa.write_character(first_prefix); + } + } + + if (use_count) + { + oa.write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata); + } + + return !use_count; + } + + /// @return true when a closing '}' still has to be written after the elements + bool write_ubjson_start_object(const BasicJsonType& j, const bool use_count, const bool use_type, + const bool add_prefix, const bool use_bjdata, bool& prefix_required) + { + prefix_required = true; + if (add_prefix) + { + oa.write_character(to_char_type('{')); + } + + if (use_type && !j.m_data.m_value.object->empty()) + { + if (!use_count) + { + JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + } + const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix, use_bjdata](const BasicJsonType & v) + { + return ubjson_prefix(v, use_bjdata) == first_prefix; + }); + + if (same_prefix && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) + { + prefix_required = false; + oa.write_character(to_char_type('$')); + oa.write_character(first_prefix); + } + } + + if (use_count) + { + oa.write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata); + } + + return !use_count; + } + + /*! + @brief whether @a j is a BJData ND-array annotation object + (https://github.com/NeuroJSON/jdata) + + Used by both the recursive object case of @ref write_ubjson and + @ref write_ubjson_value_or_push, which must agree on what counts as an + ND-array: @a j is only actually written as one once @ref + write_bjdata_ndarray has also accepted its contents. + + @pre @a j.is_object() + */ + static bool is_bjdata_ndarray(const BasicJsonType& j) + { + const auto& object = *j.m_data.m_value.object; + return object.size() == 3 + && object.find("_ArrayType_") != object.end() + && object.find("_ArraySize_") != object.end() + && object.find("_ArrayData_") != object.end(); + } + + /// @brief an object or array @ref write_ubjson_iterative is still writing + /// the elements of + struct ubjson_frame + { + ubjson_frame(const BasicJsonType* value_, const bool prefix_required_) noexcept + : value(value_) + , prefix_required(prefix_required_) + { + if (value->is_object()) + { + object_it = value->m_data.m_value.object->cbegin(); + } + else + { + array_it = value->m_data.m_value.array->cbegin(); + } + } + + // declared for GCC's -Weffc++, which asks for them in a class with + // pointer members and a non-trivial destructor; the exception + // specifications are left implicit, as GCC 4.8 rejects explicit ones + // that differ from them + ubjson_frame(const ubjson_frame&) = default; + ubjson_frame(ubjson_frame&&) = default; + ubjson_frame& operator=(const ubjson_frame&) = default; + ubjson_frame& operator=(ubjson_frame&&) = default; + ~ubjson_frame() = default; + + /// the array or object being written + const BasicJsonType* value; + /// whether value's elements each carry their own type marker; an + /// optimized ($type) container writes it once for all of them instead + bool prefix_required; + typename BasicJsonType::object_t::const_iterator object_it{}; + typename BasicJsonType::array_t::const_iterator array_it{}; + }; + + /*! + @brief write @a j with @ref write_ubjson, or write its header and push a + frame for @ref write_ubjson_iterative to continue with its elements + + @param[in] add_prefix whether @a j's own type marker is written now (the + elements of an optimized container, and everything below the + top level, never repeat it) + + @sa @ref write_cbor_value_or_push + */ + void write_ubjson_value_or_push(const BasicJsonType& j, const bool add_prefix, const bool use_count, + const bool use_type, const bool use_bjdata, const bjdata_version_t bjdata_version, + std::vector& stack) + { + if (!j.is_array() && !j.is_object()) + { + write_ubjson(j, use_count, use_type, add_prefix, use_bjdata, bjdata_version); + return; + } + + if (use_bjdata && j.is_object() && is_bjdata_ndarray(j) + && !write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) + { + // fully written as an ND-array: nothing below it to come back to + return; + } + + const bool is_array = j.is_array(); + bool prefix_required = true; + if (is_array) + { + write_ubjson_start_array(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); + } + else + { + write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); + } + + const bool empty = is_array ? j.m_data.m_value.array->empty() : j.m_data.m_value.object->empty(); + if (!empty) + { + stack.emplace_back(&j, prefix_required); + return; + } + + // write_ubjson_start_array/_object return !use_count, i.e. whether a + // closer still has to be written; use_count is constant for the whole + // document, so that is recomputed here instead of being carried along + if (!use_count) + { + oa.write_character(to_char_type(is_array ? ']' : '}')); + } + } + + /*! + @brief write out @a root and everything below it without the call stack + + @sa @ref write_cbor_iterative + */ + void write_ubjson_iterative(const BasicJsonType& root, const bool use_count, const bool use_type, + const bool add_prefix, const bool use_bjdata, const bjdata_version_t bjdata_version) + { + std::vector stack; + write_ubjson_value_or_push(root, add_prefix, use_count, use_type, use_bjdata, bjdata_version, stack); + + while (!stack.empty()) + { + const ubjson_frame current = stack.back(); + const BasicJsonType& j = *current.value; + + if (j.is_array()) + { + const auto& array = *j.m_data.m_value.array; + if (current.array_it == array.cend()) + { + if (!use_count) + { + oa.write_character(to_char_type(']')); + } + stack.pop_back(); + continue; + } + + const BasicJsonType* child = &(*current.array_it); + const bool child_prefix = current.prefix_required; + ++stack.back().array_it; + write_ubjson_value_or_push(*child, child_prefix, use_count, use_type, use_bjdata, bjdata_version, stack); + } + else + { + const auto& object = *j.m_data.m_value.object; + if (current.object_it == object.cend()) + { + if (!use_count) + { + oa.write_character(to_char_type('}')); + } + stack.pop_back(); + continue; + } + + string_t storage; + const string_t& key = sanitize_utf8_for_write(current.object_it->first, j, storage); + write_number_with_ubjson_prefix(key.size(), true, use_bjdata); + oa.write_characters( + reinterpret_cast(key.data()), + key.size()); + const BasicJsonType* child = &(current.object_it->second); + const bool child_prefix = current.prefix_required; + ++stack.back().object_it; + write_ubjson_value_or_push(*child, child_prefix, use_count, use_type, use_bjdata, bjdata_version, stack); + } + } + } + ////////// // BSON // ////////// @@ -1172,6 +1631,7 @@ class binary_writer into a byte, before anything is written @throw type_error.316 if @a j is a string that is not valid UTF-8, before anything is written + @throw type_error.321 if @a j is discarded */ std::size_t calc_bson_value_size(const BasicJsonType& j) { @@ -1198,10 +1658,12 @@ class binary_writer case value_t::null: return 0ul; + case value_t::discarded: + throw_on_discarded(j, "BSON"); + // LCOV_EXCL_START case value_t::object: case value_t::array: - case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return 0ul; @@ -1238,10 +1700,12 @@ class binary_writer case value_t::null: return write_bson_null(name); + case value_t::discarded: + throw_on_discarded(j, "BSON"); + // LCOV_EXCL_START case value_t::object: case value_t::array: - case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return; @@ -1308,6 +1772,8 @@ class binary_writer byte, before anything is written @throw type_error.316 if a string value or a key is not valid UTF-8, before anything is written + @throw type_error.321 if a value nested in @a document is discarded, + before anything is written */ std::size_t calc_bson_sizes(const BasicJsonType& document, std::vector& nested_sizes) { @@ -1817,16 +2283,31 @@ class binary_writer /*! @brief validate (dry_run) or write one BJData ND-array element of dtype 'd' (single precision) - @return whether @a el's value fits a float without overflow; always true when @a dry_run is false + @return whether @a el's value survives narrowing to float and back without any change + (so the ND-array round-trips exactly), or is infinite or NaN; always true when + @a dry_run is false */ bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run) { const auto dval = el.template get(); if (dry_run) { - return !std::isfinite(dval) || - (dval >= static_cast(std::numeric_limits::lowest()) && - dval <= static_cast((std::numeric_limits::max)())); +#ifdef __GNUC__ + JSON_HEDLEY_DIAGNOSTIC_PUSH + JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal") +#endif + // a value that would be rounded (rather than exactly represented) by the + // narrowing to float is treated like an out-of-range integer element; this + // is the same criterion write_compact_float() uses for CBOR/MessagePack + const bool in_range = std::isnan(dval) || + (dval >= static_cast(std::numeric_limits::lowest()) && + dval <= static_cast((std::numeric_limits::max)()) && + static_cast(static_cast(dval)) == dval) || + std::isinf(dval); +#ifdef __GNUC__ + JSON_HEDLEY_DIAGNOSTIC_POP +#endif + return in_range; } write_number(static_cast(dval), true); return true; diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 3f3645524..9c89ab0bc 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -226,6 +226,70 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// SAX interface type, see @ref nlohmann::json_sax using json_sax_t = json_sax; + //////////////////////////////////////////////////////////////////////////////// + // utility templates to create a json type with different template parameters // + //////////////////////////////////////////////////////////////////////////////// + + /// Json type using a different type for storing objects + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class ObjectType2> + using with_object_t = basic_json; + + /// Json type using a different type for storing arrays + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class ArrayType2> + using with_array_t = basic_json; + + /// Json type using a different type for storing strings + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_string_t = basic_json; + + /// Json type using a different type for storing booleans + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_boolean_t = basic_json; + + /// Json type using different types for storing signed and unsigned integers + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_integers_t = basic_json; + + /// Json type using a different type for storing floating point numbers + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_float_t = basic_json; + + /// Json type using a different type as base allocator + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class AllocatorType2> + using with_allocator_t = basic_json; + + /// Json type using a different type as json serializer + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class JSONSerializer2> + using with_json_serializer_t = basic_json; + + /// Json type using a different type for storing binary data + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_binary_t = basic_json; + + /// Json type using a different type as base class + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_base_class_t = basic_json; + //////////////// // exceptions // //////////////// @@ -612,100 +676,252 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// constructor for rvalue binary arrays (internal type) json_value(binary_t&& value) : binary(create(std::move(value))) {} - void destroy(value_t t) + /// constructors taking ownership of an already created value + explicit json_value(string_t* value) noexcept : string(value) {} + explicit json_value(object_t* value) noexcept : object(value) {} + explicit json_value(array_t* value) noexcept : array(value) {} + +private: + // raw, allocation-free transfer of m_data from src to dst: no + // set_parents()/assert_invariant() (the former is O(#children) per + // call under JSON_DIAGNOSTICS, which would make the walk below + // quadratic); dst takes ownership, src is left as value_t::null. + static void take(basic_json& dst, basic_json& src) noexcept + { + dst.m_data.m_type = src.m_data.m_type; + dst.m_data.m_value = src.m_data.m_value; + src.m_data.m_type = value_t::null; + } + + // true if v is not an array/object, or is an already-empty one + static bool has_no_children(const basic_json& v) noexcept + { + switch (v.m_data.m_type) + { + case value_t::array: + return v.m_data.m_value.array->empty(); + case value_t::object: + return v.m_data.m_value.object->empty(); + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return true; + } + } + + // The walk in destroy_container() may take the children of a + // container in any order, as long as it picks the same child again + // while that container is not modified in between. Arrays and + // objects with bidirectional iterators (std::map, ordered_map, ...) + // use their last child, which a vector-based container can remove + // in O(1). ObjectType only needs forward iterators, though (e.g. + // std::unordered_map), so other objects use their first child. + template + static typename ObjectType_::iterator walk_child_it(ObjectType_& o, std::bidirectional_iterator_tag /*unused*/) + { + return std::prev(o.end()); + } + + template + static typename ObjectType_::iterator walk_child_it(ObjectType_& o, std::forward_iterator_tag /*unused*/) + { + return o.begin(); + } + + template + static typename ObjectType_::iterator walk_child_it(ObjectType_& o) + { + JSON_ASSERT(!o.empty()); + return walk_child_it(o, typename std::iterator_traits::iterator_category()); + } + + // the child of a non-empty array/object v that the walk in + // destroy_container() continues with (see walk_child_it() above) + static basic_json& walk_child(basic_json& v) + { + if (v.m_data.m_type == value_t::array) + { + return v.m_data.m_value.array->back(); + } + JSON_ASSERT(v.m_data.m_type == value_t::object); + return walk_child_it(*v.m_data.m_value.object)->second; + } + + // removes walk_child(v) from a non-empty array/object v; this never + // allocates, and since it is only ever called when that child is a + // scalar or an already-empty array/object, destroying it never + // recurses more than one level deep (see destroy() below) + static void pop_walk_child(basic_json& v) + { + if (v.m_data.m_type == value_t::array) + { + v.m_data.m_value.array->pop_back(); + } + else + { + JSON_ASSERT(v.m_data.m_type == value_t::object); + v.m_data.m_value.object->erase(walk_child_it(*v.m_data.m_value.object)); + } + } + + // deallocates the (already empty) array/object held by v; this is + // the same allocator-based free the old recursive implementation + // used, just factored out so every level of the walk in destroy() + // can share it + static void free_container(basic_json& v) noexcept + { + if (v.m_data.m_type == value_t::array) + { + JSON_ASSERT(v.m_data.m_value.array->empty()); + AllocatorType alloc; + std::allocator_traits::destroy(alloc, v.m_data.m_value.array); + std::allocator_traits::deallocate(alloc, v.m_data.m_value.array, 1); + } + else + { + JSON_ASSERT(v.m_data.m_type == value_t::object); + JSON_ASSERT(v.m_data.m_value.object->empty()); + AllocatorType alloc; + std::allocator_traits::destroy(alloc, v.m_data.m_value.object); + std::allocator_traits::deallocate(alloc, v.m_data.m_value.object, 1); + } + v.m_data.m_type = value_t::null; // avoid a double free if v is later destructed + } + +public: + void destroy_string() noexcept + { + if (string == nullptr) + { + // not initialized (e.g., due to exception in the ctor) + return; + } + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + } + + void destroy_binary() noexcept + { + if (binary == nullptr) + { + // not initialized (e.g., due to exception in the ctor) + return; + } + AllocatorType alloc; + std::allocator_traits::destroy(alloc, binary); + std::allocator_traits::deallocate(alloc, binary, 1); + } + + // t must be value_t::array or value_t::object + void destroy_container(value_t t) noexcept { if ( (t == value_t::object && object == nullptr) || - (t == value_t::array && array == nullptr) || - (t == value_t::string && string == nullptr) || - (t == value_t::binary && binary == nullptr) + (t == value_t::array && array == nullptr) ) { // not initialized (e.g., due to exception in the ctor) return; } - if (t == value_t::array || t == value_t::object) + + // Destroy the tree without recursing per nesting level and + // without any heap allocation: a heap-allocated flattening + // stack (the previous implementation) can itself throw + // bad_alloc, which would escape this noexcept destructor and + // terminate the program (#5135). + // + // Instead, walk down a chain of children (always the one + // walk_child() picks), reversing links as we go: cur is the + // container currently being emptied, and prev is its parent + // (value_t::null when there is none). Each parent's + // walk_child() slot doubles as storage for that parent's own + // parent link while we are below it, so no extra memory is + // needed; the parent is not modified meanwhile, so + // walk_child() finds that same slot again on the way up. We + // only ever remove a child once it is a scalar or an empty + // array/object, which neither allocates nor recurses more + // than one level deep. + // + // This json_value is not itself a basic_json, so the + // top-level container is first moved into a local stand-in + // ("cur"); a default-constructed basic_json has a null + // pointer in its m_value (see data::m_value's initializer), + // so swapping it with *this leaves this union's own pointer + // null, and it is never looked at or freed a second time. + basic_json cur; + cur.m_data.m_type = t; + using std::swap; + swap(cur.m_data.m_value, *this); + + basic_json prev; // value_t::null: no parent + + while (true) { - // flatten the current json_value to a heap-allocated stack - std::vector stack; - - // move the top-level items to stack - if (t == value_t::array) + if (has_no_children(cur)) { - stack.reserve(array->size()); - std::move(array->begin(), array->end(), std::back_inserter(stack)); - } - else - { - stack.reserve(object->size()); - for (auto&& it : *object) + if (prev.m_data.m_type == value_t::null) { - stack.push_back(std::move(it.second)); - } - } - - while (!stack.empty()) - { - // move the last item to a local variable to be processed - basic_json current_item(std::move(stack.back())); - stack.pop_back(); - - // if current_item is array/object, move - // its children to the stack to be processed later - if (current_item.is_array()) - { - std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack)); - - current_item.m_data.m_value.array->clear(); - } - else if (current_item.is_object()) - { - for (auto&& it : *current_item.m_data.m_value.object) - { - stack.push_back(std::move(it.second)); - } - - current_item.m_data.m_value.object->clear(); + free_container(cur); + return; // back at the top with nothing left to do } - // it's now safe that current_item gets destructed - // since it doesn't have any children + // ascend: detach the grandparent link from prev's + // walk_child() slot, drop that (now null) slot, free cur + // (it is empty), then move up one level + basic_json gp; + take(gp, walk_child(prev)); + pop_walk_child(prev); + + free_container(cur); + + take(cur, prev); + take(prev, gp); + continue; } + + basic_json& cur_child_ref = walk_child(cur); + + if (has_no_children(cur_child_ref)) + { + // scalar, or already-empty array/object + pop_walk_child(cur); + continue; + } + + // descend into the non-empty child, reversing the + // link: its slot takes over prev, and the child becomes + // the new cur + basic_json tmp; + take(tmp, cur_child_ref); + take(cur_child_ref, prev); + take(prev, cur); + take(cur, tmp); } + } + void destroy(value_t t) + { switch (t) { - case value_t::object: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, object); - std::allocator_traits::deallocate(alloc, object, 1); - break; - } - - case value_t::array: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, array); - std::allocator_traits::deallocate(alloc, array, 1); - break; - } - case value_t::string: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, string); - std::allocator_traits::deallocate(alloc, string, 1); + destroy_string(); break; - } case value_t::binary: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, binary); - std::allocator_traits::deallocate(alloc, binary, 1); + destroy_binary(); + break; + + case value_t::object: + case value_t::array: + destroy_container(t); break; - } case value_t::null: case value_t::boolean: @@ -714,9 +930,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::number_float: case value_t::discarded: default: - { break; - } } } }; @@ -797,6 +1011,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #endif } + /// @brief replace the stored value with an already created one + /// The new value must be created before calling this function: if its + /// creation throws, the current value is left untouched. + void replace_value(value_t t, const json_value& v) noexcept + { + m_data.m_value.destroy(m_data.m_type); + m_data.m_value = v; + m_data.m_type = t; + set_parents(); + assert_invariant(); + } + iterator set_parents(iterator it, std::ptrdiff_t count_set_parents) { #if JSON_DIAGNOSTICS @@ -2026,6 +2252,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec bool type_deduction = true, value_t manual_type = value_t::array) { +#if JSON_BRACE_INIT_COPY_SEMANTICS + // a single element that is a value rather than a braced list is + // copied or moved as is, whatever its content looks like + if (type_deduction && init.size() == 1 && !init.begin()->is_braced_list()) + { + *this = init.begin()->moved_or_copied(); + set_parents(); + assert_invariant(); + return; + } +#endif + // check if each element is an array with two elements whose first // element is a string bool is_an_object = std::all_of(init.begin(), init.end(), @@ -2056,8 +2294,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (is_an_object) { // the initializer list is a list of pairs -> create an object - m_data.m_type = value_t::object; m_data.m_value = value_t::object; + m_data.m_type = value_t::object; for (auto& element_ref : init) { @@ -2079,8 +2317,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } #endif // the initializer list describes an array -> create an array - m_data.m_type = value_t::array; m_data.m_value.array = create(init.begin(), init.end()); + m_data.m_type = value_t::array; } set_parents(); @@ -2093,8 +2331,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(const typename binary_t::container_type& init) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = init; + res.m_data.m_type = value_t::binary; return res; } @@ -2104,8 +2342,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = binary_t(init, subtype); + res.m_data.m_type = value_t::binary; return res; } @@ -2115,8 +2353,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(typename binary_t::container_type&& init) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = std::move(init); + res.m_data.m_type = value_t::binary; return res; } @@ -2126,8 +2364,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = binary_t(std::move(init), subtype); + res.m_data.m_type = value_t::binary; return res; } @@ -3492,9 +3730,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec && !std::is_same>::value, int > = 0 > JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) ValueType value(const ::nlohmann::json_pointer& ptr, const ValueType& default_value) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return value(ptr.convert(), default_value); } +#endif template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type::type, detail::enable_if_t < @@ -3503,9 +3745,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec && !std::is_same>::value, int > = 0 > JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) ReturnType value(const ::nlohmann::json_pointer& ptr, ValueType && default_value) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return value(ptr.convert(), std::forward(default_value)); } +#endif /// @brief access the first element /// @sa https://json.nlohmann.me/api/basic_json/front/ @@ -3863,9 +4109,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) bool contains(const typename ::nlohmann::json_pointer& ptr) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.contains(this); } +#endif /// @} @@ -3976,9 +4226,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) static iteration_proxy iterator_wrapper(reference ref) noexcept +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ref.items(); } +#endif /// @brief wrapper to access iterator member functions in range-based for /// @sa https://json.nlohmann.me/api/basic_json/items/ @@ -3987,9 +4241,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) static iteration_proxy iterator_wrapper(const_reference ref) noexcept +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ref.items(); } +#endif /// @brief helper to access iterator member functions in range-based for /// @sa https://json.nlohmann.me/api/basic_json/items/ @@ -5078,7 +5336,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template requires std::is_scalar_v - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) <= rhs; } @@ -5087,7 +5345,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template requires std::is_scalar_v - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) >= rhs; } @@ -5108,11 +5366,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #endif } + // The friend comparisons with a scalar name the JSON type via decltype of + // their parameter in noexcept, because older MSVC versions do not see the + // class scope there: MSVC 2015 and 2017 take basic_json as the template, + // and MSVC 2019 16.0 rejects member types and template parameters. + /// @brief comparison: equal /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ template::value, int>::type = 0> - friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs == basic_json(rhs); } @@ -5121,7 +5384,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ template::value, int>::type = 0> - friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) == rhs; } @@ -5137,7 +5400,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ template::value, int>::type = 0> - friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs != basic_json(rhs); } @@ -5146,7 +5409,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ template::value, int>::type = 0> - friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) != rhs; } @@ -5166,7 +5429,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ template::value, int>::type = 0> - friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs < basic_json(rhs); } @@ -5175,7 +5438,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ template::value, int>::type = 0> - friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) < rhs; } @@ -5195,7 +5458,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template::value, int>::type = 0> - friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs <= basic_json(rhs); } @@ -5204,7 +5467,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template::value, int>::type = 0> - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) <= rhs; } @@ -5225,7 +5488,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ template::value, int>::type = 0> - friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs > basic_json(rhs); } @@ -5234,7 +5497,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ template::value, int>::type = 0> - friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) > rhs; } @@ -5254,7 +5517,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template::value, int>::type = 0> - friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs >= basic_json(rhs); } @@ -5263,7 +5526,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template::value, int>::type = 0> - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) >= rhs; } @@ -5299,6 +5562,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return o; } +#if !JSON_DELETE_DEPRECATED_FUNCTIONS + // the deleted version is a function template after the class, because + // GCC < 5 and Clang < 10 reject deleted friend functions in class templates /// @brief serialize to stream /// @sa https://json.nlohmann.me/api/operator_ltlt/ /// @deprecated This function is deprecated since 3.0.0 and will be removed in @@ -5310,6 +5576,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { return o << j; } +#endif #endif // JSON_NO_IO /// @} @@ -5361,12 +5628,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true, const bool ignore_comments = false, const bool ignore_trailing_commas = false) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { basic_json result; auto p = parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas); p.parse(true, result); return result; } +#endif /// @brief check if the input is valid JSON /// @sa https://json.nlohmann.me/api/basic_json/accept/ @@ -5396,9 +5667,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool accept(detail::span_input_adapter&& i, const bool ignore_comments = false, const bool ignore_trailing_commas = false) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true); } +#endif /// @brief generate SAX events /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ @@ -5408,12 +5683,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false) + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { auto ia = detail::input_adapter(std::forward(i)); return format == input_format_t::json ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) - : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict); + : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict, tag_handler); } /// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support) @@ -5425,12 +5701,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false) + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { auto ia = detail::input_adapter(std::move(first), std::move(last)); return format == input_format_t::json ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) - : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict); + : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict, tag_handler); } /// @brief generate SAX events @@ -5458,19 +5735,27 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false) + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { auto ia = i.get(); return format == input_format_t::json // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict); + : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict, tag_handler); } +#endif #if defined(__clang__) #pragma clang diagnostic pop #endif #ifndef JSON_NO_IO +#if !JSON_DELETE_DEPRECATED_FUNCTIONS + // the deleted version is a function template after the class, because + // GCC < 5 and Clang < 10 reject deleted friend functions in class templates /// @brief deserialize from stream /// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in @@ -5482,6 +5767,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { return operator>>(i, j); } +#endif /// @brief deserialize from stream /// @sa https://json.nlohmann.me/api/operator_gtgt/ @@ -5829,9 +6115,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) @@ -5839,9 +6129,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler); } +#endif /// @brief create a JSON value from an input in MessagePack format /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ @@ -5874,18 +6168,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json from_msgpack(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_msgpack(ptr, ptr + len, strict, allow_exceptions); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions); } +#endif /// @brief create a JSON value from an input in UBJSON format /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ @@ -5918,18 +6220,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json from_ubjson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_ubjson(ptr, ptr + len, strict, allow_exceptions); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions); } +#endif /// @brief create a JSON value from an input in BJData format /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ @@ -5956,6 +6266,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len)) + static basic_json from_bjdata(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else + { + return from_bjdata(ptr, ptr + len, strict, allow_exceptions); + } +#endif + /// @brief create a JSON value from an input in BON8 format /// @sa https://json.nlohmann.me/api/basic_json/from_bon8/ template @@ -5979,6 +6303,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len)) + static basic_json from_bon8(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else + { + return from_bon8(ptr, ptr + len, strict, allow_exceptions); + } +#endif + /// @brief create a JSON value from an input in BSON format /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ template @@ -6010,18 +6348,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json from_bson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_bson(ptr, ptr + len, strict, allow_exceptions); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions); } +#endif /// @} ////////////////////////// @@ -6041,9 +6387,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) reference operator[](const ::nlohmann::json_pointer& ptr) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_unchecked(this); } +#endif /// @brief access specified element via JSON Pointer /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ @@ -6055,9 +6405,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) const_reference operator[](const ::nlohmann::json_pointer& ptr) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_unchecked(this); } +#endif /// @brief access specified element via JSON Pointer /// @sa https://json.nlohmann.me/api/basic_json/at/ @@ -6069,9 +6423,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) reference at(const ::nlohmann::json_pointer& ptr) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_checked(this); } +#endif /// @brief access specified element via JSON Pointer /// @sa https://json.nlohmann.me/api/basic_json/at/ @@ -6083,9 +6441,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) const_reference at(const ::nlohmann::json_pointer& ptr) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_checked(this); } +#endif /// @brief return flattened JSON value /// @sa https://json.nlohmann.me/api/basic_json/flatten/ @@ -7062,6 +7424,18 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j) return j.dump(); } +#if JSON_DELETE_DEPRECATED_FUNCTIONS && !defined(JSON_NO_IO) + /// @brief serialize to stream (deleted; use operator<<(std::ostream&, const basic_json&)) + /// @sa https://json.nlohmann.me/api/operator_ltlt/ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + std::ostream& operator>>(const NLOHMANN_BASIC_JSON_TPL& j, std::ostream& o) = delete; + + /// @brief deserialize from stream (deleted; use operator>>(std::istream&, basic_json&)) + /// @sa https://json.nlohmann.me/api/operator_gtgt/ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + std::istream& operator<<(NLOHMANN_BASIC_JSON_TPL& j, std::istream& i) = delete; +#endif + NLOHMANN_JSON_NAMESPACE_END /////////////////////// diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 2e0970726..74539d376 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -259,6 +259,9 @@ public: for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) { + // false positive: Infer's model of std::string keeps the buffer of a + // moved-from string, so it assumes a buffer is destroyed twice + // @infer-ignore USE_AFTER_DELETE it->~value_type(); // destroy but keep allocation new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it } diff --git a/nlohmann_json.natvis b/nlohmann_json.natvis index 17029f1dd..02e9d28ed 100644 --- a/nlohmann_json.natvis +++ b/nlohmann_json.natvis @@ -35,6 +35,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -65,6 +109,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -95,6 +183,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -125,6 +257,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -155,6 +331,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -185,6 +405,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -215,6 +479,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -245,6 +553,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -275,6 +627,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -305,6 +701,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -335,6 +775,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -365,6 +849,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -395,6 +923,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -425,6 +997,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -455,6 +1071,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -485,6 +1145,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -515,6 +1219,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -545,6 +1441,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -575,6 +1515,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -605,6 +1589,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -635,6 +1663,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -665,6 +1737,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -695,6 +1811,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -725,6 +1885,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -755,6 +1959,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -785,6 +2033,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -815,6 +2107,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -845,6 +2181,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -875,6 +2255,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -905,6 +2477,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -935,6 +2551,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -965,6 +2625,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -995,6 +2699,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1025,6 +2773,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1055,6 +2847,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1085,6 +2921,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1115,6 +2995,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1145,6 +3069,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1175,6 +3143,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1205,6 +3365,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1235,6 +3439,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1265,6 +3513,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1295,6 +3587,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1325,6 +3661,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1355,6 +3735,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1385,6 +3809,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1415,6 +3883,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1445,6 +4105,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1475,6 +4179,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1505,6 +4253,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1535,6 +4327,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1565,6 +4401,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1595,6 +4475,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1625,6 +4697,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1655,6 +4771,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1685,6 +4845,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1715,6 +4919,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1745,6 +5141,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1775,6 +5215,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1805,6 +5585,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1835,6 +5659,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1865,6 +5733,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1895,6 +5807,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1925,6 +5881,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1955,6 +5955,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -1985,6 +6029,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2015,6 +6103,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2045,6 +6177,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2075,6 +6251,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2105,6 +6473,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2135,6 +6547,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2165,6 +6621,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2195,6 +6695,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2225,6 +6769,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2255,6 +6843,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2285,6 +6917,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2315,6 +6991,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2345,6 +7213,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2375,6 +7287,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2405,6 +7361,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2435,6 +7435,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2465,6 +7509,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2495,6 +7583,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2525,6 +7805,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2555,6 +7879,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2585,6 +7953,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2615,6 +8027,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2645,6 +8249,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2675,6 +8323,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2705,6 +8693,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2735,6 +8767,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2765,6 +8841,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2795,6 +8915,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2825,6 +8989,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2855,6 +9063,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2885,6 +9137,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2915,6 +9211,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2945,6 +9433,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -2975,6 +9507,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3005,6 +9581,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3035,6 +9655,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3065,6 +9729,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3095,6 +9803,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3125,6 +10025,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3155,6 +10099,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3185,6 +10173,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3215,6 +10247,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3245,6 +10469,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3275,6 +10543,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3305,6 +10913,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3335,6 +10987,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3365,6 +11061,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3395,6 +11135,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3425,6 +11209,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3455,6 +11283,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3485,6 +11505,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3515,6 +11579,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3545,6 +11653,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3575,6 +11727,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3605,6 +11949,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3635,6 +12023,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3665,6 +12393,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3695,6 +12467,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3725,6 +12541,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3755,6 +12615,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3785,6 +12837,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3815,6 +12911,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3845,6 +13281,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3875,6 +13355,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3905,6 +13873,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3935,6 +13947,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3965,6 +14021,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -3995,6 +14095,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4025,6 +14169,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4055,6 +14243,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4085,6 +14317,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4115,6 +14391,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4145,6 +14613,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4175,6 +14687,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4205,6 +14761,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4235,6 +14835,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4265,6 +14909,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4295,6 +14983,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4325,6 +15205,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4355,6 +15279,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4385,6 +15353,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4415,6 +15427,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4445,6 +15649,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4475,6 +15723,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4505,6 +16093,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4535,6 +16167,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4565,6 +16241,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4595,6 +16315,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4625,6 +16389,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4655,6 +16463,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4685,6 +16685,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4715,6 +16759,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4745,6 +16833,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4775,6 +16907,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4805,6 +17129,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4835,6 +17203,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4865,6 +17573,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4895,6 +17647,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4925,6 +17721,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4955,6 +17795,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -4985,6 +18017,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5015,6 +18091,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5045,6 +18461,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5075,6 +18535,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5105,6 +19053,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5135,6 +19127,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5165,6 +19201,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5195,6 +19275,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5225,6 +19349,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5255,6 +19423,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5285,6 +19645,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5315,6 +19719,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5345,6 +19793,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5375,6 +19867,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5405,6 +20089,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5435,6 +20163,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5465,6 +20533,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5495,6 +20607,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5525,6 +20681,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5555,6 +20755,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5585,6 +20977,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5615,6 +21051,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5645,6 +21421,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5675,6 +21495,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5705,6 +22013,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5735,6 +22087,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5765,6 +22161,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5795,6 +22235,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5825,6 +22457,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5855,6 +22531,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5885,6 +22901,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5915,6 +22975,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5945,6 +23493,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -5975,6 +23567,642 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6005,6 +24233,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6035,6 +24307,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6065,6 +24381,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6095,6 +24455,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6125,6 +24529,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6155,6 +24603,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6185,6 +24825,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6215,6 +24899,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6245,6 +24973,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6275,6 +25047,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6305,6 +25269,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6335,6 +25343,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6365,6 +25713,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6395,6 +25787,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6425,6 +25861,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6455,6 +25935,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6485,6 +26157,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6515,6 +26231,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6545,6 +26601,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6575,6 +26675,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6605,6 +27193,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6635,6 +27267,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6665,6 +27341,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6695,6 +27415,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6725,6 +27637,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6755,6 +27711,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6785,6 +28081,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6815,6 +28155,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6845,6 +28673,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6875,6 +28747,642 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6905,6 +29413,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6935,6 +29487,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6965,6 +29561,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -6995,6 +29635,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7025,6 +29857,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7055,6 +29931,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7085,6 +30301,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7115,6 +30375,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7145,6 +30893,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7175,6 +30967,642 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7205,6 +31633,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7235,6 +31707,790 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7265,6 +32521,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7295,6 +32595,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7325,6 +32669,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7355,6 +32743,198 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7385,6 +32965,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7415,6 +33039,346 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7445,6 +33409,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7475,6 +33483,494 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7505,6 +34001,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7535,6 +34075,642 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7565,6 +34741,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7595,6 +34815,790 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7625,6 +35629,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7655,6 +35703,938 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7685,6 +36665,50 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + null @@ -7715,4 +36739,1232 @@ + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + + {second} + + second + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 66c5c2c75..e6b57b2d3 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -108,6 +108,10 @@ #define JSON_STRICT_BINARY_UTF8 0 #endif +#ifndef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0 +#endif + #if JSON_DIAGNOSTICS #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag #else @@ -150,14 +154,20 @@ #define NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8 #endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS _ekmo +#else + #define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS +#endif + #ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) json_abi ## a ## b ## c ## d ## e ## f ## g -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h) json_abi ## a ## b ## c ## d ## e ## f ## g ## h +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ @@ -167,7 +177,8 @@ NLOHMANN_JSON_ABI_TAG_BRACE_INIT_COPY_SEMANTICS, \ NLOHMANN_JSON_ABI_TAG_PRECISE_STREAM_POSITION, \ NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING, \ - NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8) + NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8, \ + NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ @@ -3214,6 +3225,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_DISABLE_ENUM_SERIALIZATION 0 #endif +#ifndef JSON_DELETE_DEPRECATED_FUNCTIONS + #define JSON_DELETE_DEPRECATED_FUNCTIONS 0 +#endif + #ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 #endif @@ -4422,6 +4437,30 @@ template struct is_compatible_object_type : is_compatible_object_type_impl {}; +template +using insert_result_t = decltype(std::declval().insert(std::declval&>())); + +template +using insert_result_second_t = decltype(std::declval().insert(std::declval&>()).second); + +// a map-like type (std::map, std::unordered_map, ...) whose keys are enums; see +// JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +template +struct is_enum_keyed_map : std::false_type {}; + +template +struct is_enum_keyed_map < + T, enable_if_t < is_detected::value&& + is_detected::value >> +{ + // maps with non-unique keys (std::multimap, std::unordered_multimap, ...) + // are excluded, because an object cannot hold duplicate keys; they are + // detected by insert() returning an iterator instead of a pair + // NOLINTNEXTLINE(modernize-type-traits) we use C++11 + static constexpr bool value = std::is_enum::value && + !(is_detected::value && !is_detected::value); +}; + template struct is_constructible_object_type_impl : std::false_type {}; @@ -4866,6 +4905,21 @@ T conditional_static_cast(U value) return value; } +// like conditional_static_cast, but converts to bool by comparing with zero, +// because MSVC 2015 warns about any conversion to bool (C4800), even with an +// explicit cast; used for enums whose underlying type is bool +template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > +T bool_aware_static_cast(U value) +{ + return conditional_static_cast(value); +} + +template::value, int> = 0> +bool bool_aware_static_cast(U value) +{ + return value != U(); +} + template using all_integral = conjunction...>; @@ -5661,7 +5715,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e) typename BasicJsonType::number_unsigned_t, underlying_type>::type; value_type val; get_arithmetic_value(j, val); - e = static_cast(static_cast(val)); + e = static_cast(bool_aware_static_cast(val)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -6019,11 +6073,40 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m) } } +// read a map with enum keys from an object, using the enum's own from_json for +// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written +// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +template +inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/) +{ + if (!j.is_object()) + { + return false; + } + m.clear(); + for (const auto& p : *j.template get_ptr()) + { + m.emplace(BasicJsonType(p.first).template get(), p.second.template get()); + } + return true; +} + +template +inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/) +{ + return false; +} + template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, typename = enable_if_t < !std::is_constructible < typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::map& m) { + // NOLINTNEXTLINE(modernize-type-traits) we use C++11 + if (from_json_enum_keyed_object(j, m, std::is_enum {})) + { + return; + } from_json_pair_array_to_map(j, m); } @@ -6032,6 +6115,11 @@ template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::unordered_map& m) { + // NOLINTNEXTLINE(modernize-type-traits) we use C++11 + if (from_json_enum_keyed_object(j, m, std::is_enum {})) + { + return; + } from_json_pair_array_to_map(j, m); } @@ -6105,7 +6193,6 @@ NLOHMANN_JSON_NAMESPACE_END #include // optional #endif -#include // copy #include // begin, end #include // allocator_traits #include // basic_string, char_traits @@ -6115,6 +6202,8 @@ NLOHMANN_JSON_NAMESPACE_END #include // valarray #include // vector +// #include + // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -6743,10 +6832,14 @@ namespace detail ////////////////// /* - * Note all external_constructor<>::construct functions need to call - * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an - * allocated value (e.g., a string). See bug issue + * Note all external_constructor<>::construct functions need to store the new + * value with j.replace_value(), which destroys the old one to avoid a memory + * leak in case j contains an allocated value (e.g., a string). See bug issue * https://github.com/nlohmann/json/issues/2865 for more information. + * + * A value that has to be allocated is created before the old one is destroyed: + * were it the other way around, an exception while creating the new value would + * leave j with the type of the new value, but the pointer to the destroyed old one. */ template struct external_constructor; @@ -6757,10 +6850,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::boolean; - j.m_data.m_value = b; - j.assert_invariant(); + j.replace_value(value_t::boolean, b); } }; @@ -6770,19 +6860,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value = s; - j.assert_invariant(); + const typename BasicJsonType::json_value value(s); + j.replace_value(value_t::string, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value = std::move(s); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(s)); + j.replace_value(value_t::string, value); } template < typename BasicJsonType, typename CompatibleStringType, @@ -6790,10 +6876,8 @@ struct external_constructor int > = 0 > static void construct(BasicJsonType& j, const CompatibleStringType& str) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value.string = j.template create(str); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(str)); + j.replace_value(value_t::string, value); } }; @@ -6803,19 +6887,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::binary; - j.m_data.m_value = typename BasicJsonType::binary_t(b); - j.assert_invariant(); + const typename BasicJsonType::json_value value(b); + j.replace_value(value_t::binary, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::binary; - j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b)); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(b)); + j.replace_value(value_t::binary, value); } }; @@ -6825,10 +6905,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_float; - j.m_data.m_value = val; - j.assert_invariant(); + j.replace_value(value_t::number_float, val); } }; @@ -6838,10 +6915,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_unsigned; - j.m_data.m_value = val; - j.assert_invariant(); + j.replace_value(value_t::number_unsigned, val); } }; @@ -6851,10 +6925,7 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_integer; - j.m_data.m_value = val; - j.assert_invariant(); + j.replace_value(value_t::number_integer, val); } }; @@ -6864,21 +6935,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = arr; - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(arr); + j.replace_value(value_t::array, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = std::move(arr); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(arr)); + j.replace_value(value_t::array, value); } template < typename BasicJsonType, typename CompatibleArrayType, @@ -6892,39 +6957,23 @@ struct external_constructor using std::begin; using std::end; - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value.array = j.template create(begin(arr), end(arr)); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(begin(arr), end(arr))); + j.replace_value(value_t::array, value); } template static void construct(BasicJsonType& j, const std::vector& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; - j.m_data.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_data.m_value.array->push_back(x); - j.set_parent(j.m_data.m_value.array->back()); - } - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(arr.begin(), arr.end())); + j.replace_value(value_t::array, value); } template::value, int> = 0> static void construct(BasicJsonType& j, const std::valarray& arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; - j.m_data.m_value.array->resize(arr.size()); - std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin()); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(std::begin(arr), std::end(arr))); + j.replace_value(value_t::array, value); } #if JSON_HAS_RANGE_VIEW_CONVERSION @@ -6932,18 +6981,15 @@ struct external_constructor enable_if_t>::value, int> = 0> static void construct(BasicJsonType& j, CompatibleArrayType && arr) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; + // no range constructor: a view's begin() and end() may have different + // types, and the view may only be iterable once + typename BasicJsonType::array_t elements; for (auto&& x : std::forward(arr)) { - j.m_data.m_value.array->push_back(x); + elements.push_back(x); } - // set the parents only once all elements are in place: a push_back - // that reallocates moves the earlier elements, which does not keep - // their parent pointers - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(elements)); + j.replace_value(value_t::array, value); } #endif }; @@ -6954,21 +7000,15 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value = obj; - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(obj); + j.replace_value(value_t::object, value); } template static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value = std::move(obj); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(std::move(obj)); + j.replace_value(value_t::object, value); } template < typename BasicJsonType, typename CompatibleObjectType, @@ -6978,11 +7018,8 @@ struct external_constructor using std::begin; using std::end; - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value.object = j.template create(begin(obj), end(obj)); - j.set_parents(); - j.assert_invariant(); + const typename BasicJsonType::json_value value(j.template create(begin(obj), end(obj))); + j.replace_value(value_t::object, value); } }; @@ -6991,9 +7028,20 @@ struct external_constructor ///////////// #ifdef JSON_HAS_CPP_17 +// whether storing the value of a std::optional cannot throw; MSVC 2017 +// evaluates std::is_nothrow_assignable as true even if T's to_json throws, so +// the exception would call std::terminate (#5642) +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920 + template + using is_nothrow_optional_to_json = std::false_type; +#else + template + using is_nothrow_optional_to_json = std::is_nothrow_assignable; +#endif + template::value, int> = 0> -void to_json(BasicJsonType& j, const std::optional& opt) noexcept(std::is_nothrow_assignable::value) +void to_json(BasicJsonType& j, const std::optional& opt) noexcept(is_nothrow_optional_to_json::value) { if (opt.has_value()) { @@ -7069,7 +7117,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept { using underlying_type = typename std::underlying_type::type; static constexpr value_t integral_value_t = std::is_unsigned::value ? value_t::number_unsigned : value_t::number_integer; - external_constructor::construct(j, static_cast(e)); + external_constructor::construct(j, bool_aware_static_cast(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -7089,6 +7137,9 @@ template < typename BasicJsonType, typename CompatibleArrayType, !is_basic_json::value #if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value +#endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + && !is_enum_keyed_map::value #endif , int > = 0 > @@ -7143,6 +7194,33 @@ inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) external_constructor::construct(j, obj); } +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +// store a map with enum keys as an object, using the enum's own to_json for the +// keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); without the macro, such maps +// are stored as arrays of [key, value] pairs +template < typename BasicJsonType, typename EnumKeyedMap, + enable_if_t < is_enum_keyed_map::value&& !is_basic_json::value, int > = 0 > +inline void to_json(BasicJsonType& j, const EnumKeyedMap& map) +{ + typename BasicJsonType::object_t obj; + for (const auto& p : map) + { + BasicJsonType key = p.first; + if (JSON_HEDLEY_UNLIKELY(!key.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", key.type_name()), &key)); + } + + auto& key_string = *key.template get_ptr(); + if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second)) + { + JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key)); + } + } + external_constructor::construct(j, std::move(obj)); +} +#endif + template inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { @@ -7505,8 +7583,10 @@ std::size_t hash_iteratively(const BasicJsonType& j); @brief hash a JSON value The hash function tries to rely on std::hash where possible. Furthermore, the -type of the JSON value is taken into account to have different hash values for -null, 0, 0U, and false, etc. +type of the JSON value is taken into account, so null, false, and numbers may +hash differently from each other, but any two numbers that compare equal +under operator== hash equally regardless of which of number_integer, +number_unsigned, or number_float actually holds the value. Hashing an array or an object hashes its elements, which used to call this function again once per nesting level, so a value nested deeply enough @@ -7525,8 +7605,6 @@ template std::size_t hash(const BasicJsonType& j, const std::size_t depth = 0) { using string_t = typename BasicJsonType::string_t; - 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; const auto type = static_cast(j.type()); @@ -7583,21 +7661,24 @@ std::size_t hash(const BasicJsonType& j, const std::size_t depth = 0) } case BasicJsonType::value_t::number_integer: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - case BasicJsonType::value_t::number_unsigned: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - case BasicJsonType::value_t::number_float: { - const auto h = std::hash {}(j.template get()); - return combine(type, h); + // operator== compares numbers by their mathematical value across + // number_integer, number_unsigned, and number_float, so equal + // numbers of different internal types (0, 0U, 0.0) must hash the + // same. Two equal numbers have the same value, which converts to + // the same number_float_t, so all numbers share one type tag and + // hash that converted value. Adding zero turns -0.0 (equal to 0) + // into 0.0, as std::hash need not map both to the same hash. + // The converse does not hold: converting a number_float_t value + // to an integer type is lossy, so the result can hash + // differently, and unequal numbers that convert to the same + // number_float_t (e.g., 2^53 and 2^53 + 1) share a hash. + const auto number_type = static_cast(BasicJsonType::value_t::number_float); + const auto value = j.template get() + static_cast(0); + const auto h = std::hash {}(value); + return combine(number_type, h); } case BasicJsonType::value_t::binary: @@ -12182,6 +12263,39 @@ scan_number_done: // read the next character and ignore whitespace skip_whitespace(); + return scan_after_whitespace(); + } + + /*! + @brief scan the next token when the caller expects a separator (':' or + ',') most of the time + + After an object key the next token is almost always ':', after a value + inside an object or array almost always ','. Testing for that character + first is a compare and a well-predicted branch, where the switch in + scan_after_whitespace() is an indirect jump through a table. Anything else + goes through the switch, so the result is the same as scan()'s. + + May only be called after scan() has run once (the BOM check is skipped). + */ + token_type scan_expecting(token_type expected_type) + { + JSON_ASSERT(expected_type == token_type::name_separator || expected_type == token_type::value_separator); + JSON_ASSERT(position.chars_read_total > 0); + const char_int_type expected_char = static_cast((expected_type == token_type::name_separator) ? ':' : ','); + skip_whitespace(); + if (JSON_HEDLEY_LIKELY(current == expected_char)) + { + return expected_type; + } + return scan_after_whitespace(); + } + + private: + /// the part of scan() after the leading whitespace: skip comments and + /// scan the token that starts with current + token_type scan_after_whitespace() + { // ignore comments while (ignore_comments && current == '/') { @@ -12261,7 +12375,6 @@ scan_number_done: } } - private: /// input adapter InputAdapterType ia; @@ -13783,7 +13896,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current != char_traits::eof())) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, - exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); + exception_message(concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); } } @@ -13906,7 +14019,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast(document_size) != chars_read - document_start)) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr)); + exception_message(concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr)); } return true; } @@ -13921,7 +14034,7 @@ class binary_reader // check_bson_document_size() measures the document from here const std::size_t document_start = chars_read; std::int32_t document_size{}; - if (!get_number(input_format_t::bson, document_size)) + if (!get_number(document_size)) { return false; } @@ -13986,7 +14099,7 @@ class binary_reader continue; } - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("element list"))) { return false; } @@ -14030,7 +14143,7 @@ class binary_reader while (true) { get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("cstring"))) { return false; } @@ -14100,10 +14213,10 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); + exception_message(concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); } - if (JSON_HEDLEY_UNLIKELY(!get_string(input_format_t::bson, len - static_cast(1), result))) + if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast(1), result))) { return false; } @@ -14112,8 +14225,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, - "BSON string is not null-terminated", + exception_message("BSON string is not null-terminated", "string"), nullptr)); } @@ -14136,18 +14248,18 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); + exception_message(concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); } // All BSON binary values have a subtype std::uint8_t subtype{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::bson, subtype))) + if (JSON_HEDLEY_UNLIKELY(!get_number(subtype))) { return false; } result.set_subtype(subtype); - return get_binary(input_format_t::bson, len, result); + return get_binary(len, result); } /*! @@ -14168,14 +14280,14 @@ class binary_reader case 0x01: // double { double number{}; - return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0x02: // string { std::int32_t len{}; string_t value; - return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + return get_number(len) && get_bson_string(len, value) && sax->string(value); } case 0x03: // object @@ -14192,13 +14304,13 @@ class binary_reader { std::int32_t len{}; binary_t value; - return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + return get_number(len) && get_bson_binary(len, value) && sax->binary(value); } case 0x08: // boolean { std::uint8_t value{}; - return get_number(input_format_t::bson, value) && sax->boolean(value != 0); + return get_number(value) && sax->boolean(value != 0); } case 0x0A: // null @@ -14209,19 +14321,19 @@ class binary_reader case 0x10: // int32 { std::int32_t value{}; - return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value)); + return get_number(value) && emit_signed(value); } case 0x12: // int64 { std::int64_t value{}; - return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value)); + return get_number(value) && emit_signed(value); } case 0x11: // uint64 { std::uint64_t value{}; - return get_number(input_format_t::bson, value) && sax->number_unsigned(value); + return get_number(value) && emit_unsigned(value); } default: // anything else is not supported (yet) @@ -14243,18 +14355,24 @@ class binary_reader bool get_cbor_negative_integer() { NumberType number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } - const auto max_val = static_cast((std::numeric_limits::max)()); - if (number > max_val) + + // the value is -1 - number, which fits into number_integer_t + // whenever number does; the outer cast undoes the integral promotion + // for number_integer_t types narrower than int + if (JSON_HEDLEY_LIKELY(value_in_range_of(number))) { - return sax->parse_error(chars_read, get_token_string(), - parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, "negative integer overflow", "value"), nullptr)); + return sax->number_integer(conditional_static_cast(static_cast(-1) - static_cast(number))); } - return sax->number_integer(conditional_static_cast(static_cast(-1) - static_cast(number))); + + // like the lexer does for JSON text, store a value too small for + // number_integer_t as number_float_t; compute it as long double so + // that emit_float sees a finite value and can detect an overflow of + // number_float_t + return emit_float(static_cast(-1) - static_cast(number)); } /*! @@ -14279,7 +14397,7 @@ class binary_reader { // EOF case char_traits::eof(): - return unexpect_eof(input_format_t::cbor, "value"); + return unexpect_eof("value"); // Integer 0x00..0x17 (0..23) case 0x00: @@ -14311,25 +14429,25 @@ class binary_reader case 0x18: // Unsigned integer (one-byte uint8_t follows) { std::uint8_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0x19: // Unsigned integer (two-byte uint16_t follows) { std::uint16_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0x1A: // Unsigned integer (four-byte uint32_t follows) { std::uint32_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0x1B: // Unsigned integer (eight-byte uint64_t follows) { std::uint64_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } // Negative integer -1-0x00..-1-0x17 (-1..-24) @@ -14550,7 +14668,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } // ignore and store: the tag value is already in the head, so @@ -14572,7 +14690,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } case cbor_tag_handler_t::ignore: @@ -14630,29 +14748,43 @@ class binary_reader return sax->null(); case 0xF9: // Half-Precision Float (two-byte IEEE 754) - return get_half_float(input_format_t::cbor, false); + return get_half_float(false); case 0xFA: // Single-Precision Float (four-byte IEEE 754) { float number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { double number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } default: // anything else (0xFF is handled inside the other types) { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } } } + /*! + @brief reports a nested indefinite-length CBOR string or byte array + @param[in] type_name name of the rejected string type + @param[in] context parsing context for the error message + @return whether the SAX consumer accepts the parse error + */ + bool cbor_indefinite_string_error(const char* type_name, const char* context) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(concat("indefinite-length ", type_name, + " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", last_token), context), nullptr)); + } + /*! @brief reads a definite-length CBOR string @@ -14662,12 +14794,13 @@ class binary_reader into the same string. @param[out] result string the bytes are appended to + @param[in] inside_indefinite whether the bytes belong to an indefinite-length string @return whether string creation completed @pre @a current is not EOF */ - bool get_cbor_string_chunk(string_t& result) + bool get_cbor_string_chunk(string_t& result, const bool inside_indefinite) { switch (current) { @@ -14697,38 +14830,38 @@ class binary_reader case 0x76: case 0x77: { - return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + return get_string(static_cast(current) & 0x1Fu, result); } case 0x78: // UTF-8 string (one-byte uint8_t for n follows) { std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } case 0x79: // UTF-8 string (two-byte uint16_t for n follow) { std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) { std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) { std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + return get_number(len) && get_string(len, result); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); + exception_message(concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", last_token), "string"), nullptr)); } } } @@ -14746,46 +14879,41 @@ class binary_reader */ bool get_cbor_string(string_t& result, const char* context = "string") { - // number of indefinite-length strings that have been opened and not - // closed yet. RFC 8949, Section 3.2.3 does not permit nesting them, - // but this reader has always accepted it, so the open levels are - // counted instead of recursed through, which overflowed the stack for - // an input of repeated 0x7F bytes (see #5104). Every chunk is appended - // to the same result, so no per-level state is needed. - std::size_t open = 0; + // read chunks iteratively, but reject a second indefinite-length + // level as required by RFC 8949, Section 3.2.3 + bool indefinite = false; while (true) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("string"))) { return false; } if (current == 0x7F) // UTF-8 string (indefinite length) { - ++open; - get(); - continue; - } - - // a break marker closes the innermost indefinite-length string; - // outside of one it is not a string and falls through to the error - if (open != 0 && current == 0xFF) - { - if (--open == 0) + if (JSON_HEDLEY_UNLIKELY(indefinite)) { - return check_string_utf8(result, context); + return cbor_indefinite_string_error("string", "string"); } + indefinite = true; get(); continue; } - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result))) + // a break marker closes the indefinite-length string; outside + // of one it falls through to the error below + if (indefinite && current == 0xFF) + { + return check_string_utf8(result, context); + } + + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result, indefinite))) { return false; } - if (open == 0) + if (!indefinite) { return check_string_utf8(result, context); } @@ -14865,7 +14993,7 @@ class binary_reader auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); + exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); } /*! @@ -14877,12 +15005,13 @@ class binary_reader read into the same byte array. @param[out] result byte array the bytes are appended to + @param[in] inside_indefinite whether the bytes belong to an indefinite-length string @return whether byte array creation completed @pre @a current is not EOF */ - bool get_cbor_binary_chunk(binary_t& result) + bool get_cbor_binary_chunk(binary_t& result, const bool inside_indefinite) { switch (current) { @@ -14912,42 +15041,42 @@ class binary_reader case 0x56: case 0x57: { - return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + return get_binary(static_cast(current) & 0x1Fu, result); } case 0x58: // Binary data (one-byte uint8_t for n follows) { std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } case 0x59: // Binary data (two-byte uint16_t for n follow) { std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } case 0x5A: // Binary data (four-byte uint32_t for n follow) { std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } case 0x5B: // Binary data (eight-byte uint64_t for n follow) { std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); + return get_number(len) && + get_binary(len, result); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); + exception_message(concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", last_token), "binary"), nullptr)); } } } @@ -14965,42 +15094,41 @@ class binary_reader */ bool get_cbor_binary(binary_t& result) { - // the open indefinite-length byte arrays are counted rather than - // recursed through, for the reason given in @ref get_cbor_string - std::size_t open = 0; + // read chunks iteratively, but reject a second indefinite-length + // level as required by RFC 8949, Section 3.2.3 + bool indefinite = false; while (true) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("binary"))) { return false; } if (current == 0x5F) // Binary data (indefinite length) { - ++open; - get(); - continue; - } - - // a break marker closes the innermost indefinite-length byte - // array; outside of one it falls through to the error below - if (open != 0 && current == 0xFF) - { - if (--open == 0) + if (JSON_HEDLEY_UNLIKELY(indefinite)) { - return true; + return cbor_indefinite_string_error("binary array", "binary"); } + indefinite = true; get(); continue; } - if (JSON_HEDLEY_UNLIKELY(!get_cbor_binary_chunk(result))) + // a break marker closes the indefinite-length string; outside + // of one it falls through to the error below + if (indefinite && current == 0xFF) + { + return true; + } + + if (JSON_HEDLEY_UNLIKELY(!get_cbor_binary_chunk(result, indefinite))) { return false; } - if (open == 0) + if (!indefinite) { return true; } @@ -15029,7 +15157,7 @@ class binary_reader case 0x18: // 1 byte { std::uint8_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -15040,7 +15168,7 @@ class binary_reader case 0x19: // 2 bytes { std::uint16_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -15051,7 +15179,7 @@ class binary_reader case 0x1A: // 4 bytes { std::uint32_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -15062,7 +15190,7 @@ class binary_reader case 0x1B: // 8 bytes { std::uint64_t n{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n))) + if (JSON_HEDLEY_UNLIKELY(!get_number(n))) { return false; } @@ -15095,7 +15223,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(len) || len == detail::unknown_size())) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format_t::cbor, concat("excessive ", context, " size"), "size"), nullptr)); + exception_message(concat("excessive ", context, " size"), "size"), nullptr)); } result = conditional_static_cast(len); return true; @@ -15224,7 +15352,7 @@ class binary_reader { // EOF case char_traits::eof(): - return unexpect_eof(input_format_t::msgpack, "value"); + return unexpect_eof("value"); // positive fixint case 0x00: @@ -15464,85 +15592,85 @@ class binary_reader case 0xCA: // float 32 { float number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xCB: // float 64 { double number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xCC: // uint 8 { std::uint8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xCD: // uint 16 { std::uint16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xCE: // uint 32 { std::uint32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xCF: // uint 64 { std::uint64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 0xD0: // int 8 { std::int8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xD1: // int 16 { std::int16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xD2: // int 32 { std::int32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xD3: // int 64 { std::int64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 0xDC: // array 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && enter_array(static_cast(len)); + return get_number(len) && enter_array(static_cast(len)); } case 0xDD: // array 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && enter_array(conditional_static_cast(len)); + return get_number(len) && enter_array(conditional_static_cast(len)); } case 0xDE: // map 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && enter_object(static_cast(len)); + return get_number(len) && enter_object(static_cast(len)); } case 0xDF: // map 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && enter_object(conditional_static_cast(len)); + return get_number(len) && enter_object(conditional_static_cast(len)); } // negative fixint @@ -15584,7 +15712,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); + exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr)); } } } @@ -15601,7 +15729,7 @@ class binary_reader */ bool get_msgpack_string(string_t& result, const char* context = "string") { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("string"))) { return false; } @@ -15642,32 +15770,32 @@ class binary_reader case 0xBE: case 0xBF: { - return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result) && check_string_utf8(result, context); + return get_string(static_cast(current) & 0x1Fu, result) && check_string_utf8(result, context); } case 0xD9: // str 8 { std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 0xDA: // str 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 0xDB: // str 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); + exception_message(concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); } } } @@ -15761,7 +15889,7 @@ class binary_reader auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::msgpack, concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); + exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr)); } /*! @@ -15788,31 +15916,31 @@ class binary_reader case 0xC4: // bin 8 { std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); + return get_number(len) && + get_binary(len, result); } case 0xC5: // bin 16 { std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); + return get_number(len) && + get_binary(len, result); } case 0xC6: // bin 32 { std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); + return get_number(len) && + get_binary(len, result); } case 0xC7: // ext 8 { std::uint8_t len{}; std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && + return get_number(len) && + get_number(subtype) && + get_binary(len, result) && assign_and_return_true(subtype); } @@ -15820,9 +15948,9 @@ class binary_reader { std::uint16_t len{}; std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && + return get_number(len) && + get_number(subtype) && + get_binary(len, result) && assign_and_return_true(subtype); } @@ -15830,49 +15958,49 @@ class binary_reader { std::uint32_t len{}; std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && + return get_number(len) && + get_number(subtype) && + get_binary(len, result) && assign_and_return_true(subtype); } case 0xD4: // fixext 1 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 1, result) && + return get_number(subtype) && + get_binary(1, result) && assign_and_return_true(subtype); } case 0xD5: // fixext 2 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 2, result) && + return get_number(subtype) && + get_binary(2, result) && assign_and_return_true(subtype); } case 0xD6: // fixext 4 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 4, result) && + return get_number(subtype) && + get_binary(4, result) && assign_and_return_true(subtype); } case 0xD7: // fixext 8 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 8, result) && + return get_number(subtype) && + get_binary(8, result) && assign_and_return_true(subtype); } case 0xD8: // fixext 16 { std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 16, result) && + return get_number(subtype) && + get_binary(16, result) && assign_and_return_true(subtype); } @@ -16071,7 +16199,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(len < 0)) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "string length must not be negative", "string"), nullptr)); + exception_message("string length must not be negative", "string"), nullptr)); } return true; } @@ -16101,7 +16229,7 @@ class binary_reader get(); } - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("value"))) { return false; } @@ -16111,31 +16239,31 @@ class binary_reader case 'U': { std::uint8_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 'i': { std::int8_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'I': { std::int16_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'l': { std::int32_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'L': { std::int64_t len{}; - return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && check_ubjson_string_length(len) && get_string(len, result) && check_string_utf8(result, context); } case 'u': @@ -16145,7 +16273,7 @@ class binary_reader break; } std::uint16_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 'm': @@ -16155,7 +16283,7 @@ class binary_reader break; } std::uint32_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } case 'M': @@ -16165,7 +16293,7 @@ class binary_reader break; } std::uint64_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result) && check_string_utf8(result, context); + return get_number(len) && get_string(len, result) && check_string_utf8(result, context); } default: @@ -16182,7 +16310,7 @@ class binary_reader { message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; } - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "string"), nullptr)); } /*! @@ -16261,19 +16389,19 @@ class binary_reader bool get_ubjson_signed_count(std::size_t& result) { SignedType number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } if (JSON_HEDLEY_UNLIKELY(number < 0)) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + exception_message("count in an optimized container must be positive", "size"), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(number))) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "integer value overflow", "size"), nullptr)); + exception_message("integer value overflow", "size"), nullptr)); } result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char return true; @@ -16287,10 +16415,15 @@ class binary_reader is_ndarray can only return `true` when its initial value is `false` @param[in] prefix type marker if already read, otherwise set to 0 + @param[in] ndarray_dtype the element type marker of the enclosing bjdata ndarray if + already known (it precedes the dimension vector read here), + otherwise 0; used to emit the "_ArrayType_" annotation key + before "_ArraySize_" if a dimension vector turns out to + describe an ndarray @return whether size determination completed */ - bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0, char_int_type ndarray_dtype = 0) { if (prefix == 0) { @@ -16302,7 +16435,7 @@ class binary_reader case 'U': { std::uint8_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } @@ -16329,7 +16462,7 @@ class binary_reader break; } std::uint16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } @@ -16344,7 +16477,7 @@ class binary_reader break; } std::uint32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } @@ -16359,14 +16492,14 @@ class binary_reader break; } std::uint64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + if (JSON_HEDLEY_UNLIKELY(!get_number(number))) { return false; } if (!value_in_range_of(number)) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "integer value overflow", "size"), nullptr)); + exception_message("integer value overflow", "size"), nullptr)); } result = detail::conditional_static_cast(number); return true; @@ -16380,7 +16513,7 @@ class binary_reader } if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message("ndarray dimensional vector is not allowed", "size"), nullptr)); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -16403,8 +16536,34 @@ class binary_reader } } + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3))) + { + return false; + } + + // the element type precedes the dimension vector (see get_ubjson_size_type) + // and is passed down as ndarray_dtype; emit it here so the annotation keys + // follow the documented _ArrayType_, _ArraySize_, _ArrayData_ order + if (ndarray_dtype != 0) + { + const char* type_name = bjd_type_name(ndarray_dtype); + if (JSON_HEDLEY_UNLIKELY(type_name == nullptr)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message("invalid byte: 0x" + last_token, "type"), nullptr)); + } + + string_t type_key = "_ArrayType_"; + string_t type = type_name; // sax->string() takes a reference + if (JSON_HEDLEY_UNLIKELY(!sax->key(type_key) || !sax->string(type))) + { + return false; + } + } + string_t key = "_ArraySize_"; - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(dim.size()))) { return false; } @@ -16420,7 +16579,7 @@ class binary_reader // or SIZE_MAX. if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits::max)() / i)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } result *= i; // the pre-check above already rules out result becoming 0 @@ -16429,9 +16588,9 @@ class binary_reader // unknown-size container (see get_ubjson_size_type()) if (result == npos) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } - if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast(i)))) + if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i))) { return false; } @@ -16457,7 +16616,7 @@ class binary_reader { message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; } - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "size"), nullptr)); } /*! @@ -16492,10 +16651,10 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + exception_message(concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); } - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type"))) { return false; } @@ -16503,16 +16662,16 @@ class binary_reader get_ignore_noop(); if (JSON_HEDLEY_UNLIKELY(current != '#')) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("value"))) { return false; } auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); + exception_message(concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); } - const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + const bool is_error = get_ubjson_size_value(result.first, is_ndarray, 0, result.second); // an ndarray was read here only if the flag flipped; when it was // seeded true, get_ubjson_size_value() already rejected the nested // dimension vector @@ -16529,7 +16688,7 @@ class binary_reader if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, - exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); + exception_message("ndarray requires both type and size", "size"), nullptr)); } return is_error; } @@ -16546,7 +16705,7 @@ class binary_reader switch (prefix) { case char_traits::eof(): // EOF - return unexpect_eof(input_format, "value"); + return unexpect_eof("value"); case 'T': // true return sax->boolean(true); @@ -16563,37 +16722,37 @@ class binary_reader break; } std::uint8_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'U': { std::uint8_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'i': { std::int8_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'I': { std::int16_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'l': { std::int32_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'L': { std::int64_t number{}; - return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number)); + return get_number(number) && emit_signed(number); } case 'u': @@ -16603,7 +16762,7 @@ class binary_reader break; } std::uint16_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'm': @@ -16613,7 +16772,7 @@ class binary_reader break; } std::uint32_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'M': @@ -16623,7 +16782,7 @@ class binary_reader break; } std::uint64_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); + return get_number(number) && emit_unsigned(number); } case 'h': @@ -16632,19 +16791,19 @@ class binary_reader { break; } - return get_half_float(input_format, true); + return get_half_float(true); } case 'd': { float number{}; - return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 'D': { double number{}; - return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 'H': @@ -16655,7 +16814,7 @@ class binary_reader case 'C': // char { get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("char"))) { return false; } @@ -16663,7 +16822,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); + exception_message(concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); } string_t s(1, static_cast(current)); return sax->string(s); @@ -16685,7 +16844,7 @@ class binary_reader break; } auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message("invalid byte: 0x" + last_token, "value"), nullptr)); } /*! @@ -16705,27 +16864,17 @@ class binary_reader if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) { size_and_type.second &= ~(static_cast(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker - const char* type_name = bjd_type_name(size_and_type.second); - string_t key = "_ArrayType_"; - if (JSON_HEDLEY_UNLIKELY(type_name == nullptr)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); - } - - string_t type = type_name; // sax->string() takes a reference - if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) - { - return false; - } + // the "_ArrayType_" and "_ArraySize_" annotation keys were already emitted by + // get_ubjson_size_value() (the type marker is known before the dimension vector + // that determines size_and_type.first is read, so it is emitted first there to + // match the documented _ArrayType_, _ArraySize_, _ArrayData_ key order) if (size_and_type.second == 'C' || size_and_type.second == 'B') { size_and_type.second = 'U'; } - key = "_ArrayData_"; + string_t key = "_ArrayData_"; if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) { return false; @@ -16746,7 +16895,7 @@ class binary_reader if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B') { binary_t result; - return get_binary(input_format, size_and_type.first, result) && sax->binary(result); + return get_binary(size_and_type.first, result) && sax->binary(result); } if (size_and_type.first != npos) @@ -16759,7 +16908,7 @@ class binary_reader && size_and_type.first > max_valueless_container_size)) { return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "excessive array size", "size"), nullptr)); + exception_message("excessive array size", "size"), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!enter_array(size_and_type.first, size_and_type.second))) @@ -16796,7 +16945,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); + exception_message("BJData object does not support ND-array size in optimized format", "object"), nullptr)); } if (size_and_type.first != npos) @@ -16826,10 +16975,16 @@ class binary_reader for (std::size_t i = 0; i < size; ++i) { get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } + // the lexer would stop at a NUL and accept the digits before it + if (JSON_HEDLEY_UNLIKELY(current == '\0')) + { + return sax->parse_error(chars_read, "00", parse_error::create(115, chars_read, + exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr)); + } number_vector.push_back(static_cast(current)); } @@ -16845,7 +17000,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) { return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, - exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } switch (result_number) @@ -16885,7 +17040,7 @@ class binary_reader case token_type::literal_or_value: default: return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, - exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } } @@ -16954,7 +17109,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bon8, concat(detail, ": 0x", last_token), context), nullptr)); + exception_message(concat(detail, ": 0x", last_token), context), nullptr)); } /*! @@ -17058,7 +17213,7 @@ class binary_reader if (byte == char_traits::eof()) { - return unexpect_eof(input_format_t::bon8, "value"); + return unexpect_eof("value"); } // string: ASCII character @@ -17095,25 +17250,25 @@ class binary_reader case 0x8C: // int32 { std::int32_t number{}; - return get_number(input_format_t::bon8, number) && emit_bon8_integer(number); + return get_number(number) && emit_bon8_integer(number); } case 0x8D: // int64 { std::int64_t number{}; - return get_number(input_format_t::bon8, number) && emit_bon8_integer(number); + return get_number(number) && emit_bon8_integer(number); } case 0x8E: // binary32 { float number{}; - return get_number(input_format_t::bon8, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0x8F: // binary64 { double number{}; - return get_number(input_format_t::bon8, number) && sax->number_float(static_cast(number), ""); + return get_number(number) && emit_float(number); } case 0xF8: @@ -17179,7 +17334,9 @@ class binary_reader @brief pass an integer to the SAX parser Non-negative integers are passed as unsigned, negative integers as signed - numbers, like the other binary formats do. + numbers, like the other binary formats do. A value that does not fit the + number type is passed as described for @ref emit_unsigned and + @ref emit_signed. @param[in] number the integer @return whether the SAX parser accepted the value @@ -17188,9 +17345,9 @@ class binary_reader { if (number >= 0) { - return sax->number_unsigned(static_cast(number)); + return emit_unsigned(static_cast(number)); } - return sax->number_integer(static_cast(number)); + return emit_signed(number); } /*! @@ -17210,7 +17367,7 @@ class binary_reader */ bool get_bon8_integer(const char_int_type lead, const char_int_type second) { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bon8, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } @@ -17242,13 +17399,12 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(get_bon8() == char_traits::eof())) { - return unexpect_eof(input_format_t::bon8, "number"); + return unexpect_eof("number"); } value = (value << 8) | static_cast(current); } - return negative ? sax->number_integer(static_cast(-(value + offset))) - : sax->number_unsigned(static_cast(value + offset)); + return emit_bon8_integer(negative ? -(value + offset) : value + offset); } /*! @@ -17266,7 +17422,7 @@ class binary_reader if (byte == char_traits::eof()) { - return unexpect_eof(input_format_t::bon8, "key"); + return unexpect_eof("key"); } if (byte == 0xFF) @@ -17286,7 +17442,7 @@ class binary_reader if (second == char_traits::eof()) { // the input ends inside a character or an integer - return unexpect_eof(input_format_t::bon8, "key"); + return unexpect_eof("key"); } unget_bon8(second); if (is_bon8_continuation(second)) @@ -17359,7 +17515,7 @@ class binary_reader if (byte == char_traits::eof()) { - return unexpect_eof(input_format_t::bon8, "string"); + return unexpect_eof("string"); } // end of string @@ -17390,7 +17546,7 @@ class binary_reader { // the input ends inside a character or an integer: either // way, the message is incomplete - return unexpect_eof(input_format_t::bon8, "string"); + return unexpect_eof("string"); } if (!is_bon8_continuation(second)) { @@ -17431,7 +17587,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(get_bon8() == char_traits::eof())) { - return unexpect_eof(input_format_t::bon8, "string"); + return unexpect_eof("string"); } if (JSON_HEDLEY_UNLIKELY(!is_bon8_continuation(current))) { @@ -17470,7 +17626,7 @@ class binary_reader @return bool, whether the read was successful */ template - bool get_to(T& dest, const input_format_t format, const char* context) + bool get_to(T& dest, const char* context) { // false positive: new_chars_read is read on the next lines // @infer-ignore DEAD_STORE @@ -17480,7 +17636,7 @@ class binary_reader { // in case of failure, advance position by 1 to report the failing location ++chars_read; - sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); return false; } return true; @@ -17531,7 +17687,6 @@ class binary_reader @brief read a number from the input @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) @param[out] result number of type @a NumberType @return whether conversion completed @@ -17543,42 +17698,122 @@ class binary_reader should reorder on big endian systems. */ template - bool get_number(const input_format_t format, NumberType& result) + bool get_number(NumberType& result) { // read in the original format - if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!get_to(result, "number"))) { return false; } - if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + if (is_little_endian != (InputIsLittleEndian || input_format == input_format_t::bjdata)) { byte_swap(result); } return true; } + /*! + @brief pass a signed integer read from the input to the SAX parser + + Like the lexer does for JSON text, a value that does not fit into + number_integer_t is passed as number_unsigned_t if it is non-negative and + fits there, and as number_float_t otherwise. With the default number + types, every integer the binary formats can encode fits, so this only + matters for narrower custom number types. + + @tparam NumberType a signed integer type + @param[in] number the integer + @return whether the SAX parser accepted the value + + @throw out_of_range.406 if @a number overflows number_float_t (see + @ref emit_float) + */ + template + bool emit_signed(const NumberType number) + { + if (JSON_HEDLEY_LIKELY(value_in_range_of(number))) + { + return sax->number_integer(static_cast(number)); + } + if (value_in_range_of(number)) + { + return sax->number_unsigned(static_cast(number)); + } + // std::isfinite has no integer overloads in MSVC's + return emit_float(static_cast(number)); + } + + /*! + @brief pass an unsigned integer read from the input to the SAX parser + + Like the lexer does for JSON text, a value that does not fit into + number_unsigned_t is passed as number_float_t. + + @tparam NumberType an unsigned integer type + @param[in] number the integer + @return whether the SAX parser accepted the value + + @throw out_of_range.406 if @a number overflows number_float_t (see + @ref emit_float) + */ + template + bool emit_unsigned(const NumberType number) + { + if (JSON_HEDLEY_LIKELY(value_in_range_of(number))) + { + return sax->number_unsigned(static_cast(number)); + } + // std::isfinite has no integer overloads in MSVC's + return emit_float(static_cast(number)); + } + + /*! + @brief pass a floating-point number read from the input to the SAX parser + + Like the lexer does for JSON text, a finite value that overflows + number_float_t is rejected instead of silently becoming infinity. Infinity + and NaN in the input are passed on unchanged. Integers only overflow if + number_float_t cannot represent 2^64, e.g., a half-precision type. + + @tparam NumberType a floating-point type (emit_signed and emit_unsigned + convert integers to long double first) + @param[in] number the number + @return whether the SAX parser accepted the value + + @throw out_of_range.406 if a finite @a number overflows number_float_t + */ + template + bool emit_float(const NumberType number) + { + const auto result = static_cast(number); + if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result))) + { + return sax->parse_error(chars_read, get_token_string(), + out_of_range::create(406, exception_message("number overflow", "value"), nullptr)); + } + return sax->number_float(result, ""); + } + /*! @brief read and decode an IEEE 754 half-precision (16-bit) float Used by CBOR (big endian) and BJData (little endian); the two formats only differ in the byte order of the two bytes that make up the half. - - @param[in] format the current format (for diagnostics) @param[in] little_endian whether the two bytes are little endian (BJData) or big endian (CBOR) @return whether reading and decoding succeeded */ - bool get_half_float(const input_format_t format, const bool little_endian) + bool get_half_float(const bool little_endian) { const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("number"))) { return false; } @@ -17624,7 +17859,6 @@ class binary_reader @brief create a string by reading characters from the input @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) @param[in] len number of characters to read @param[out] result string created by reading @a len bytes @@ -17635,8 +17869,7 @@ class binary_reader the input before we run out of string memory. */ template - bool get_string(const input_format_t format, - const NumberType len, + bool get_string(const NumberType len, string_t& result) { // Strings are taken as is by default: none of CBOR (RFC 8949 §3.1 @@ -17648,7 +17881,7 @@ class binary_reader // @ref error_handler, applied once the whole string (all chunks of // an indefinite-length CBOR string included) has been assembled, by // @ref check_string_utf8 at the call site. - return get_bytes(format, len, "string", result); + return get_bytes(len, "string", result); } /*! @@ -17679,7 +17912,7 @@ class binary_reader { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, "invalid string: ill-formed UTF-8 byte", context), nullptr)); + exception_message("invalid string: ill-formed UTF-8 byte", context), nullptr)); } result = sanitize_utf8(result, error_handler); @@ -17690,7 +17923,6 @@ class binary_reader @brief create a byte array by reading bytes from the input @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) @param[in] len number of bytes to read @param[out] result byte array created by reading @a len bytes @@ -17701,11 +17933,10 @@ class binary_reader the input before we run out of memory. */ template - bool get_binary(const input_format_t format, - const NumberType len, + bool get_binary(const NumberType len, binary_t& result) { - return get_bytes(format, len, "binary", result); + return get_bytes(len, "binary", result); } /*! @@ -17713,7 +17944,6 @@ class binary_reader @tparam NumberType the type of the length @tparam ContainerType the destination container (string_t or binary_t) - @param[in] format the current format (for diagnostics) @param[in] len number of bytes to read @param[in] context further context information (for diagnostics) @param[out] result container the bytes are appended to @@ -17728,8 +17958,7 @@ class binary_reader detects a premature end of input. */ template - bool get_bytes(const input_format_t format, - NumberType len, + bool get_bytes(NumberType len, const char* context, ContainerType& result) { @@ -17760,7 +17989,7 @@ class binary_reader result.resize(old_size + bytes_read); ++chars_read; current = char_traits::eof(); - return unexpect_eof(format, context); + return unexpect_eof(context); } // a full chunk was read; get_elements() never returns more than requested JSON_ASSERT(bytes_read == wanted); @@ -17770,17 +17999,16 @@ class binary_reader } /*! - @param[in] format the current format (for diagnostics) @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF */ - JSON_HEDLEY_NON_NULL(3) - bool unexpect_eof(const input_format_t format, const char* context) const + JSON_HEDLEY_NON_NULL(2) + bool unexpect_eof(const char* context) const { if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) { return sax->parse_error(chars_read, "", - parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); } return true; } @@ -17796,18 +18024,16 @@ class binary_reader } /*! - @param[in] format the current format @param[in] detail a detailed error message @param[in] context further context information @return a message string to use in the parse_error exceptions */ - std::string exception_message(const input_format_t format, - const std::string& detail, + std::string exception_message(const std::string& detail, const std::string& context) const { std::string error_msg = "syntax error while parsing "; - switch (format) + switch (input_format) { case input_format_t::cbor: error_msg += "CBOR"; @@ -18215,7 +18441,7 @@ class parser } // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator))) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -18378,7 +18604,7 @@ class parser { // comma -> next value // or end of array (ignore_trailing_commas = true) - if (get_token() == token_type::value_separator) + if (get_token_expecting(token_type::value_separator)) { // parse a new value get_token(); @@ -18418,7 +18644,7 @@ class parser // comma -> next value // or end of object (ignore_trailing_commas = true) - if (get_token() == token_type::value_separator) + if (get_token_expecting(token_type::value_separator)) { get_token(); @@ -18439,7 +18665,7 @@ class parser } // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator))) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -18483,6 +18709,13 @@ class parser return last_token = m_lexer.scan(); } + /// get next token from lexer; true if it is the separator @a expected_type + /// (name_separator or value_separator), which it usually is + bool get_token_expecting(token_type expected_type) + { + return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type; + } + std::string exception_message(const token_type expected, const std::string& context) { std::string error_msg = "syntax error "; @@ -19757,9 +19990,13 @@ class json_pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/ JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) operator string_t() const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return to_string(); } +#endif #ifndef JSON_NO_IO /// @brief write string representation of the JSON pointer to stream @@ -20702,9 +20939,13 @@ class json_pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) bool operator==(const string_t& rhs) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return *this == json_pointer(rhs); } +#endif /// @brief 3-way compares two JSON pointers template @@ -20782,18 +21023,26 @@ template& lhs, const StringType& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return lhs == json_pointer(rhs); } +#endif template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) inline bool operator==(const StringType& lhs, const json_pointer& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return json_pointer(lhs) == rhs; } +#endif template inline bool operator!=(const json_pointer& lhs, @@ -20807,18 +21056,26 @@ template& lhs, const StringType& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return !(lhs == rhs); } +#endif template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) inline bool operator!=(const StringType& lhs, const json_pointer& rhs) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return !(lhs == rhs); } +#endif template inline bool operator<(const json_pointer& lhs, @@ -20869,6 +21126,7 @@ class json_ref json_ref(std::initializer_list init) : owned_value(init) + , braced_list(true) {} template < @@ -20904,9 +21162,17 @@ class json_ref return &** this; } + /// whether the value was written as a braced list, such as {"key", 1}, + /// rather than given as a value + bool is_braced_list() const noexcept + { + return braced_list; + } + private: mutable value_type owned_value = nullptr; value_type const* value_ref = nullptr; + bool braced_list = false; }; } // namespace detail @@ -21259,6 +21525,8 @@ class output_adapter } // namespace detail NLOHMANN_JSON_NAMESPACE_END +// #include + // #include // #include @@ -21360,6 +21628,7 @@ class binary_writer @throw type_error.316 if a string value or an object key is not valid UTF-8 @throw type_error.317 if @a j is not an object + @throw type_error.321 if a value nested in @a j is discarded */ void write_bson(const BasicJsonType& j) { @@ -21388,12 +21657,30 @@ class binary_writer } /*! - @param[in] j JSON value to serialize + @param[in] j JSON value to serialize + @param[in] depth nesting level of @a j, counted from the top-level value + passed to @ref basic_json::to_cbor @throw type_error.316 if a string value or an object key is not valid UTF-8 + @throw type_error.321 if @a j or a value nested in it is discarded + + Serializing a container descends into its elements, so a value nested deeply + enough used to exhaust the call stack and terminate the process with no + exception to catch. The descent is bounded here: once @ref recursion_depth_limit + levels have been entered, @ref write_cbor_iterative writes out what is left + without the call stack. A value nested less deeply than that - all but a + vanishing minority - is written by exactly the code that always wrote it. + + @sa https://github.com/nlohmann/json/issues/5392 */ - void write_cbor(const BasicJsonType& j) + void write_cbor(const BasicJsonType& j, const std::size_t depth = 0) { + if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object())) + { + write_cbor_iterative(j); + return; + } + switch (j.type()) { case value_t::null: @@ -21475,10 +21762,9 @@ class binary_writer // step 1: write control byte and the array size write_cbor_head(0x80, j.m_data.m_value.array->size()); - // step 2: write each element for (const auto& el : *j.m_data.m_value.array) { - write_cbor(el); + write_cbor(el, depth + 1); } break; } @@ -21533,7 +21819,6 @@ class binary_writer // step 1: write control byte and the object size write_cbor_head(0xA0, j.m_data.m_value.object->size()); - // step 2: write each element for (const auto& el : *j.m_data.m_value.object) { // el.first is checked here, against the object as @@ -21548,14 +21833,14 @@ class binary_writer check_utf8(el.first, j); } write_cbor(el.first); - write_cbor(el.second); + write_cbor(el.second, depth + 1); } break; } case value_t::discarded: default: - break; + throw_on_discarded(j, "CBOR"); } } @@ -21614,10 +21899,22 @@ class binary_writer } /*! - @param[in] j JSON value to serialize + @param[in] j JSON value to serialize + @param[in] depth nesting level of @a j, counted from the top-level value + passed to @ref basic_json::to_msgpack + @throw type_error.321 if @a j or a value nested in it is discarded + + @sa @ref write_cbor + @sa https://github.com/nlohmann/json/issues/5392 */ - void write_msgpack(const BasicJsonType& j) + void write_msgpack(const BasicJsonType& j, const std::size_t depth = 0) { + if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object())) + { + write_msgpack_iterative(j); + return; + } + switch (j.type()) { case value_t::null: // nil @@ -21733,29 +22030,11 @@ class binary_writer case value_t::array: { // step 1: write control byte and the array size - const auto N = to_msgpack_length(j.m_data.m_value.array->size(), j); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // array 16 - oa.write_character(to_char_type(0xDC)); - write_number(static_cast(N)); - } - else - { - // array 32 - oa.write_character(to_char_type(0xDD)); - write_number(static_cast(N)); - } + write_msgpack_array_prefix(j.m_data.m_value.array->size(), j); - // step 2: write each element for (const auto& el : *j.m_data.m_value.array) { - write_msgpack(el); + write_msgpack(el, depth + 1); } break; } @@ -21851,26 +22130,8 @@ class binary_writer case value_t::object: { // step 1: write control byte and the object size - const auto N = to_msgpack_length(j.m_data.m_value.object->size(), j); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xF))); - } - else if (N <= (std::numeric_limits::max)()) - { - // map 16 - oa.write_character(to_char_type(0xDE)); - write_number(static_cast(N)); - } - else - { - // map 32 - oa.write_character(to_char_type(0xDF)); - write_number(static_cast(N)); - } + write_msgpack_object_prefix(j.m_data.m_value.object->size(), j); - // step 2: write each element for (const auto& el : *j.m_data.m_value.object) { // as in write_cbor, el.first is checked here against the @@ -21881,14 +22142,14 @@ class binary_writer check_utf8(el.first, j); } write_msgpack(el.first); - write_msgpack(el.second); + write_msgpack(el.second, depth + 1); } break; } case value_t::discarded: default: - break; + throw_on_discarded(j, "MessagePack"); } } @@ -21899,13 +22160,26 @@ class binary_writer @param[in] add_prefix whether prefixes need to be used for this value @param[in] use_bjdata whether write in BJData format, default is false @param[in] bjdata_version which BJData version to use, default is draft2 + @param[in] depth nesting level of @a j, counted from the top-level value + passed to @ref basic_json::to_ubjson or @ref basic_json::to_bjdata @throw type_error.316 if a string value or an object key is not valid UTF-8 + @throw type_error.321 if @a j or a value nested in it is discarded + + @sa @ref write_cbor + @sa https://github.com/nlohmann/json/issues/5392 */ void write_ubjson(const BasicJsonType& j, const bool use_count, const bool use_type, const bool add_prefix = true, - const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2) + const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2, + const std::size_t depth = 0) { + if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object())) + { + write_ubjson_iterative(j, use_count, use_type, add_prefix, use_bjdata, bjdata_version); + return; + } + const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3; switch (j.type()) @@ -21966,55 +22240,15 @@ class binary_writer case value_t::array: { - if (add_prefix) - { - oa.write_character(to_char_type('[')); - } - bool prefix_required = true; - if (use_type && !j.m_data.m_value.array->empty()) - { - if (!use_count) - { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); - } - const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); - const bool same_prefix = std::all_of(j.begin() + 1, j.end(), - [this, first_prefix, use_bjdata](const BasicJsonType & v) - { - return ubjson_prefix(v, use_bjdata) == first_prefix; - }); - - // an optimized array of a valueless type carries no payload, so a - // reader has nothing but the declared count to bound the allocation - // by and refuses an excessive one. Write the unoptimized form for - // those, at one byte per element, so the result can be read back. - // Objects are not affected: every element is preceded by its key. - const bool valueless_type = (first_prefix == 'Z' || first_prefix == 'T' || first_prefix == 'F'); - const bool excessive_valueless = valueless_type - && j.m_data.m_value.array->size() > detail::max_valueless_container_size; - - if (same_prefix && !excessive_valueless - && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) - { - prefix_required = false; - oa.write_character(to_char_type('$')); - oa.write_character(first_prefix); - } - } - - if (use_count) - { - oa.write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata); - } + const bool write_closer = write_ubjson_start_array(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); for (const auto& el : *j.m_data.m_value.array) { - write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version); + write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1); } - if (!use_count) + if (write_closer) { oa.write_character(to_char_type(']')); } @@ -22072,7 +22306,7 @@ class binary_writer case value_t::object: { - if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end()) + if (use_bjdata && is_bjdata_ndarray(j)) { if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) { @@ -22080,38 +22314,8 @@ class binary_writer } } - if (add_prefix) - { - oa.write_character(to_char_type('{')); - } - bool prefix_required = true; - if (use_type && !j.m_data.m_value.object->empty()) - { - if (!use_count) - { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); - } - const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); - const bool same_prefix = std::all_of(j.begin(), j.end(), - [this, first_prefix, use_bjdata](const BasicJsonType & v) - { - return ubjson_prefix(v, use_bjdata) == first_prefix; - }); - - if (same_prefix && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) - { - prefix_required = false; - oa.write_character(to_char_type('$')); - oa.write_character(first_prefix); - } - } - - if (use_count) - { - oa.write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata); - } + const bool write_closer = write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); for (const auto& el : *j.m_data.m_value.object) { @@ -22121,10 +22325,10 @@ class binary_writer oa.write_characters( reinterpret_cast(key.data()), key.size()); - write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version); + write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1); } - if (!use_count) + if (write_closer) { oa.write_character(to_char_type('}')); } @@ -22134,7 +22338,7 @@ class binary_writer case value_t::discarded: default: - break; + throw_on_discarded(j, use_bjdata ? "BJData" : "UBJSON"); } } @@ -22154,6 +22358,528 @@ class binary_writer } private: + /*! + @brief throws because @a j is discarded and cannot be serialized + @throw type_error.321 always + */ + JSON_HEDLEY_NO_RETURN static void throw_on_discarded(const BasicJsonType& j, const char* format_name) + { + static_cast(j); // unused when JSON_NOEXCEPTION is defined + static_cast(format_name); + JSON_THROW(type_error::create(321, concat("cannot serialize discarded value to ", format_name), &j)); + } + + void write_msgpack_array_prefix(const std::size_t N, const BasicJsonType& j) + { + const auto n = to_msgpack_length(N, j); + if (n <= 15) + { + // fixarray + write_number(static_cast(0x90 | n)); + } + else if (n <= (std::numeric_limits::max)()) + { + // array 16 + oa.write_character(to_char_type(0xDC)); + write_number(static_cast(n)); + } + else + { + // array 32 + oa.write_character(to_char_type(0xDD)); + write_number(static_cast(n)); + } + } + + void write_msgpack_object_prefix(const std::size_t N, const BasicJsonType& j) + { + const auto n = to_msgpack_length(N, j); + if (n <= 15) + { + // fixmap + write_number(static_cast(0x80 | (n & 0xF))); + } + else if (n <= (std::numeric_limits::max)()) + { + // map 16 + oa.write_character(to_char_type(0xDE)); + write_number(static_cast(n)); + } + else + { + // map 32 + oa.write_character(to_char_type(0xDF)); + write_number(static_cast(n)); + } + } + + /// @brief a CBOR or MessagePack array or object whose elements + /// @ref write_cbor_iterative or @ref write_msgpack_iterative is + /// still writing + struct binary_container_frame + { + explicit binary_container_frame(const BasicJsonType* value_) noexcept + : value(value_) + { + if (value->is_object()) + { + object_it = value->m_data.m_value.object->cbegin(); + } + else + { + array_it = value->m_data.m_value.array->cbegin(); + } + } + + // declared for GCC's -Weffc++, which asks for them in a class with + // pointer members and a non-trivial destructor; the exception + // specifications are left implicit, as GCC 4.8 rejects explicit ones + // that differ from them + binary_container_frame(const binary_container_frame&) = default; + binary_container_frame(binary_container_frame&&) = default; + binary_container_frame& operator=(const binary_container_frame&) = default; + binary_container_frame& operator=(binary_container_frame&&) = default; + ~binary_container_frame() = default; + + /// the array or object being written + const BasicJsonType* value; + /// value's elements still to write; which of the two is live follows + /// from the type of value. They are kept side by side rather than in + /// a union, which would need its special members written out by + /// hand, see detail/iterators/internal_iterator.hpp + typename BasicJsonType::object_t::const_iterator object_it{}; + typename BasicJsonType::array_t::const_iterator array_it{}; + }; + + /*! + @brief write @a j with @ref write_cbor, or write its header and push a + frame for @ref write_cbor_iterative to continue with its elements + + A scalar, and an empty array or object, are written out in full: there is + nothing below them for @ref write_cbor_iterative to come back to, so + nothing is pushed for them. + */ + void write_cbor_value_or_push(const BasicJsonType& j, std::vector& stack) + { + if (j.is_array()) + { + write_cbor_head(0x80, j.m_data.m_value.array->size()); + if (!j.m_data.m_value.array->empty()) + { + stack.emplace_back(&j); + } + return; + } + + if (j.is_object()) + { + write_cbor_head(0xA0, j.m_data.m_value.object->size()); + if (!j.m_data.m_value.object->empty()) + { + stack.emplace_back(&j); + } + return; + } + + write_cbor(j); + } + + /*! + @brief write out @a root and everything below it without the call stack + + Emits the same bytes as @ref write_cbor, keeping the containers it has + entered on an explicit stack instead of descending into them. Only reached + for values nested deeper than @ref recursion_depth_limit, which is why it + is not written for speed. + */ + void write_cbor_iterative(const BasicJsonType& root) + { + // only a container with elements is ever pushed; see write_cbor_value_or_push + std::vector stack; + write_cbor_value_or_push(root, stack); + + while (!stack.empty()) + { + const binary_container_frame current = stack.back(); + + if (current.value->is_array()) + { + const auto& array = *current.value->m_data.m_value.array; + if (current.array_it == array.cend()) + { + stack.pop_back(); + continue; + } + + // read the child before pushing: entering it can move every frame + const BasicJsonType* child = &(*current.array_it); + ++stack.back().array_it; + write_cbor_value_or_push(*child, stack); + } + else + { + const auto& object = *current.value->m_data.m_value.object; + if (current.object_it == object.cend()) + { + stack.pop_back(); + continue; + } + + // el.first is checked here, against the object as diagnostics + // context, like the matching check in write_cbor's object case + if (error_handler == error_handler_t::strict) + { + check_utf8(current.object_it->first, *current.value); + } + write_cbor(current.object_it->first); + const BasicJsonType* child = &(current.object_it->second); + ++stack.back().object_it; + write_cbor_value_or_push(*child, stack); + } + } + } + + /*! + @brief write @a j with @ref write_msgpack, or write its header and push a + frame for @ref write_msgpack_iterative to continue with its elements + + @sa @ref write_cbor_value_or_push + */ + void write_msgpack_value_or_push(const BasicJsonType& j, std::vector& stack) + { + if (j.is_array()) + { + write_msgpack_array_prefix(j.m_data.m_value.array->size(), j); + if (!j.m_data.m_value.array->empty()) + { + stack.emplace_back(&j); + } + return; + } + + if (j.is_object()) + { + write_msgpack_object_prefix(j.m_data.m_value.object->size(), j); + if (!j.m_data.m_value.object->empty()) + { + stack.emplace_back(&j); + } + return; + } + + write_msgpack(j); + } + + /*! + @brief write out @a root and everything below it without the call stack + + @sa @ref write_cbor_iterative + */ + void write_msgpack_iterative(const BasicJsonType& root) + { + std::vector stack; + write_msgpack_value_or_push(root, stack); + + while (!stack.empty()) + { + const binary_container_frame current = stack.back(); + + if (current.value->is_array()) + { + const auto& array = *current.value->m_data.m_value.array; + if (current.array_it == array.cend()) + { + stack.pop_back(); + continue; + } + + const BasicJsonType* child = &(*current.array_it); + ++stack.back().array_it; + write_msgpack_value_or_push(*child, stack); + } + else + { + const auto& object = *current.value->m_data.m_value.object; + if (current.object_it == object.cend()) + { + stack.pop_back(); + continue; + } + + if (error_handler == error_handler_t::strict) + { + check_utf8(current.object_it->first, *current.value); + } + write_msgpack(current.object_it->first); + const BasicJsonType* child = &(current.object_it->second); + ++stack.back().object_it; + write_msgpack_value_or_push(*child, stack); + } + } + } + + /// @return true when a closing ']' still has to be written after the elements + bool write_ubjson_start_array(const BasicJsonType& j, const bool use_count, const bool use_type, + const bool add_prefix, const bool use_bjdata, bool& prefix_required) + { + prefix_required = true; + if (add_prefix) + { + oa.write_character(to_char_type('[')); + } + + if (use_type && !j.m_data.m_value.array->empty()) + { + if (!use_count) + { + JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + } + const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix, use_bjdata](const BasicJsonType & v) + { + return ubjson_prefix(v, use_bjdata) == first_prefix; + }); + + // an optimized array of a valueless type carries no payload, so a + // reader has nothing but the declared count to bound the allocation + // by and refuses an excessive one. Write the unoptimized form for + // those, at one byte per element, so the result can be read back. + // Objects are not affected: every element is preceded by its key. + const bool valueless_type = (first_prefix == 'Z' || first_prefix == 'T' || first_prefix == 'F'); + const bool excessive_valueless = valueless_type + && j.m_data.m_value.array->size() > detail::max_valueless_container_size; + + if (same_prefix && !excessive_valueless + && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) + { + prefix_required = false; + oa.write_character(to_char_type('$')); + oa.write_character(first_prefix); + } + } + + if (use_count) + { + oa.write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata); + } + + return !use_count; + } + + /// @return true when a closing '}' still has to be written after the elements + bool write_ubjson_start_object(const BasicJsonType& j, const bool use_count, const bool use_type, + const bool add_prefix, const bool use_bjdata, bool& prefix_required) + { + prefix_required = true; + if (add_prefix) + { + oa.write_character(to_char_type('{')); + } + + if (use_type && !j.m_data.m_value.object->empty()) + { + if (!use_count) + { + JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + } + const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix, use_bjdata](const BasicJsonType & v) + { + return ubjson_prefix(v, use_bjdata) == first_prefix; + }); + + if (same_prefix && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix))) + { + prefix_required = false; + oa.write_character(to_char_type('$')); + oa.write_character(first_prefix); + } + } + + if (use_count) + { + oa.write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata); + } + + return !use_count; + } + + /*! + @brief whether @a j is a BJData ND-array annotation object + (https://github.com/NeuroJSON/jdata) + + Used by both the recursive object case of @ref write_ubjson and + @ref write_ubjson_value_or_push, which must agree on what counts as an + ND-array: @a j is only actually written as one once @ref + write_bjdata_ndarray has also accepted its contents. + + @pre @a j.is_object() + */ + static bool is_bjdata_ndarray(const BasicJsonType& j) + { + const auto& object = *j.m_data.m_value.object; + return object.size() == 3 + && object.find("_ArrayType_") != object.end() + && object.find("_ArraySize_") != object.end() + && object.find("_ArrayData_") != object.end(); + } + + /// @brief an object or array @ref write_ubjson_iterative is still writing + /// the elements of + struct ubjson_frame + { + ubjson_frame(const BasicJsonType* value_, const bool prefix_required_) noexcept + : value(value_) + , prefix_required(prefix_required_) + { + if (value->is_object()) + { + object_it = value->m_data.m_value.object->cbegin(); + } + else + { + array_it = value->m_data.m_value.array->cbegin(); + } + } + + // declared for GCC's -Weffc++, which asks for them in a class with + // pointer members and a non-trivial destructor; the exception + // specifications are left implicit, as GCC 4.8 rejects explicit ones + // that differ from them + ubjson_frame(const ubjson_frame&) = default; + ubjson_frame(ubjson_frame&&) = default; + ubjson_frame& operator=(const ubjson_frame&) = default; + ubjson_frame& operator=(ubjson_frame&&) = default; + ~ubjson_frame() = default; + + /// the array or object being written + const BasicJsonType* value; + /// whether value's elements each carry their own type marker; an + /// optimized ($type) container writes it once for all of them instead + bool prefix_required; + typename BasicJsonType::object_t::const_iterator object_it{}; + typename BasicJsonType::array_t::const_iterator array_it{}; + }; + + /*! + @brief write @a j with @ref write_ubjson, or write its header and push a + frame for @ref write_ubjson_iterative to continue with its elements + + @param[in] add_prefix whether @a j's own type marker is written now (the + elements of an optimized container, and everything below the + top level, never repeat it) + + @sa @ref write_cbor_value_or_push + */ + void write_ubjson_value_or_push(const BasicJsonType& j, const bool add_prefix, const bool use_count, + const bool use_type, const bool use_bjdata, const bjdata_version_t bjdata_version, + std::vector& stack) + { + if (!j.is_array() && !j.is_object()) + { + write_ubjson(j, use_count, use_type, add_prefix, use_bjdata, bjdata_version); + return; + } + + if (use_bjdata && j.is_object() && is_bjdata_ndarray(j) + && !write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) + { + // fully written as an ND-array: nothing below it to come back to + return; + } + + const bool is_array = j.is_array(); + bool prefix_required = true; + if (is_array) + { + write_ubjson_start_array(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); + } + else + { + write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required); + } + + const bool empty = is_array ? j.m_data.m_value.array->empty() : j.m_data.m_value.object->empty(); + if (!empty) + { + stack.emplace_back(&j, prefix_required); + return; + } + + // write_ubjson_start_array/_object return !use_count, i.e. whether a + // closer still has to be written; use_count is constant for the whole + // document, so that is recomputed here instead of being carried along + if (!use_count) + { + oa.write_character(to_char_type(is_array ? ']' : '}')); + } + } + + /*! + @brief write out @a root and everything below it without the call stack + + @sa @ref write_cbor_iterative + */ + void write_ubjson_iterative(const BasicJsonType& root, const bool use_count, const bool use_type, + const bool add_prefix, const bool use_bjdata, const bjdata_version_t bjdata_version) + { + std::vector stack; + write_ubjson_value_or_push(root, add_prefix, use_count, use_type, use_bjdata, bjdata_version, stack); + + while (!stack.empty()) + { + const ubjson_frame current = stack.back(); + const BasicJsonType& j = *current.value; + + if (j.is_array()) + { + const auto& array = *j.m_data.m_value.array; + if (current.array_it == array.cend()) + { + if (!use_count) + { + oa.write_character(to_char_type(']')); + } + stack.pop_back(); + continue; + } + + const BasicJsonType* child = &(*current.array_it); + const bool child_prefix = current.prefix_required; + ++stack.back().array_it; + write_ubjson_value_or_push(*child, child_prefix, use_count, use_type, use_bjdata, bjdata_version, stack); + } + else + { + const auto& object = *j.m_data.m_value.object; + if (current.object_it == object.cend()) + { + if (!use_count) + { + oa.write_character(to_char_type('}')); + } + stack.pop_back(); + continue; + } + + string_t storage; + const string_t& key = sanitize_utf8_for_write(current.object_it->first, j, storage); + write_number_with_ubjson_prefix(key.size(), true, use_bjdata); + oa.write_characters( + reinterpret_cast(key.data()), + key.size()); + const BasicJsonType* child = &(current.object_it->second); + const bool child_prefix = current.prefix_required; + ++stack.back().object_it; + write_ubjson_value_or_push(*child, child_prefix, use_count, use_type, use_bjdata, bjdata_version, stack); + } + } + } + ////////// // BSON // ////////// @@ -22405,6 +23131,7 @@ class binary_writer into a byte, before anything is written @throw type_error.316 if @a j is a string that is not valid UTF-8, before anything is written + @throw type_error.321 if @a j is discarded */ std::size_t calc_bson_value_size(const BasicJsonType& j) { @@ -22431,10 +23158,12 @@ class binary_writer case value_t::null: return 0ul; + case value_t::discarded: + throw_on_discarded(j, "BSON"); + // LCOV_EXCL_START case value_t::object: case value_t::array: - case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return 0ul; @@ -22471,10 +23200,12 @@ class binary_writer case value_t::null: return write_bson_null(name); + case value_t::discarded: + throw_on_discarded(j, "BSON"); + // LCOV_EXCL_START case value_t::object: case value_t::array: - case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return; @@ -22541,6 +23272,8 @@ class binary_writer byte, before anything is written @throw type_error.316 if a string value or a key is not valid UTF-8, before anything is written + @throw type_error.321 if a value nested in @a document is discarded, + before anything is written */ std::size_t calc_bson_sizes(const BasicJsonType& document, std::vector& nested_sizes) { @@ -23050,16 +23783,31 @@ class binary_writer /*! @brief validate (dry_run) or write one BJData ND-array element of dtype 'd' (single precision) - @return whether @a el's value fits a float without overflow; always true when @a dry_run is false + @return whether @a el's value survives narrowing to float and back without any change + (so the ND-array round-trips exactly), or is infinite or NaN; always true when + @a dry_run is false */ bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run) { const auto dval = el.template get(); if (dry_run) { - return !std::isfinite(dval) || - (dval >= static_cast(std::numeric_limits::lowest()) && - dval <= static_cast((std::numeric_limits::max)())); +#ifdef __GNUC__ + JSON_HEDLEY_DIAGNOSTIC_PUSH + JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal") +#endif + // a value that would be rounded (rather than exactly represented) by the + // narrowing to float is treated like an out-of-range integer element; this + // is the same criterion write_compact_float() uses for CBOR/MessagePack + const bool in_range = std::isnan(dval) || + (dval >= static_cast(std::numeric_limits::lowest()) && + dval <= static_cast((std::numeric_limits::max)()) && + static_cast(static_cast(dval)) == dval) || + std::isinf(dval); +#ifdef __GNUC__ + JSON_HEDLEY_DIAGNOSTIC_POP +#endif + return in_range; } write_number(static_cast(dval), true); return true; @@ -24187,8 +24935,8 @@ boundaries compute_boundaries(FloatType value) // // -e <= 60 or e >= -60 := alpha -constexpr int kAlpha = -60; -constexpr int kGamma = -32; +JSON_INLINE_VARIABLE constexpr int kAlpha = -60; +JSON_INLINE_VARIABLE constexpr int kGamma = -32; struct cached_power // c = f * 2^e ~= 10^k { @@ -26878,6 +27626,9 @@ public: for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) { + // false positive: Infer's model of std::string keeps the buffer of a + // moved-from string, so it assumes a buffer is destroyed twice + // @infer-ignore USE_AFTER_DELETE it->~value_type(); // destroy but keep allocation new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it } @@ -27179,6 +27930,70 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// SAX interface type, see @ref nlohmann::json_sax using json_sax_t = json_sax; + //////////////////////////////////////////////////////////////////////////////// + // utility templates to create a json type with different template parameters // + //////////////////////////////////////////////////////////////////////////////// + + /// Json type using a different type for storing objects + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class ObjectType2> + using with_object_t = basic_json; + + /// Json type using a different type for storing arrays + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class ArrayType2> + using with_array_t = basic_json; + + /// Json type using a different type for storing strings + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_string_t = basic_json; + + /// Json type using a different type for storing booleans + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_boolean_t = basic_json; + + /// Json type using different types for storing signed and unsigned integers + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_integers_t = basic_json; + + /// Json type using a different type for storing floating point numbers + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_float_t = basic_json; + + /// Json type using a different type as base allocator + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class AllocatorType2> + using with_allocator_t = basic_json; + + /// Json type using a different type as json serializer + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template class JSONSerializer2> + using with_json_serializer_t = basic_json; + + /// Json type using a different type for storing binary data + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_binary_t = basic_json; + + /// Json type using a different type as base class + /// @sa https://json.nlohmann.me/api/basic_json/with_t/ + template + using with_base_class_t = basic_json; + //////////////// // exceptions // //////////////// @@ -27565,100 +28380,252 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// constructor for rvalue binary arrays (internal type) json_value(binary_t&& value) : binary(create(std::move(value))) {} - void destroy(value_t t) + /// constructors taking ownership of an already created value + explicit json_value(string_t* value) noexcept : string(value) {} + explicit json_value(object_t* value) noexcept : object(value) {} + explicit json_value(array_t* value) noexcept : array(value) {} + +private: + // raw, allocation-free transfer of m_data from src to dst: no + // set_parents()/assert_invariant() (the former is O(#children) per + // call under JSON_DIAGNOSTICS, which would make the walk below + // quadratic); dst takes ownership, src is left as value_t::null. + static void take(basic_json& dst, basic_json& src) noexcept + { + dst.m_data.m_type = src.m_data.m_type; + dst.m_data.m_value = src.m_data.m_value; + src.m_data.m_type = value_t::null; + } + + // true if v is not an array/object, or is an already-empty one + static bool has_no_children(const basic_json& v) noexcept + { + switch (v.m_data.m_type) + { + case value_t::array: + return v.m_data.m_value.array->empty(); + case value_t::object: + return v.m_data.m_value.object->empty(); + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return true; + } + } + + // The walk in destroy_container() may take the children of a + // container in any order, as long as it picks the same child again + // while that container is not modified in between. Arrays and + // objects with bidirectional iterators (std::map, ordered_map, ...) + // use their last child, which a vector-based container can remove + // in O(1). ObjectType only needs forward iterators, though (e.g. + // std::unordered_map), so other objects use their first child. + template + static typename ObjectType_::iterator walk_child_it(ObjectType_& o, std::bidirectional_iterator_tag /*unused*/) + { + return std::prev(o.end()); + } + + template + static typename ObjectType_::iterator walk_child_it(ObjectType_& o, std::forward_iterator_tag /*unused*/) + { + return o.begin(); + } + + template + static typename ObjectType_::iterator walk_child_it(ObjectType_& o) + { + JSON_ASSERT(!o.empty()); + return walk_child_it(o, typename std::iterator_traits::iterator_category()); + } + + // the child of a non-empty array/object v that the walk in + // destroy_container() continues with (see walk_child_it() above) + static basic_json& walk_child(basic_json& v) + { + if (v.m_data.m_type == value_t::array) + { + return v.m_data.m_value.array->back(); + } + JSON_ASSERT(v.m_data.m_type == value_t::object); + return walk_child_it(*v.m_data.m_value.object)->second; + } + + // removes walk_child(v) from a non-empty array/object v; this never + // allocates, and since it is only ever called when that child is a + // scalar or an already-empty array/object, destroying it never + // recurses more than one level deep (see destroy() below) + static void pop_walk_child(basic_json& v) + { + if (v.m_data.m_type == value_t::array) + { + v.m_data.m_value.array->pop_back(); + } + else + { + JSON_ASSERT(v.m_data.m_type == value_t::object); + v.m_data.m_value.object->erase(walk_child_it(*v.m_data.m_value.object)); + } + } + + // deallocates the (already empty) array/object held by v; this is + // the same allocator-based free the old recursive implementation + // used, just factored out so every level of the walk in destroy() + // can share it + static void free_container(basic_json& v) noexcept + { + if (v.m_data.m_type == value_t::array) + { + JSON_ASSERT(v.m_data.m_value.array->empty()); + AllocatorType alloc; + std::allocator_traits::destroy(alloc, v.m_data.m_value.array); + std::allocator_traits::deallocate(alloc, v.m_data.m_value.array, 1); + } + else + { + JSON_ASSERT(v.m_data.m_type == value_t::object); + JSON_ASSERT(v.m_data.m_value.object->empty()); + AllocatorType alloc; + std::allocator_traits::destroy(alloc, v.m_data.m_value.object); + std::allocator_traits::deallocate(alloc, v.m_data.m_value.object, 1); + } + v.m_data.m_type = value_t::null; // avoid a double free if v is later destructed + } + +public: + void destroy_string() noexcept + { + if (string == nullptr) + { + // not initialized (e.g., due to exception in the ctor) + return; + } + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + } + + void destroy_binary() noexcept + { + if (binary == nullptr) + { + // not initialized (e.g., due to exception in the ctor) + return; + } + AllocatorType alloc; + std::allocator_traits::destroy(alloc, binary); + std::allocator_traits::deallocate(alloc, binary, 1); + } + + // t must be value_t::array or value_t::object + void destroy_container(value_t t) noexcept { if ( (t == value_t::object && object == nullptr) || - (t == value_t::array && array == nullptr) || - (t == value_t::string && string == nullptr) || - (t == value_t::binary && binary == nullptr) + (t == value_t::array && array == nullptr) ) { // not initialized (e.g., due to exception in the ctor) return; } - if (t == value_t::array || t == value_t::object) + + // Destroy the tree without recursing per nesting level and + // without any heap allocation: a heap-allocated flattening + // stack (the previous implementation) can itself throw + // bad_alloc, which would escape this noexcept destructor and + // terminate the program (#5135). + // + // Instead, walk down a chain of children (always the one + // walk_child() picks), reversing links as we go: cur is the + // container currently being emptied, and prev is its parent + // (value_t::null when there is none). Each parent's + // walk_child() slot doubles as storage for that parent's own + // parent link while we are below it, so no extra memory is + // needed; the parent is not modified meanwhile, so + // walk_child() finds that same slot again on the way up. We + // only ever remove a child once it is a scalar or an empty + // array/object, which neither allocates nor recurses more + // than one level deep. + // + // This json_value is not itself a basic_json, so the + // top-level container is first moved into a local stand-in + // ("cur"); a default-constructed basic_json has a null + // pointer in its m_value (see data::m_value's initializer), + // so swapping it with *this leaves this union's own pointer + // null, and it is never looked at or freed a second time. + basic_json cur; + cur.m_data.m_type = t; + using std::swap; + swap(cur.m_data.m_value, *this); + + basic_json prev; // value_t::null: no parent + + while (true) { - // flatten the current json_value to a heap-allocated stack - std::vector stack; - - // move the top-level items to stack - if (t == value_t::array) + if (has_no_children(cur)) { - stack.reserve(array->size()); - std::move(array->begin(), array->end(), std::back_inserter(stack)); - } - else - { - stack.reserve(object->size()); - for (auto&& it : *object) + if (prev.m_data.m_type == value_t::null) { - stack.push_back(std::move(it.second)); - } - } - - while (!stack.empty()) - { - // move the last item to a local variable to be processed - basic_json current_item(std::move(stack.back())); - stack.pop_back(); - - // if current_item is array/object, move - // its children to the stack to be processed later - if (current_item.is_array()) - { - std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack)); - - current_item.m_data.m_value.array->clear(); - } - else if (current_item.is_object()) - { - for (auto&& it : *current_item.m_data.m_value.object) - { - stack.push_back(std::move(it.second)); - } - - current_item.m_data.m_value.object->clear(); + free_container(cur); + return; // back at the top with nothing left to do } - // it's now safe that current_item gets destructed - // since it doesn't have any children + // ascend: detach the grandparent link from prev's + // walk_child() slot, drop that (now null) slot, free cur + // (it is empty), then move up one level + basic_json gp; + take(gp, walk_child(prev)); + pop_walk_child(prev); + + free_container(cur); + + take(cur, prev); + take(prev, gp); + continue; } + + basic_json& cur_child_ref = walk_child(cur); + + if (has_no_children(cur_child_ref)) + { + // scalar, or already-empty array/object + pop_walk_child(cur); + continue; + } + + // descend into the non-empty child, reversing the + // link: its slot takes over prev, and the child becomes + // the new cur + basic_json tmp; + take(tmp, cur_child_ref); + take(cur_child_ref, prev); + take(prev, cur); + take(cur, tmp); } + } + void destroy(value_t t) + { switch (t) { - case value_t::object: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, object); - std::allocator_traits::deallocate(alloc, object, 1); - break; - } - - case value_t::array: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, array); - std::allocator_traits::deallocate(alloc, array, 1); - break; - } - case value_t::string: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, string); - std::allocator_traits::deallocate(alloc, string, 1); + destroy_string(); break; - } case value_t::binary: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, binary); - std::allocator_traits::deallocate(alloc, binary, 1); + destroy_binary(); + break; + + case value_t::object: + case value_t::array: + destroy_container(t); break; - } case value_t::null: case value_t::boolean: @@ -27667,9 +28634,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::number_float: case value_t::discarded: default: - { break; - } } } }; @@ -27750,6 +28715,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #endif } + /// @brief replace the stored value with an already created one + /// The new value must be created before calling this function: if its + /// creation throws, the current value is left untouched. + void replace_value(value_t t, const json_value& v) noexcept + { + m_data.m_value.destroy(m_data.m_type); + m_data.m_value = v; + m_data.m_type = t; + set_parents(); + assert_invariant(); + } + iterator set_parents(iterator it, std::ptrdiff_t count_set_parents) { #if JSON_DIAGNOSTICS @@ -28979,6 +29956,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec bool type_deduction = true, value_t manual_type = value_t::array) { +#if JSON_BRACE_INIT_COPY_SEMANTICS + // a single element that is a value rather than a braced list is + // copied or moved as is, whatever its content looks like + if (type_deduction && init.size() == 1 && !init.begin()->is_braced_list()) + { + *this = init.begin()->moved_or_copied(); + set_parents(); + assert_invariant(); + return; + } +#endif + // check if each element is an array with two elements whose first // element is a string bool is_an_object = std::all_of(init.begin(), init.end(), @@ -29009,8 +29998,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (is_an_object) { // the initializer list is a list of pairs -> create an object - m_data.m_type = value_t::object; m_data.m_value = value_t::object; + m_data.m_type = value_t::object; for (auto& element_ref : init) { @@ -29032,8 +30021,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } #endif // the initializer list describes an array -> create an array - m_data.m_type = value_t::array; m_data.m_value.array = create(init.begin(), init.end()); + m_data.m_type = value_t::array; } set_parents(); @@ -29046,8 +30035,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(const typename binary_t::container_type& init) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = init; + res.m_data.m_type = value_t::binary; return res; } @@ -29057,8 +30046,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = binary_t(init, subtype); + res.m_data.m_type = value_t::binary; return res; } @@ -29068,8 +30057,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(typename binary_t::container_type&& init) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = std::move(init); + res.m_data.m_type = value_t::binary; return res; } @@ -29079,8 +30068,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); - res.m_data.m_type = value_t::binary; res.m_data.m_value = binary_t(std::move(init), subtype); + res.m_data.m_type = value_t::binary; return res; } @@ -30445,9 +31434,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec && !std::is_same>::value, int > = 0 > JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) ValueType value(const ::nlohmann::json_pointer& ptr, const ValueType& default_value) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return value(ptr.convert(), default_value); } +#endif template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type::type, detail::enable_if_t < @@ -30456,9 +31449,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec && !std::is_same>::value, int > = 0 > JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) ReturnType value(const ::nlohmann::json_pointer& ptr, ValueType && default_value) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return value(ptr.convert(), std::forward(default_value)); } +#endif /// @brief access the first element /// @sa https://json.nlohmann.me/api/basic_json/front/ @@ -30816,9 +31813,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) bool contains(const typename ::nlohmann::json_pointer& ptr) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.contains(this); } +#endif /// @} @@ -30929,9 +31930,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) static iteration_proxy iterator_wrapper(reference ref) noexcept +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ref.items(); } +#endif /// @brief wrapper to access iterator member functions in range-based for /// @sa https://json.nlohmann.me/api/basic_json/items/ @@ -30940,9 +31945,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) static iteration_proxy iterator_wrapper(const_reference ref) noexcept +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ref.items(); } +#endif /// @brief helper to access iterator member functions in range-based for /// @sa https://json.nlohmann.me/api/basic_json/items/ @@ -32031,7 +33040,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template requires std::is_scalar_v - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) <= rhs; } @@ -32040,7 +33049,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template requires std::is_scalar_v - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) >= rhs; } @@ -32061,11 +33070,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #endif } + // The friend comparisons with a scalar name the JSON type via decltype of + // their parameter in noexcept, because older MSVC versions do not see the + // class scope there: MSVC 2015 and 2017 take basic_json as the template, + // and MSVC 2019 16.0 rejects member types and template parameters. + /// @brief comparison: equal /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ template::value, int>::type = 0> - friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs == basic_json(rhs); } @@ -32074,7 +33088,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ template::value, int>::type = 0> - friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) == rhs; } @@ -32090,7 +33104,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ template::value, int>::type = 0> - friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs != basic_json(rhs); } @@ -32099,7 +33113,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ template::value, int>::type = 0> - friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) != rhs; } @@ -32119,7 +33133,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ template::value, int>::type = 0> - friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs < basic_json(rhs); } @@ -32128,7 +33142,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ template::value, int>::type = 0> - friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) < rhs; } @@ -32148,7 +33162,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template::value, int>::type = 0> - friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs <= basic_json(rhs); } @@ -32157,7 +33171,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template::value, int>::type = 0> - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) <= rhs; } @@ -32178,7 +33192,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ template::value, int>::type = 0> - friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs > basic_json(rhs); } @@ -32187,7 +33201,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ template::value, int>::type = 0> - friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) > rhs; } @@ -32207,7 +33221,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template::value, int>::type = 0> - friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return lhs >= basic_json(rhs); } @@ -32216,7 +33230,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template::value, int>::type = 0> - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible, ScalarType>::value) { return basic_json(lhs) >= rhs; } @@ -32252,6 +33266,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return o; } +#if !JSON_DELETE_DEPRECATED_FUNCTIONS + // the deleted version is a function template after the class, because + // GCC < 5 and Clang < 10 reject deleted friend functions in class templates /// @brief serialize to stream /// @sa https://json.nlohmann.me/api/operator_ltlt/ /// @deprecated This function is deprecated since 3.0.0 and will be removed in @@ -32263,6 +33280,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { return o << j; } +#endif #endif // JSON_NO_IO /// @} @@ -32314,12 +33332,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool allow_exceptions = true, const bool ignore_comments = false, const bool ignore_trailing_commas = false) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { basic_json result; auto p = parser(i.get(), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas); p.parse(true, result); return result; } +#endif /// @brief check if the input is valid JSON /// @sa https://json.nlohmann.me/api/basic_json/accept/ @@ -32349,9 +33371,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static bool accept(detail::span_input_adapter&& i, const bool ignore_comments = false, const bool ignore_trailing_commas = false) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true); } +#endif /// @brief generate SAX events /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ @@ -32361,12 +33387,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false) + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { auto ia = detail::input_adapter(std::forward(i)); return format == input_format_t::json ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) - : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict); + : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict, tag_handler); } /// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support) @@ -32378,12 +33405,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false) + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { auto ia = detail::input_adapter(std::move(first), std::move(last)); return format == input_format_t::json ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) - : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict); + : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict, tag_handler); } /// @brief generate SAX events @@ -32411,19 +33439,27 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false, - const bool ignore_trailing_commas = false) + const bool ignore_trailing_commas = false, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { auto ia = i.get(); return format == input_format_t::json // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) ? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict); + : detail::binary_reader(std::move(ia), format).sax_parse(sax, strict, tag_handler); } +#endif #if defined(__clang__) #pragma clang diagnostic pop #endif #ifndef JSON_NO_IO +#if !JSON_DELETE_DEPRECATED_FUNCTIONS + // the deleted version is a function template after the class, because + // GCC < 5 and Clang < 10 reject deleted friend functions in class templates /// @brief deserialize from stream /// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in @@ -32435,6 +33471,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec { return operator>>(i, j); } +#endif /// @brief deserialize from stream /// @sa https://json.nlohmann.me/api/operator_gtgt/ @@ -32782,9 +33819,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) @@ -32792,9 +33833,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler); } +#endif /// @brief create a JSON value from an input in MessagePack format /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ @@ -32827,18 +33872,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json from_msgpack(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_msgpack(ptr, ptr + len, strict, allow_exceptions); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions); } +#endif /// @brief create a JSON value from an input in UBJSON format /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ @@ -32871,18 +33924,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json from_ubjson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_ubjson(ptr, ptr + len, strict, allow_exceptions); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions); } +#endif /// @brief create a JSON value from an input in BJData format /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ @@ -32909,6 +33970,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len)) + static basic_json from_bjdata(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else + { + return from_bjdata(ptr, ptr + len, strict, allow_exceptions); + } +#endif + /// @brief create a JSON value from an input in BON8 format /// @sa https://json.nlohmann.me/api/basic_json/from_bon8/ template @@ -32932,6 +34007,20 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions); } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len)) + static basic_json from_bon8(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else + { + return from_bon8(ptr, ptr + len, strict, allow_exceptions); + } +#endif + /// @brief create a JSON value from an input in BSON format /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ template @@ -32963,18 +34052,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static basic_json from_bson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_bson(ptr, ptr + len, strict, allow_exceptions); } +#endif JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions); } +#endif /// @} ////////////////////////// @@ -32994,9 +34091,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) reference operator[](const ::nlohmann::json_pointer& ptr) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_unchecked(this); } +#endif /// @brief access specified element via JSON Pointer /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ @@ -33008,9 +34109,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) const_reference operator[](const ::nlohmann::json_pointer& ptr) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_unchecked(this); } +#endif /// @brief access specified element via JSON Pointer /// @sa https://json.nlohmann.me/api/basic_json/at/ @@ -33022,9 +34127,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) reference at(const ::nlohmann::json_pointer& ptr) +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_checked(this); } +#endif /// @brief access specified element via JSON Pointer /// @sa https://json.nlohmann.me/api/basic_json/at/ @@ -33036,9 +34145,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template::value, int> = 0> JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) const_reference at(const ::nlohmann::json_pointer& ptr) const +#if JSON_DELETE_DEPRECATED_FUNCTIONS + = delete; +#else { return ptr.get_checked(this); } +#endif /// @brief return flattened JSON value /// @sa https://json.nlohmann.me/api/basic_json/flatten/ @@ -34015,6 +35128,18 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j) return j.dump(); } +#if JSON_DELETE_DEPRECATED_FUNCTIONS && !defined(JSON_NO_IO) + /// @brief serialize to stream (deleted; use operator<<(std::ostream&, const basic_json&)) + /// @sa https://json.nlohmann.me/api/operator_ltlt/ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + std::ostream& operator>>(const NLOHMANN_BASIC_JSON_TPL& j, std::ostream& o) = delete; + + /// @brief deserialize from stream (deleted; use operator>>(std::istream&, basic_json&)) + /// @sa https://json.nlohmann.me/api/operator_gtgt/ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + std::istream& operator<<(NLOHMANN_BASIC_JSON_TPL& j, std::istream& i) = delete; +#endif + NLOHMANN_JSON_NAMESPACE_END /////////////////////// @@ -34198,6 +35323,8 @@ struct formatter // NOLINT(cert-dcl58-c #undef JSON_PRECISE_STREAM_POSITION #undef JSON_STRICT_NUL_HANDLING #undef JSON_STRICT_BINARY_UTF8 + #undef JSON_DELETE_DEPRECATED_FUNCTIONS + #undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS #endif // #include diff --git a/single_include/nlohmann/json_fwd.hpp b/single_include/nlohmann/json_fwd.hpp index 7cadc9b1c..7b8aa5bfd 100644 --- a/single_include/nlohmann/json_fwd.hpp +++ b/single_include/nlohmann/json_fwd.hpp @@ -67,6 +67,10 @@ #define JSON_STRICT_BINARY_UTF8 0 #endif +#ifndef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0 +#endif + #if JSON_DIAGNOSTICS #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag #else @@ -109,14 +113,20 @@ #define NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8 #endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS _ekmo +#else + #define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS +#endif + #ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) json_abi ## a ## b ## c ## d ## e ## f ## g -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h) json_abi ## a ## b ## c ## d ## e ## f ## g ## h +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ @@ -126,7 +136,8 @@ NLOHMANN_JSON_ABI_TAG_BRACE_INIT_COPY_SEMANTICS, \ NLOHMANN_JSON_ABI_TAG_PRECISE_STREAM_POSITION, \ NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING, \ - NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8) + NLOHMANN_JSON_ABI_TAG_STRICT_BINARY_UTF8, \ + NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aac6fee5e..e092616b7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,7 @@ set(JSON_SIMDUTF_VERSION 9.1.0 CACHE STRING "The simdutf version used by JSON_Te set(JSON_32bitTest AUTO CACHE STRING "Enable the 32bit unit test (ON/OFF/AUTO/ONLY).") set(JSON_TestStandards "" CACHE STRING "The list of standards to test explicitly.") +set(JSON_TestShard "" CACHE STRING "Build only a part of the unit tests, given as / (e.g. 0/2), to split them across CI jobs with a time limit.") # using an env var, since this will also affect targets executing cmake (such as "ci_test_compiler_default") if (NOT "" STREQUAL "$ENV{JSON_FORCED_GLOBAL_COMPILE_OPTIONS}") @@ -134,12 +135,17 @@ json_test_set_test_options(test-disabled_exceptions #$<$:/EH> ) -# raise timeout of expensive Unicode test -json_test_set_test_options(test-unicode4 TEST_PROPERTIES TIMEOUT 3000) - # only the #972 regression test needs thirdparty/fifo_map on its include path json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include) +# GCC's false -Warray-bounds error with JSON_DIAGNOSTICS only shows up when optimizing (#5742). +# -O3 makes the optimizer-driven warnings of the ci_test_gcc flag set (-Winline, +# -Wsuggest-attribute=...) fire on the library's inline functions; they are not +# what this test checks, so turn them off for it. +json_test_set_test_options(test-diagnostics-optimized + COMPILE_OPTIONS $<$:-O3 -Werror=array-bounds -Wno-inline -Wno-suggest-attribute=pure -Wno-suggest-attribute=const> +) + ############################################################################# # add unit tests ############################################################################# @@ -288,6 +294,33 @@ elseif(NOT json_32bit_test) list(FILTER files EXCLUDE REGEX src/unit-32bit.cpp) endif() +# with JSON_TestShard=/, keep every -th unit test file, +# starting at (the glob is sorted, so the split is stable) +set(test_shard_index 0) +if(NOT "${JSON_TestShard}" STREQUAL "") + if(NOT JSON_TestShard MATCHES "^([0-9]+)/([1-9][0-9]*)$") + message(FATAL_ERROR "JSON_TestShard must be /, e.g. 0/2, not '${JSON_TestShard}'.") + endif() + set(test_shard_index ${CMAKE_MATCH_1}) + set(test_shard_count ${CMAKE_MATCH_2}) + if(NOT test_shard_index LESS test_shard_count) + message(FATAL_ERROR "JSON_TestShard: the index must be less than the count, not '${JSON_TestShard}'.") + endif() + list(LENGTH files test_file_count) + set(shard_files "") + set(file_position 0) + foreach(file ${files}) + math(EXPR file_shard "${file_position} % ${test_shard_count}") + if(file_shard EQUAL test_shard_index) + list(APPEND shard_files ${file}) + endif() + math(EXPR file_position "${file_position} + 1") + endforeach() + set(files ${shard_files}) + list(LENGTH files shard_file_count) + message(STATUS "Test shard ${JSON_TestShard}: ${shard_file_count} of ${test_file_count} unit test files") +endif() + foreach(file ${files}) json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}) endforeach() @@ -305,6 +338,9 @@ if(json_32bit_test_only) return() endif() +# the following variants of single test files are only built in the first shard +if(test_shard_index EQUAL 0) + # test legacy comparison of discarded values json_test_set_test_options(test-comparison_legacy COMPILE_DEFINITIONS JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1 @@ -332,6 +368,8 @@ json_test_add_test_for(src/unit-diagnostic-positions.cpp MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force} ) +endif() + # *DO NOT* use json_test_set_test_options() below this line ############################################################################# diff --git a/tests/abi/config/default.cpp b/tests/abi/config/default.cpp index e4c627060..d42e883f0 100644 --- a/tests/abi/config/default.cpp +++ b/tests/abi/config/default.cpp @@ -48,6 +48,10 @@ TEST_CASE("default namespace") expected += "_sbu8"; #endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + expected += "_ekmo"; +#endif + expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR); expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR); expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_PATCH) "::basic_json"; diff --git a/tests/abi/config/noversion.cpp b/tests/abi/config/noversion.cpp index 858964695..ec406c716 100644 --- a/tests/abi/config/noversion.cpp +++ b/tests/abi/config/noversion.cpp @@ -49,6 +49,10 @@ TEST_CASE("default namespace without version component") expected += "_sbu8"; #endif +#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + expected += "_ekmo"; +#endif + expected += "::basic_json"; // fallback for Clang diff --git a/tests/fuzzing.md b/tests/fuzzing.md index b7c2da27f..329cdbf58 100644 --- a/tests/fuzzing.md +++ b/tests/fuzzing.md @@ -3,6 +3,14 @@ Each parser of the library (JSON, BJData, BON8, BSON, CBOR, MessagePack, and UBJSON) can be fuzz tested. Currently, [libFuzzer](https://llvm.org/docs/LibFuzzer.html) and [afl++](https://github.com/AFLplusplus/AFLplusplus) are supported. +## What the fuzzers check + +Each fuzzer driver (`tests/src/fuzzer-parse_*.cpp`) parses its input twice: once with `allow_exceptions = false` and +once with exceptions. Both calls must agree. Where parsing with exceptions fails, the call without exceptions must +return a discarded value (or throw the same kind of non-parse error), and it must never throw a `parse_error`. Where +parsing succeeds, both calls must return the same value. The drivers then serialize the value, parse the result back, +and check that nothing was lost. The drivers check all of this with `assert`, so they refuse to build with `NDEBUG`. + ## Corpus creation For most effective fuzzing, a [corpus](https://llvm.org/docs/LibFuzzer.html#corpus) should be provided. A corpus is a @@ -54,6 +62,9 @@ Then pass the corpus directory as command-line argument (assuming it is located The fuzzer should be able to run indefinitely without crashing. In case of a crash, the tested input is dumped into a file starting with `crash-`. +To also detect memory leaks, build with AddressSanitizer (`FUZZER_ENGINE="-fsanitize=fuzzer,address"`): libFuzzer then +runs LeakSanitizer by default (`-detect_leaks=1`). LeakSanitizer is not available with Apple Clang on macOS. + ## afl++ To use afl++, you need to pass `-fsanitize=fuzzer` as `FUZZER_ENGINE`. It will be replaced by a `libAFLDriver.a` to @@ -76,7 +87,9 @@ directory `out`. The library is further fuzz-tested 24/7 by Google's [OSS-Fuzz project](https://github.com/google/oss-fuzz). It uses the same `fuzzers` target as above and also relies on the `FUZZER_ENGINE` variable. See the used -[build script](https://github.com/google/oss-fuzz/blob/master/projects/json/build.sh) for more information. +[build script](https://github.com/google/oss-fuzz/blob/master/projects/json/build.sh) for more information. Its default +`address` sanitizer includes LeakSanitizer, so OSS-Fuzz and the CIFuzz workflow (`.github/workflows/cifuzz.yml`) report +memory leaks, too. In case the build at OSS-Fuzz fails, an issue will be created automatically. diff --git a/tests/src/fuzzer-parse_bjdata.cpp b/tests/src/fuzzer-parse_bjdata.cpp index 62a0609bf..6302db104 100644 --- a/tests/src/fuzzer-parse_bjdata.cpp +++ b/tests/src/fuzzer-parse_bjdata.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = from_bjdata(data, allow_exceptions = false) - j1 = from_bjdata(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - vec2 = to_bjdata(j1, use_size = false, use_type = false) - vec3 = to_bjdata(j1, use_size = true, use_type = false) - vec4 = to_bjdata(j1, use_size = true, use_type = true) @@ -59,6 +61,13 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + // value-stable comparison for the round-trip checks below; see the note // above on why this compares dump()s rather than the json values directly static bool is_value_stable(const json& lhs, const json& rhs) @@ -69,11 +78,37 @@ static bool is_value_stable(const json& lhs, const json& rhs) // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector const vec1(data, data + size); + + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::from_bjdata(vec1, true, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input - std::vector const vec1(data, data + size); json const j1 = json::from_bjdata(vec1); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -107,14 +142,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::type_error&) { // type errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors may happen if provided sizes are excessive + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/fuzzer-parse_bon8.cpp b/tests/src/fuzzer-parse_bon8.cpp index 416d91fd0..8d9a119fa 100644 --- a/tests/src/fuzzer-parse_bon8.cpp +++ b/tests/src/fuzzer-parse_bon8.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = from_bon8(data, allow_exceptions = false) - j1 = from_bon8(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - vec = to_bon8(j1) - j2 = from_bon8(vec) - assert(to_bon8(j2) == vec) @@ -34,6 +36,13 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + namespace { // the serialization of the value read from @a input, or the error message @@ -61,11 +70,37 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) assert(read_bon8(std::vector(data, data + size)) == read_bon8(stream)); } + std::vector const vec1(data, data + size); + + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::from_bon8(vec1, true, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input - std::vector const vec1(data, data + size); json const j1 = json::from_bon8(vec1); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -87,14 +122,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::type_error&) { // type errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors may happen if provided sizes are excessive + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/fuzzer-parse_bson.cpp b/tests/src/fuzzer-parse_bson.cpp index 86e0c38a5..357bc7eb2 100644 --- a/tests/src/fuzzer-parse_bson.cpp +++ b/tests/src/fuzzer-parse_bson.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = from_bson(data, allow_exceptions = false) - j1 = from_bson(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - vec = to_bson(j1) - j2 = from_bson(vec) - assert(to_bson(j2) == vec) @@ -29,14 +31,47 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector const vec1(data, data + size); + + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::from_bson(vec1, true, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input - std::vector const vec1(data, data + size); json const j1 = json::from_bson(vec1); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -58,14 +93,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::type_error&) { // type errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/fuzzer-parse_cbor.cpp b/tests/src/fuzzer-parse_cbor.cpp index 3cc204d8b..1574e8aee 100644 --- a/tests/src/fuzzer-parse_cbor.cpp +++ b/tests/src/fuzzer-parse_cbor.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = from_cbor(data, allow_exceptions = false) - j1 = from_cbor(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - vec = to_cbor(j1) - j2 = from_cbor(vec) - assert(to_cbor(j2) == vec) @@ -29,14 +31,47 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector const vec1(data, data + size); + + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::from_cbor(vec1, true, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input - std::vector const vec1(data, data + size); json const j1 = json::from_cbor(vec1); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -58,14 +93,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::type_error&) { // type errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/fuzzer-parse_json.cpp b/tests/src/fuzzer-parse_json.cpp index 02ba16611..c0dd969f3 100644 --- a/tests/src/fuzzer-parse_json.cpp +++ b/tests/src/fuzzer-parse_json.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = parse(data, allow_exceptions = false) - j1 = parse(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - s1 = serialize(j1) - j2 = parse(s1) - s2 = serialize(j2) @@ -30,13 +32,45 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::parse(data, data + size, nullptr, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input json const j1 = json::parse(data, data + size); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -63,10 +97,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors may happen if provided sizes are excessive + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/fuzzer-parse_msgpack.cpp b/tests/src/fuzzer-parse_msgpack.cpp index 343e5c0c2..9ab2aadd8 100644 --- a/tests/src/fuzzer-parse_msgpack.cpp +++ b/tests/src/fuzzer-parse_msgpack.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = from_msgpack(data, allow_exceptions = false) - j1 = from_msgpack(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - vec = to_msgpack(j1) - j2 = from_msgpack(vec) - assert(to_msgpack(j2) == vec) @@ -29,14 +31,47 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector const vec1(data, data + size); + + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::from_msgpack(vec1, true, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input - std::vector const vec1(data, data + size); json const j1 = json::from_msgpack(vec1); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -58,14 +93,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::type_error&) { // type errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors may happen if provided sizes are excessive + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/fuzzer-parse_ubjson.cpp b/tests/src/fuzzer-parse_ubjson.cpp index fcaf16061..9750286ae 100644 --- a/tests/src/fuzzer-parse_ubjson.cpp +++ b/tests/src/fuzzer-parse_ubjson.cpp @@ -10,7 +10,9 @@ This file implements a parser test suitable for fuzz testing. Given a byte array data, it performs the following steps: +- j0 = from_ubjson(data, allow_exceptions = false) - j1 = from_ubjson(data) +- assert(j0 is discarded if parsing j1 fails, and j0 == j1 otherwise) - vec2 = to_ubjson(j1, use_size = false, use_type = false) - vec3 = to_ubjson(j1, use_size = true, use_type = false) - vec4 = to_ubjson(j1, use_size = true, use_type = true) @@ -38,14 +40,47 @@ drivers. using json = nlohmann::json; +// compares dumps rather than values, because NaN != NaN; keep writes strings +// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw +static bool same_value(const json& lhs, const json& rhs) +{ + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); +} + // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector const vec1(data, data + size); + + // step 0: parse input without exceptions; a parse error must then be + // reported as a discarded value, never thrown + json j_noexcept; + bool noexcept_threw = false; + try + { + j_noexcept = json::from_ubjson(vec1, true, false); + } + catch (const json::parse_error&) + { + assert(false); + } + catch (const json::exception&) + { + // type and out-of-range errors are not parse errors and still throw + noexcept_threw = true; + } + // whether step 1 succeeded; if not, the catch blocks below check that + // step 0 failed, too + bool parsed = false; + try { // step 1: parse input - std::vector const vec1(data, data + size); json const j1 = json::from_ubjson(vec1); + parsed = true; + + // without exceptions, the same input must give the same value + assert(!noexcept_threw && !j_noexcept.is_discarded() && same_value(j_noexcept, j1)); try { @@ -77,14 +112,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::type_error&) { // type errors can occur during parsing, too + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } catch (const json::out_of_range&) { // out of range errors may happen if provided sizes are excessive + assert(parsed || noexcept_threw || j_noexcept.is_discarded()); } // return 0 - non-zero return values are reserved for future use diff --git a/tests/src/test_utils.hpp b/tests/src/test_utils.hpp index 8f7bd06a0..58f1f5409 100644 --- a/tests/src/test_utils.hpp +++ b/tests/src/test_utils.hpp @@ -8,6 +8,7 @@ #pragma once +#include // array #include // uint8_t #include // size_t #include // ifstream, ios @@ -43,6 +44,33 @@ T next_integer_sample(T i, T last, T stride) return n < last ? n : last; } +// UTF-8 continuation bytes in [lo, hi] that stand in for all of them in the +// ill-formed UTF-8 tests. Both the lexer's range checks and the serializer's +// decoder (detail::decode) only distinguish the classes 0x80..0x8F, 0x90..0x9F, +// and 0xA0..0xBF, so the first and last byte of each class within [lo, hi] +// exercise every behavior while a test sweeps another byte position through +// all 256 values (#5418). Define JSON_TEST_UTF8_EXHAUSTIVE to get every byte. +inline std::vector utf8_continuation_bytes(int lo, int hi) +{ + std::vector result; +#ifdef JSON_TEST_UTF8_EXHAUSTIVE + for (int byte = lo; byte <= hi; ++byte) + { + result.push_back(byte); + } +#else + static const std::array class_ends = {{0x80, 0x8F, 0x90, 0x9F, 0xA0, 0xBF}}; + for (const int byte : class_ends) + { + if (lo <= byte && byte <= hi) + { + result.push_back(byte); + } + } +#endif + return result; +} + inline std::vector read_binary_file(const std::string& filename) { std::ifstream file(filename, std::ios::binary); diff --git a/tests/src/unit-allocator.cpp b/tests/src/unit-allocator.cpp index bc283ab28..07eb21c4e 100644 --- a/tests/src/unit-allocator.cpp +++ b/tests/src/unit-allocator.cpp @@ -12,6 +12,11 @@ #include using nlohmann::json; +#include +#if JSON_HAS_RANGES + #include +#endif + namespace { // special test case to check if memory is leaked if constructor throws @@ -48,14 +53,7 @@ TEST_CASE("bad_alloc") SECTION("bad_alloc") { // create JSON type using the throwing allocator - using bad_json = nlohmann::basic_json; + using bad_json = nlohmann::json::with_allocator_t; // creating an object should throw CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&); @@ -129,14 +127,7 @@ void my_allocator_clean_up(T* p) TEST_CASE("controlled bad_alloc") { // create JSON type using the throwing allocator - using my_json = nlohmann::basic_json; + using my_json = nlohmann::json::with_allocator_t; SECTION("class json_value") { @@ -521,6 +512,10 @@ struct countdown_allocator : std::allocator TEST_CASE("converting a deeply nested value from another specialization fails cleanly (#5650)") { + // MSVC 2015's debug STL constructs the containers' debug proxies through + // the allocator in noexcept constructors, so a failing construction crashes + // the program there instead of throwing std::bad_alloc. Nothing to check. +#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0) using countdown_json = nlohmann::basic_json 0); +#endif } namespace @@ -588,17 +584,265 @@ TEST_CASE("bad my_allocator::construct") { SECTION("my_allocator::construct doesn't forward") { - using bad_alloc_json = nlohmann::basic_json; + using bad_alloc_json = nlohmann::json::with_allocator_t; bad_alloc_json j; j["test"] = bad_alloc_json::array_t(); j["test"].push_back("should not leak"); } } + +namespace +{ +std::size_t counting_allocator_allocations = 0; +std::size_t counting_allocator_deallocations = 0; + +template +struct counting_allocator : std::allocator +{ + using std::allocator::allocator; + + T* allocate(std::size_t n) + { + ++counting_allocator_allocations; + return std::allocator::allocate(n); + } + + void deallocate(T* p, std::size_t n) + { + ++counting_allocator_deallocations; + std::allocator::deallocate(p, n); + } + + template + struct rebind + { + using other = counting_allocator; + }; +}; +} // namespace + +TEST_CASE("destructor performs no allocation, only deallocation") +{ + // see https://github.com/nlohmann/json/issues/4842 and + // https://github.com/nlohmann/json/issues/5135: destroying nested + // arrays/objects used to allocate a temporary stack (first with + // std::allocator, later - after #4842 - with the provided allocator). + // Since that stack could itself throw bad_alloc from inside the + // noexcept destructor (#5135), destroy() no longer allocates anything: + // it only ever frees what is already there. + using counting_json = nlohmann::basic_json; + + SECTION("array") + { + auto* j = new counting_json({1, {2, {3, 4}}, 5}); // NOLINT(cppcoreguidelines-owning-memory) + const auto allocations_before = counting_allocator_allocations; + const auto deallocations_before = counting_allocator_deallocations; + delete j; // NOLINT(cppcoreguidelines-owning-memory) + CHECK(counting_allocator_allocations == allocations_before); + CHECK(counting_allocator_deallocations > deallocations_before); + } + + SECTION("object") + { + auto* j = new counting_json({{"a", {{"b", {1, 2}}}}, {"c", 3}}); // NOLINT(cppcoreguidelines-owning-memory) + const auto allocations_before = counting_allocator_allocations; + const auto deallocations_before = counting_allocator_deallocations; + delete j; // NOLINT(cppcoreguidelines-owning-memory) + CHECK(counting_allocator_allocations == allocations_before); + CHECK(counting_allocator_deallocations > deallocations_before); + } + + SECTION("mixed tree of empty/non-empty arrays and objects") + { + auto* j = new counting_json( // NOLINT(cppcoreguidelines-owning-memory) + { + {"empty_obj", counting_json::object()}, + {"empty_arr", counting_json::array()}, + {"nested", {{"a", counting_json::array({1, 2, counting_json::object()})}, {"b", 3}}}, + {"tail", counting_json::array({counting_json::array({1}), 2, counting_json::array({3})})} + }); + const auto allocations_before = counting_allocator_allocations; + const auto deallocations_before = counting_allocator_deallocations; + delete j; // NOLINT(cppcoreguidelines-owning-memory) + CHECK(counting_allocator_allocations == allocations_before); + CHECK(counting_allocator_deallocations > deallocations_before); + } +} + +// the no-exceptions CI job skips every CHECK_THROWS_AS, which would leave +// next_construct_fails set for the next allocation outside a check +#if !defined(JSON_NOEXCEPTION) +TEST_CASE("a failed allocation leaves the value unchanged") +{ + // create JSON type using the throwing allocator + using my_json = nlohmann::basic_json; + + // Each of these creates a string, array, object, or binary value. The + // value must be created before the type is changed: otherwise, a failed + // creation left a value of the new type without anything behind it (an + // assertion in its destructor, a null pointer everywhere else) or, when + // an old value was destroyed first, with a pointer to that destroyed one. + + SECTION("creating a binary value") + { + const std::vector bytes = {1, 2, 3}; + my_json _; + + next_construct_fails = true; + CHECK_THROWS_AS(_ = my_json::binary(bytes), std::bad_alloc&); + next_construct_fails = true; + CHECK_THROWS_AS(_ = my_json::binary(bytes, 42), std::bad_alloc&); + next_construct_fails = true; + CHECK_THROWS_AS(_ = my_json::binary(std::vector(bytes)), std::bad_alloc&); + next_construct_fails = true; + CHECK_THROWS_AS(_ = my_json::binary(std::vector(bytes), 42), std::bad_alloc&); + next_construct_fails = false; + } + + SECTION("turning a null value into an array or object") + { + my_json j; + + next_construct_fails = true; + CHECK_THROWS_AS(j[0], std::bad_alloc&); + CHECK(j.is_null()); + + next_construct_fails = true; + CHECK_THROWS_AS(j["key"], std::bad_alloc&); + CHECK(j.is_null()); + +#ifdef JSON_HAS_CPP_17 + next_construct_fails = true; + CHECK_THROWS_AS(j[std::string_view("key")], std::bad_alloc&); + CHECK(j.is_null()); +#endif + + next_construct_fails = true; + CHECK_THROWS_AS(j.push_back(my_json(1)), std::bad_alloc&); + CHECK(j.is_null()); + + const my_json one = 1; + next_construct_fails = true; + CHECK_THROWS_AS(j.push_back(one), std::bad_alloc&); + CHECK(j.is_null()); + + next_construct_fails = true; + CHECK_THROWS_AS(j.push_back(my_json::object_t::value_type("key", 1)), std::bad_alloc&); + CHECK(j.is_null()); + + next_construct_fails = true; + CHECK_THROWS_AS(j.emplace_back(1), std::bad_alloc&); + CHECK(j.is_null()); + + next_construct_fails = true; + CHECK_THROWS_AS(j.emplace("key", 1), std::bad_alloc&); + CHECK(j.is_null()); + + const my_json object = {{"key", 1}}; + next_construct_fails = true; + CHECK_THROWS_AS(j.update(object), std::bad_alloc&); + CHECK(j.is_null()); + + next_construct_fails = false; + } + + // With iterator debugging, VS 2015's containers construct a proxy with the + // allocator in constructors that cannot report its failure, so a failing + // allocator crashes this section there (SIGSEGV with VS 2015 Debug x86). +#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0) + SECTION("converting into an existing value") + { + // to_json replaces the value it is given; the old one must survive a + // failed creation of the new one + my_json j = "old"; + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::string("new")), std::bad_alloc&); + CHECK(j == "old"); + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::vector {1, 2}), std::bad_alloc&); + CHECK(j == "old"); + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::vector {true, false}), std::bad_alloc&); + CHECK(j == "old"); + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::map {{"a", 1}}), std::bad_alloc&); + CHECK(j == "old"); + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, my_json::binary_t({1, 2})), std::bad_alloc&); + CHECK(j == "old"); + + // the overloads for lvalues of the value types, for the value types + // themselves, and for the remaining compatible types + const std::string string = "new"; + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, string), std::bad_alloc&); + CHECK(j == "old"); + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, "new"), std::bad_alloc&); + CHECK(j == "old"); + + // to_json only moves a binary value that it converted from another + // container type, which my_json's std::vector is not + using binary_constructor = nlohmann::detail::external_constructor; + next_construct_fails = true; + CHECK_THROWS_AS(binary_constructor::construct(j, my_json::binary_t({1, 2})), std::bad_alloc&); + CHECK(j == "old"); + + my_json::array_t array = {1, 2}; + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, array), std::bad_alloc&); + CHECK(j == "old"); + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::move(array)), std::bad_alloc&); + CHECK(j == "old"); + + my_json::object_t object = {{"a", 1}}; + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, object), std::bad_alloc&); + CHECK(j == "old"); + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::move(object)), std::bad_alloc&); + CHECK(j == "old"); + + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, std::valarray {1, 2}), std::bad_alloc&); + CHECK(j == "old"); + +#if JSON_HAS_RANGES && !defined(__MINGW32__) + const std::vector numbers = {1, 2}; + next_construct_fails = true; + CHECK_THROWS_AS(nlohmann::to_json(j, numbers | std::views::filter([](int /*unused*/) + { + return true; + })), std::bad_alloc&); + CHECK(j == "old"); +#endif + + next_construct_fails = false; + nlohmann::to_json(j, std::vector {1, 2}); + CHECK(j == my_json({1, 2})); + } +#endif +} +#endif diff --git a/tests/src/unit-alt-string.cpp b/tests/src/unit-alt-string.cpp index e503a4914..961cd742b 100644 --- a/tests/src/unit-alt-string.cpp +++ b/tests/src/unit-alt-string.cpp @@ -163,16 +163,7 @@ void int_to_string(alt_string& target, std::size_t value) target = std::to_string(value).c_str(); } -using alt_json = nlohmann::basic_json < - std::map, - std::vector, - alt_string, - bool, - std::int64_t, - std::uint64_t, - double, - std::allocator, - nlohmann::adl_serializer >; +using alt_json = nlohmann::json::with_string_t; bool operator<(const char* op1, const alt_string& op2) noexcept { diff --git a/tests/src/unit-binary_formats.cpp b/tests/src/unit-binary_formats.cpp index ed6d89911..3e5edf765 100644 --- a/tests/src/unit-binary_formats.cpp +++ b/tests/src/unit-binary_formats.cpp @@ -11,10 +11,15 @@ #include using nlohmann::json; +#include #include +#include +#include +#include +#include #include "make_test_data_available.hpp" -TEST_CASE("Binary Formats" * doctest::skip()) +TEST_CASE("Binary Formats") { SECTION("canada.json") { @@ -142,48 +147,6 @@ TEST_CASE("Binary Formats" * doctest::skip()) CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(84.963)); } - SECTION("jeopardy.json") - { - const auto* filename = TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"; - json j = json::parse(std::ifstream(filename)); - - const auto json_size = j.dump().size(); - const auto bjdata_1_size = json::to_bjdata(j).size(); - const auto bjdata_2_size = json::to_bjdata(j, true).size(); - const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); - const auto bon8_size = json::to_bon8(j).size(); - const auto bson_size = json::to_bson({{"", j}}).size(); // wrap array in object for BSON - const auto cbor_size = json::to_cbor(j).size(); - const auto msgpack_size = json::to_msgpack(j).size(); - const auto ubjson_1_size = json::to_ubjson(j).size(); - const auto ubjson_2_size = json::to_ubjson(j, true).size(); - const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); - - CHECK(json_size == 52508728); - CHECK(bjdata_1_size == 50710965); - CHECK(bjdata_2_size == 51144830); - CHECK(bjdata_3_size == 51144830); - CHECK(bon8_size == 45942080); - CHECK(bson_size == 56008520); - CHECK(cbor_size == 46187320); - CHECK(msgpack_size == 46158575); - CHECK(ubjson_1_size == 50710965); - CHECK(ubjson_2_size == 51144830); - CHECK(ubjson_3_size == 49861422); - - CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); - CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(96.576)); - CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(97.402)); - CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(97.402)); - CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(87.494)); - CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(106.665)); - CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(87.961)); - CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(87.906)); - CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(96.576)); - CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(97.402)); - CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(94.958)); - } - SECTION("sample.json") { const auto* filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json"; @@ -224,3 +187,183 @@ TEST_CASE("Binary Formats" * doctest::skip()) CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(89.450)); } } + +// jeopardy.json is 52 MB and produces ~500 MB of serialization output, so it +// is kept apart from the cheap corpus files above (#5418) +TEST_CASE("Binary Formats (jeopardy.json)" * doctest::skip()) +{ + const auto* filename = TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"; + json j = json::parse(std::ifstream(filename)); + + const auto json_size = j.dump().size(); + const auto bjdata_1_size = json::to_bjdata(j).size(); + const auto bjdata_2_size = json::to_bjdata(j, true).size(); + const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); + const auto bon8_size = json::to_bon8(j).size(); + const auto bson_size = json::to_bson({{"", j}}).size(); // wrap array in object for BSON + const auto cbor_size = json::to_cbor(j).size(); + const auto msgpack_size = json::to_msgpack(j).size(); + const auto ubjson_1_size = json::to_ubjson(j).size(); + const auto ubjson_2_size = json::to_ubjson(j, true).size(); + const auto ubjson_3_size = json::to_ubjson(j, true, true).size(); + + CHECK(json_size == 52508728); + CHECK(bjdata_1_size == 50710965); + CHECK(bjdata_2_size == 51144830); + CHECK(bjdata_3_size == 51144830); + CHECK(bon8_size == 45942080); + CHECK(bson_size == 56008520); + CHECK(cbor_size == 46187320); + CHECK(msgpack_size == 46158575); + CHECK(ubjson_1_size == 50710965); + CHECK(ubjson_2_size == 51144830); + CHECK(ubjson_3_size == 49861422); + + CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0)); + CHECK((100.0 * double(bjdata_1_size) / double(json_size)) == Approx(96.576)); + CHECK((100.0 * double(bjdata_2_size) / double(json_size)) == Approx(97.402)); + CHECK((100.0 * double(bjdata_3_size) / double(json_size)) == Approx(97.402)); + CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(87.494)); + CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(106.665)); + CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(87.961)); + CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(87.906)); + CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(96.576)); + CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(97.402)); + CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(94.958)); +} + +namespace +{ +// the binary formats as function pointers for "Binary formats with narrow number types"; +// named functions rather than lambdas, because clang 3.5 cannot convert a lambda +// to a function pointer in the braced initializer of the format table +using narrow_json = nlohmann::basic_json; +using bytes = std::vector; + +bytes encode_cbor(const json& j) +{ + return json::to_cbor(j); +} +narrow_json decode_cbor(const bytes& v, bool allow_exceptions) +{ + return narrow_json::from_cbor(v, true, allow_exceptions); +} + +bytes encode_msgpack(const json& j) +{ + return json::to_msgpack(j); +} +narrow_json decode_msgpack(const bytes& v, bool allow_exceptions) +{ + return narrow_json::from_msgpack(v, true, allow_exceptions); +} + +bytes encode_ubjson(const json& j) +{ + return json::to_ubjson(j); +} +narrow_json decode_ubjson(const bytes& v, bool allow_exceptions) +{ + return narrow_json::from_ubjson(v, true, allow_exceptions); +} + +bytes encode_bjdata(const json& j) +{ + return json::to_bjdata(j); +} +narrow_json decode_bjdata(const bytes& v, bool allow_exceptions) +{ + return narrow_json::from_bjdata(v, true, allow_exceptions); +} + +// BSON can only store numbers as object members +bytes encode_bson(const json& j) +{ + return json::to_bson(json{{"a", j}}); +} +narrow_json decode_bson(const bytes& v, bool allow_exceptions) +{ + const auto result = narrow_json::from_bson(v, true, allow_exceptions); + return result.is_discarded() ? result : result.at("a"); +} + +bytes encode_bon8(const json& j) +{ + return json::to_bon8(j); +} +narrow_json decode_bon8(const bytes& v, bool allow_exceptions) +{ + return narrow_json::from_bon8(v, true, allow_exceptions); +} + +} // namespace + +TEST_CASE("Binary formats with narrow number types") +{ + // Numbers that do not fit the number types are handled like the lexer + // handles them in JSON text: an integer that fits neither integer type is + // stored as a floating-point number, and a finite floating-point number + // that overflows number_float_t is rejected with out_of_range.406. + struct binary_format + { + const char* name; + bytes (*encode)(const json&); + narrow_json (*decode)(const bytes&, bool); + }; + + const std::vector formats = + { + {"CBOR", encode_cbor, decode_cbor}, + {"MessagePack", encode_msgpack, decode_msgpack}, + {"UBJSON", encode_ubjson, decode_ubjson}, + {"BJData", encode_bjdata, decode_bjdata}, + {"BSON", encode_bson, decode_bson}, + {"BON8", encode_bon8, decode_bon8}, + }; + + for (const auto& format : formats) + { + const std::string name = format.name; + INFO("format := ", name); + const auto roundtrip = [&format](const json & j) + { + return format.decode(format.encode(j), true); + }; + + // integers that fit keep their type + CHECK(roundtrip(json(-5)).is_number_integer()); + CHECK(roundtrip(json(-5)).get() == -5); + CHECK(roundtrip(json(3000000000u)).is_number_unsigned()); + CHECK(roundtrip(json(3000000000u)).get() == 3000000000u); + + // integers that fit neither integer type are stored as float + CHECK(roundtrip(json(5000000000u)).is_number_float()); + CHECK(roundtrip(json(5000000000u)).get() == 5000000000.0f); + if (name != "BON8") // BON8 cannot encode integers above INT64_MAX + { + CHECK(roundtrip(json(10000000000000000000u)).is_number_float()); + CHECK(roundtrip(json(10000000000000000000u)).get() == 10000000000000000000.0f); + } + CHECK(roundtrip(json(-3000000000LL)).is_number_float()); + CHECK(roundtrip(json(-3000000000LL)).get() == -3000000000.0f); + CHECK(roundtrip(json(-5000000000LL)).is_number_float()); + CHECK(roundtrip(json(-5000000000LL)).get() == -5000000000.0f); + + // floating-point numbers that fit + CHECK(roundtrip(json(1.5)).get() == 1.5f); + const auto just_above_max = std::nextafter(static_cast((std::numeric_limits::max)()), + std::numeric_limits::infinity()); + CHECK(roundtrip(json(just_above_max)).get() == (std::numeric_limits::max)()); + + // infinity and NaN are passed on + CHECK(std::isinf(roundtrip(json(std::numeric_limits::infinity())).get())); + CHECK(std::isnan(roundtrip(json(std::numeric_limits::quiet_NaN())).get())); + + // finite floating-point numbers that overflow number_float_t are rejected + const std::string message = "[json.exception.out_of_range.406] syntax error while parsing " + name + + " value: number overflow"; + CHECK_THROWS_WITH_AS(roundtrip(json(1e300)), message.c_str(), narrow_json::out_of_range&); + CHECK_THROWS_WITH_AS(roundtrip(json(-1e300)), message.c_str(), narrow_json::out_of_range&); + CHECK(format.decode(format.encode(json(1e300)), false).is_discarded()); + } +} diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index 0098541cf..2518f3386 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -9,8 +9,17 @@ #include "doctest_compatibility.h" #define JSON_TESTS_PRIVATE +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; +using ordered_json = nlohmann::ordered_json; #include #include @@ -106,10 +115,59 @@ TEST_CASE("BJData") { SECTION("discarded") { - // discarded values are not serialized + // a discarded value cannot be serialized to BJData json const j = json::value_t::discarded; - const auto result = json::to_bjdata(j); - CHECK(result.empty()); + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error&); + } + + SECTION("discarded values nested in a container") + { + json const discarded = json::value_t::discarded; + + SECTION("in an array") + { + json const j = {1, discarded, 2}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] (/1) cannot serialize discarded value to BJData", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error&); +#endif + } + + SECTION("as an object value") + { + json j; + j["a"] = 1; + j["b"] = discarded; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] (/b) cannot serialize discarded value to BJData", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error&); +#endif + } + + SECTION("nested deeper (array in object in array)") + { + json inner_array = {1, discarded}; + json middle_object; + middle_object["x"] = inner_array; + json const j = {middle_object}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] (/0/x/1) cannot serialize discarded value to BJData", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bjdata(j), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error&); +#endif + } + + SECTION("optimized array of all-discarded elements") + { + json const j = {discarded, discarded}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bjdata(j, true, true), "[json.exception.type_error.321] (/0) cannot serialize discarded value to BJData", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bjdata(j, true, true), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error&); +#endif + } } SECTION("null") @@ -1229,6 +1287,32 @@ TEST_CASE("BJData") CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec2), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1A", json::parse_error); std::vector const vec3 = {'H', 'i', 2, '1', '.'}; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec3), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1.", json::parse_error); + // Reject NULs where they are read, including trailing NULs and payloads cut off after one. + SECTION("NUL in high-precision number (issue #5753)") + { + for (const auto& vec : std::vector> + { + {'H', 'i', 3, '1', 0, 'x'}, + {'H', 'i', 2, '1', 0}, + {'H', 'i', 3, '1', 0} + }) + { + CAPTURE(vec) + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text; last byte: 0x00", json::parse_error); + CHECK(json::from_bjdata(vec, true, false).is_discarded()); + CHECK(json::from_bjdata(vec, false, false).is_discarded()); + } + + std::vector const nested = {'[', 'H', 'i', 3, '1', 0, 'x', ']'}; + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(nested), "[json.exception.parse_error.115] parse error at byte 6: syntax error while parsing BJData high-precision number: invalid number text; last byte: 0x00", json::parse_error); + CHECK(json::from_bjdata(nested, true, false).is_discarded()); + + std::vector const valid = {'H', 'i', 1, '1'}; + const auto j = json::from_bjdata(valid); + CHECK(j.is_number_unsigned()); + CHECK(j == json(1)); + } + std::vector const vec_overflow = {'H', 'i', 5, '1', 'e', '4', '0', '0'}; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec_overflow), "[json.exception.out_of_range.406] number overflow parsing '1e400'", json::out_of_range); std::vector const vec4 = {'H', 2, '1', '0'}; @@ -2175,29 +2259,33 @@ TEST_CASE("BJData") SECTION("start_array() in ndarray _ArraySize_") { + // _ArrayType_ (2 events: key + string) is now emitted before + // _ArraySize_ (see GitHub issue #5661), which shifts the events + // below later by the same 2 events std::vector const v = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 2, 1, 1, 2}; - SaxCountdown scp(2); + SaxCountdown scp(4); CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata)); } SECTION("number_integer() in ndarray _ArraySize_") { std::vector const v = {'[', '$', 'U', '#', '[', '$', 'i', '#', 'i', 2, 2, 1, 1, 2}; - SaxCountdown scp(3); + SaxCountdown scp(5); CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata)); } SECTION("key() in ndarray _ArrayType_") { + // _ArrayType_ is emitted right after start_object(), before _ArraySize_ std::vector const v = {'[', '$', 'U', '#', '[', '$', 'U', '#', 'i', 2, 2, 2, 1, 2, 3, 4}; - SaxCountdown scp(6); + SaxCountdown scp(1); CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata)); } SECTION("string() in ndarray _ArrayType_") { std::vector const v = {'[', '$', 'U', '#', '[', '$', 'U', '#', 'i', 2, 2, 2, 1, 2, 3, 4}; - SaxCountdown scp(7); + SaxCountdown scp(2); CHECK_FALSE(json::sax_parse(v, &scp, json::input_format_t::bjdata)); } @@ -2800,6 +2888,22 @@ TEST_CASE("BJData") CHECK(out_single.at(0) == '{'); CHECK(json::from_bjdata(out_single) == j_single); + // a double element that is finite and within the range of "single" + // but is not exactly representable as a float, so narrowing it would + // silently round it (0.1 is read back as 0.10000000149011612); this, + // like the overflow case above, falls back to a plain object (see + // GitHub issue #5661) + json const j_single_rounded = json({{"_ArrayType_", "single"}, {"_ArraySize_", {2, 1}}, {"_ArrayData_", {1.5, 0.1}}}); + const auto out_single_rounded = json::to_bjdata(j_single_rounded); + CHECK(out_single_rounded.at(0) == '{'); + CHECK(json::from_bjdata(out_single_rounded) == j_single_rounded); + + // a double element that underflows to 0 when narrowed to "single" + json const j_single_underflow = json({{"_ArrayType_", "single"}, {"_ArraySize_", {2, 1}}, {"_ArrayData_", {1.5, 1e-300}}}); + const auto out_single_underflow = json::to_bjdata(j_single_underflow); + CHECK(out_single_underflow.at(0) == '{'); + CHECK(json::from_bjdata(out_single_underflow) == j_single_underflow); + // in-range boundary values still use the compact ndarray encoding json const j_uint8_ok = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", {2, 1}}, {"_ArrayData_", {0, 255}}}); CHECK(json::to_bjdata(j_uint8_ok) == std::vector({'[', '$', 'U', '#', '[', 'i', 2, 'i', 1, ']', 0, 255})); @@ -2813,6 +2917,23 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(out_single_ok) == json({{"_ArrayType_", "single"}, {"_ArraySize_", {2, 1}}, {"_ArrayData_", {1.5f, -1.5f}}})); } + SECTION("ndarray annotation keys are read back in the documented order") + { + // from_bjdata() must emit the annotation object's keys in the order + // used throughout the documentation, _ArrayType_, _ArraySize_, + // _ArrayData_: the type marker precedes the dimension vector on the + // wire (see get_ubjson_size_type()), so it is known, and emitted, + // before _ArraySize_. For a plain json this key order is invisible + // (its comparison ignores it), but for an ordered_json it is not (see + // GitHub issue #5661). + const ordered_json o = ordered_json::parse(R"({"_ArrayType_":"uint8","_ArraySize_":[2,2],"_ArrayData_":[1,2,3,4]})"); + const auto packed = ordered_json::to_bjdata(o); + CHECK(packed.at(0) == '['); + const ordered_json o_back = ordered_json::from_bjdata(packed); + CHECK(o_back == o); + CHECK(o_back.dump() == o.dump()); + } + SECTION("ndarray that would not be read back as an annotated object stays as object") { // the reader only restores an annotated object from an ND-array @@ -4490,3 +4611,79 @@ TEST_CASE("BJData roundtrips" * doctest::skip()) } } } + +TEST_CASE("issue #5648 - from_bjdata(ptr, len) must read len bytes, not treat ptr as a C string") +{ + // to_bjdata() encodes the integer 0 as the two bytes 'i' 0x00 (a BJData + // type marker followed by the value byte 0x00), so the packed data + // below contains a 0x00 byte before its end. + const json j = {{"a", 0}}; + const std::vector packed = json::to_bjdata(j); + bool contains_nul = false; + for (const auto byte : packed) + { + contains_nul |= (byte == 0x00); + } + REQUIRE(contains_nul); + +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED + // before the fix, from_bjdata had no (ptr, len) overload, so this call + // bound to from_bjdata(InputType&&, bool strict) instead: ptr was read + // as a NUL-terminated C string (stopping at the embedded 0x00 byte), and + // len was silently converted to the strict flag. The deprecated + // overload added for this issue forwards to from_bjdata(ptr, ptr + len, + // ...) instead, like from_ubjson's deprecated (ptr, len) overload does. + json result; + CHECK_NOTHROW(result = json::from_bjdata(packed.data(), packed.size())); + CHECK(result == j); + + // len must not collapse into the strict flag either + CHECK(json::from_bjdata(packed.data(), packed.size(), false) == j); +#endif +} + +TEST_CASE("BJData large strings and binaries (chunked reader)") +{ + // Strings share get_ubjson_string() -> get_string() -> get_bytes() with + // plain UBJSON. Binary values are different: only a Draft 3 optimized + // array (type marker 'B') is read back as a binary value, through + // get_binary() -> get_bytes() (see parse_ubjson_internal()'s "If BJData + // type marker is 'B'" branch); Draft 2 (the default) writes a binary + // value as a plain array of uint8_t numbers instead (see the "round trip + // of a binary value is value-stable, not byte-stable" test above), which + // never reaches get_bytes(). Both reads happen in bounded chunks + // (binary_reader.hpp, chunk_size == 4096); check lengths around and + // beyond that size, for both vector (iterator) and pointer inputs. + for (const std::size_t len : + { + std::size_t{0}, std::size_t{1}, std::size_t{4095}, std::size_t{4096}, + std::size_t{4097}, std::size_t{8192}, std::size_t{100000} + }) + { + CAPTURE(len) + + // string + const json j_string = std::string(len, 'x'); + const std::vector v_string = json::to_bjdata(j_string); + CHECK(json::from_bjdata(v_string) == j_string); + // pointer input exercises the std::memcpy fast path + CHECK(json::from_bjdata(reinterpret_cast(v_string.data()), + reinterpret_cast(v_string.data()) + v_string.size()) == j_string); + + // binary, forced into the Draft 3 optimized ('B' marker) encoding + const json j_binary = json::binary(std::vector(len, 0xCD)); + const std::vector v_binary = json::to_bjdata(j_binary, true, true, json::bjdata_version_t::draft3); + CHECK(json::from_bjdata(v_binary) == j_binary); + CHECK(json::from_bjdata(reinterpret_cast(v_binary.data()), + reinterpret_cast(v_binary.data()) + v_binary.size()) == j_binary); + + // a truncated payload must still be reported as an error + if (len > 16) + { + std::vector truncated = v_string; + truncated.resize(truncated.size() - 8); + json _; + CHECK_THROWS_AS(_ = json::from_bjdata(truncated), json::parse_error); + } + } +} diff --git a/tests/src/unit-bon8.cpp b/tests/src/unit-bon8.cpp index 491189867..b1d82ca29 100644 --- a/tests/src/unit-bon8.cpp +++ b/tests/src/unit-bon8.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; #ifdef JSON_TEST_NO_GLOBAL_UDLS @@ -1014,6 +1022,36 @@ TEST_CASE("BON8 roundtrips" * doctest::skip()) } } +TEST_CASE("issue #5648 - from_bon8(ptr, len) must read len bytes, not treat ptr as a C string") +{ + // to_bon8() encodes the integer 40 as the two bytes 0xC2 0x00 (a BON8 + // lead byte followed by a continuation byte of 0x00), so the packed data + // below contains a 0x00 byte before its end. + const json j = {{"a", 40}, {"b", "x"}}; + const std::vector packed = json::to_bon8(j); + bool contains_nul = false; + for (const auto byte : packed) + { + contains_nul |= (byte == 0x00); + } + REQUIRE(contains_nul); + +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED + // before the fix, from_bon8 had no (ptr, len) overload, so this call + // bound to from_bon8(InputType&&, bool strict) instead: ptr was read as + // a NUL-terminated C string (stopping at the embedded 0x00 byte), and + // len was silently converted to the strict flag. The deprecated + // overload added for this issue forwards to from_bon8(ptr, ptr + len, + // ...) instead, like from_cbor's deprecated (ptr, len) overload does. + json result; + CHECK_NOTHROW(result = json::from_bon8(packed.data(), packed.size())); + CHECK(result == j); + + // len must not collapse into the strict flag either + CHECK(json::from_bon8(packed.data(), packed.size(), false) == j); +#endif +} + #ifdef JSON_HAS_CPP_17 TEST_CASE("BON8 with std::byte") { diff --git a/tests/src/unit-brace-init-copy-semantics.cpp b/tests/src/unit-brace-init-copy-semantics.cpp index 1ee0c6607..e3406758b 100644 --- a/tests/src/unit-brace-init-copy-semantics.cpp +++ b/tests/src/unit-brace-init-copy-semantics.cpp @@ -72,6 +72,28 @@ TEST_CASE("JSON_BRACE_INIT_COPY_SEMANTICS") CHECK(j7 == json::array({1, 2})); } + SECTION("single-element brace initialization copies a pair-shaped array value (#5662)") + { + // a JSON value that happens to be a 2-element array whose first + // element is a string must still be copied, not turned into an + // object; only a braced list written in the source, such as the + // inner {"key", "value"} of {{"key", "value"}}, describes an object + json const pair_shaped = json::array({"key", 42}); + + json const j1{pair_shaped}; + CHECK(j1.is_array()); + CHECK(j1 == pair_shaped); + + json const j2 = {pair_shaped}; + CHECK(j2.is_array()); + CHECK(j2 == pair_shaped); + + // the same holds for an rvalue of the same shape + json const j3{json::array({"key", 42})}; + CHECK(j3.is_array()); + CHECK(j3 == pair_shaped); + } + SECTION("what the macro does not change") { // lists with more than one element are unaffected diff --git a/tests/src/unit-bson.cpp b/tests/src/unit-bson.cpp index 17819dc65..ea5ca3130 100644 --- a/tests/src/unit-bson.cpp +++ b/tests/src/unit-bson.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; @@ -141,6 +149,54 @@ TEST_CASE("BSON") json const j = std::vector {1, 2, 3, 4, 5, 6, 7}; CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is array", json::type_error&); } + + SECTION("discarded") + { + json const j = json::value_t::discarded; + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is discarded", json::type_error&); + } + } + + SECTION("discarded values nested in a container cannot be serialized to BSON") + { + json const discarded = json::value_t::discarded; + + SECTION("as an object value") + { + json j; + j["a"] = 1; + j["b"] = discarded; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.321] (/b) cannot serialize discarded value to BSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.321] cannot serialize discarded value to BSON", json::type_error&); +#endif + } + + SECTION("in an array that is an object value") + { + json j; + j["a"] = json::array({1, discarded, 2}); +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.321] (/a/1) cannot serialize discarded value to BSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.321] cannot serialize discarded value to BSON", json::type_error&); +#endif + } + + SECTION("nested deeper (array in object in object)") + { + json inner_array = {1, discarded}; + json middle_object; + middle_object["x"] = inner_array; + json j; + j["outer"] = middle_object; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.321] (/outer/x/1) cannot serialize discarded value to BSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.321] cannot serialize discarded value to BSON", json::type_error&); +#endif + } } SECTION("keys containing code-point U+0000 cannot be serialized to BSON") @@ -1261,8 +1317,10 @@ TEST_CASE("BSON input that cannot be read is discarded by every overload") CHECK_THROWS_AS(_ = json::from_bson(input.begin(), input.end()), json::parse_error&); CHECK(json::from_bson(input, true, false).is_discarded()); CHECK(json::from_bson(input.begin(), input.end(), true, false).is_discarded()); +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED CHECK(json::from_bson(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_bson({input.data(), input.size()}, true, false).is_discarded()); +#endif } TEST_CASE("BSON SAX parsing stops at every event") @@ -1740,6 +1798,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip()) CHECK(j1 == j2); } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED { INFO_WITH_TEMP(filename + ": uint8_t* and size"); // parse JSON file @@ -1754,6 +1813,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip()) // compare parsed JSON values CHECK(j1 == j2); } +#endif { INFO_WITH_TEMP(filename + ": output to output adapters"); @@ -1933,3 +1993,47 @@ TEST_CASE("Invalid document size handling") CHECK(json::from_bson(v, true, false).is_discarded()); } } + +TEST_CASE("BSON large strings and binaries (chunked reader)") +{ + // get_bson_string()/get_bson_binary() both read through get_string()/ + // get_binary(), which read in bounded chunks (binary_reader.hpp, + // chunk_size == 4096); make sure roundtripping is correct for lengths + // around and beyond that chunk size, for both vector (iterator) and + // pointer inputs. BSON only accepts an object at the top level, so the + // string/binary value is wrapped in one. + for (const std::size_t len : + { + std::size_t{0}, std::size_t{1}, std::size_t{4095}, std::size_t{4096}, + std::size_t{4097}, std::size_t{8192}, std::size_t{100000} + }) + { + CAPTURE(len) + + // string + const json j_string = {{"k", std::string(len, 'x')}}; + const std::vector v_string = json::to_bson(j_string); + CHECK(json::from_bson(v_string) == j_string); + // pointer input exercises the std::memcpy fast path + CHECK(json::from_bson(reinterpret_cast(v_string.data()), + reinterpret_cast(v_string.data()) + v_string.size()) == j_string); + + // binary (BSON binary values always carry a subtype, so give one + // explicitly; otherwise from_bson() would round-trip to subtype 0 + // rather than back to the original "no subtype" value) + const json j_binary = {{"k", json::binary(std::vector(len, 0xCD), std::uint8_t{0})}}; + const std::vector v_binary = json::to_bson(j_binary); + CHECK(json::from_bson(v_binary) == j_binary); + CHECK(json::from_bson(reinterpret_cast(v_binary.data()), + reinterpret_cast(v_binary.data()) + v_binary.size()) == j_binary); + + // a truncated payload must still be reported as an error + if (len > 16) + { + std::vector truncated = v_string; + truncated.resize(truncated.size() - 8); + json _; + CHECK_THROWS_AS(_ = json::from_bson(truncated), json::parse_error); + } + } +} diff --git a/tests/src/unit-cbor.cpp b/tests/src/unit-cbor.cpp index f3f4301e5..9ee371495 100644 --- a/tests/src/unit-cbor.cpp +++ b/tests/src/unit-cbor.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; @@ -30,10 +38,49 @@ TEST_CASE("CBOR") { SECTION("discarded") { - // discarded values are not serialized + // a discarded value cannot be serialized to CBOR json const j = json::value_t::discarded; - const auto result = json::to_cbor(j); - CHECK(result.empty()); + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error&); + } + + SECTION("discarded values nested in a container") + { + json const discarded = json::value_t::discarded; + + SECTION("in an array") + { + json const j = {1, discarded, 2}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] (/1) cannot serialize discarded value to CBOR", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error&); +#endif + } + + SECTION("as an object value") + { + json j; + j["a"] = 1; + j["b"] = discarded; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] (/b) cannot serialize discarded value to CBOR", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error&); +#endif + } + + SECTION("nested deeper (array in object in array)") + { + json inner_array = {1, discarded}; + json middle_object; + middle_object["x"] = inner_array; + json const j = {middle_object}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] (/0/x/1) cannot serialize discarded value to CBOR", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_cbor(j), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error&); +#endif + } } SECTION("NaN") @@ -1652,7 +1699,7 @@ TEST_CASE("CBOR") CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0xA1, 0x61, 0X61})), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0xBF, 0x61, 0X61})), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x5F})), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR binary: unexpected end of input", json::parse_error&); - CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x5F, 0x00})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR binary: expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x00", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x5F, 0x00})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR binary: expected length specification (0x40-0x5B); last byte: 0x00", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x41})), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR binary: unexpected end of input", json::parse_error&); CHECK(json::from_cbor(std::vector({0x18}), true, false).is_discarded()); @@ -2215,8 +2262,10 @@ TEST_CASE("CBOR input that cannot be read is discarded by every overload") CHECK_THROWS_AS(_ = json::from_cbor(input.begin(), input.end()), json::parse_error&); CHECK(json::from_cbor(input, true, false).is_discarded()); CHECK(json::from_cbor(input.begin(), input.end(), true, false).is_discarded()); +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED CHECK(json::from_cbor(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_cbor({input.data(), input.size()}, true, false).is_discarded()); +#endif // a string that ends early, read through iterators that are not // contiguous and have to be copied from one element at a time @@ -2256,22 +2305,21 @@ TEST_CASE("CBOR indefinite-length strings do not recurse per chunk") { // Reading an indefinite-length string or byte array used to call itself // once per chunk, so a payload of repeated 0x7F (or 0x5F) bytes exhausted - // the call stack before any of the input was rejected. The open levels are - // counted now, and the levels below prove the reader still reads the same - // values and reports the same errors at the same byte offsets. + // the call stack before any of the input was rejected. Nested indefinite + // chunks are now rejected at the second byte, without recursing. json _; - SECTION("many open levels are reported, not crashed on") + SECTION("nested levels are rejected, not crashed on") { const std::vector input(200000, 0x7F); - CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), "[json.exception.parse_error.110] parse error at byte 200001: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: indefinite-length string is not allowed inside indefinite-length string; last byte: 0x7F", json::parse_error&); CHECK(json::from_cbor(input, true, false).is_discarded()); } - SECTION("many open levels are reported, not crashed on (binary)") + SECTION("nested levels are rejected, not crashed on (binary)") { const std::vector input(200000, 0x5F); - CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), "[json.exception.parse_error.110] parse error at byte 200001: syntax error while parsing CBOR binary: unexpected end of input", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR binary: indefinite-length binary array is not allowed inside indefinite-length binary array; last byte: 0x5F", json::parse_error&); CHECK(json::from_cbor(input, true, false).is_discarded()); } @@ -2279,22 +2327,22 @@ TEST_CASE("CBOR indefinite-length strings do not recurse per chunk") { CHECK(json::from_cbor(std::vector({0x7F, 0xFF})) == json("")); CHECK(json::from_cbor(std::vector({0x7F, 0x61, 0x61, 0xFF})) == json("a")); - // nested indefinite-length strings are concatenated across levels - CHECK(json::from_cbor(std::vector({0x7F, 0x7F, 0x61, 0x61, 0xFF, 0x61, 0x62, 0xFF})) == json("ab")); - CHECK(json::from_cbor(std::vector({0x7F, 0x7F, 0x7F, 0x61, 0x7A, 0xFF, 0xFF, 0xFF})) == json("z")); + // empty and nonempty definite-length chunks concatenate in order + CHECK(json::from_cbor(std::vector({0x7F, 0x61, 'a', 0x60, 0x61, 'b', 0x61, 'c', 0xFF})) == json("abc")); CHECK(json::from_cbor(std::vector({0xA1, 0x7F, 0x61, 0x61, 0xFF, 0x01})) == json({{"a", 1}})); } SECTION("chunks are still concatenated (binary)") { CHECK(json::from_cbor(std::vector({0x5F, 0x41, 0x61, 0xFF})) == json::binary({0x61})); - CHECK(json::from_cbor(std::vector({0x5F, 0x5F, 0x41, 0x61, 0xFF, 0x41, 0x62, 0xFF})) == json::binary({0x61, 0x62})); + CHECK(json::from_cbor(std::vector({0x5F, 0xFF})) == json::binary({})); + CHECK(json::from_cbor(std::vector({0x5F, 0x41, 0x61, 0x40, 0x41, 0x62, 0x41, 0x63, 0xFF})) == json::binary({0x61, 0x62, 0x63})); } SECTION("a chunk that is not a string is still rejected") { - CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x7F, 0x7F, 0x00})), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x00", json::parse_error&); - CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x5F, 0x5F, 0x00})), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing CBOR binary: expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x00", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x7F, 0x00})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B); last byte: 0x00", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x5F, 0x00})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR binary: expected length specification (0x40-0x5B); last byte: 0x00", json::parse_error&); } SECTION("a break marker outside an indefinite-length string is not a string") @@ -2613,12 +2661,14 @@ TEST_CASE("CBOR roundtrips" * doctest::skip()) CHECK(j1 == j2); } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED { INFO_WITH_TEMP(filename + ": uint8_t* and size"); json j2; CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()})); CHECK(j1 == j2); } +#endif { INFO_WITH_TEMP(filename + ": output to output adapters"); @@ -2845,9 +2895,17 @@ TEST_CASE("examples from RFC 8949 Appendix A") { const auto packed = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.cbor"); json j; - CHECK_NOTHROW(j = json::from_cbor(packed)); + // the fixture's tail contains nested indefinite-length byte strings. + CHECK_THROWS_WITH_AS(j = json::from_cbor(packed), "[json.exception.parse_error.113] parse error at byte 513: syntax error while parsing CBOR binary: indefinite-length binary array is not allowed inside indefinite-length binary array; last byte: 0x5F", json::parse_error&); - const auto expected = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out"); + // keep the byte-for-byte decoding check for its valid prefix: the first + // 512 encoded bytes contain 468 payload bytes in definite-length chunks. + auto valid_prefix = packed; + valid_prefix.resize(512); + valid_prefix.push_back(0xFF); + auto expected = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out"); + expected.resize(468); + CHECK_NOTHROW(j = json::from_cbor(valid_prefix)); CHECK(j == json::binary(expected)); // 0xd8 @@ -3185,7 +3243,8 @@ TEST_CASE("Tagged values") // CBOR encodes negative integers as: result = -1 - n // For type 0x3B, n is an 8-byte uint64_t. Valid range for n with // the default int64_t is [0, INT64_MAX], producing results in [INT64_MIN, -1]. - // When n > INT64_MAX, the result exceeds int64_t range and is rejected. + // When n > INT64_MAX, the result exceeds int64_t range and is stored + // as a floating-point number, as the lexer does for JSON text. SECTION("n = 0 is valid (result = -1)") { @@ -3206,33 +3265,34 @@ TEST_CASE("Tagged values") CHECK(result.get() == (std::numeric_limits::min)()); } - SECTION("n = INT64_MAX + 1 is rejected (overflow)") + SECTION("n = INT64_MAX + 1 is stored as float") { // n = INT64_MAX + 1 (0x8000000000000000) - // result = -1 - n = -9223372036854775809, which exceeds int64_t range + // result = -1 - n = -9223372036854775809, which exceeds int64_t range; + // the nearest double is -9223372036854775808.0 const std::vector input = {0x3B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - json _; - CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), - "[json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: negative integer overflow", - json::parse_error); + const auto result = json::from_cbor(input); + CHECK(result.is_number_float()); + CHECK(result.get() == -9223372036854775808.0); + CHECK(result == json::parse("-9223372036854775809")); } - SECTION("n = UINT64_MAX is rejected (overflow)") + SECTION("n = UINT64_MAX is stored as float") { // n = UINT64_MAX (0xFFFFFFFFFFFFFFFF) // result = -1 - n = -18446744073709551616, which exceeds int64_t range const std::vector input = {0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - json _; - CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), - "[json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: negative integer overflow", - json::parse_error); + const auto result = json::from_cbor(input); + CHECK(result.is_number_float()); + CHECK(result.get() == -18446744073709551616.0); + CHECK(result == json::parse("-18446744073709551616")); } - SECTION("overflow with allow_exceptions=false returns discarded") + SECTION("overflow with allow_exceptions=false is not an error") { const std::vector input = {0x3B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const auto result = json::from_cbor(input, true, false); - CHECK(result.is_discarded()); + CHECK(result.is_number_float()); } } diff --git a/tests/src/unit-class_parser.cpp b/tests/src/unit-class_parser.cpp index f2de97ea3..978d94f92 100644 --- a/tests/src/unit-class_parser.cpp +++ b/tests/src/unit-class_parser.cpp @@ -2317,6 +2317,58 @@ TEST_CASE("parser class") #endif } + SECTION("comments before separators") + { + // The parser first checks for the expected ':' or ',' and only then + // falls back to the full token switch, which skips comments. A comment + // directly before a separator takes that fallback. + json _; + + SECTION("ignored") + { + const std::vector> inputs = + { + {"{\"a\" /* c */ : 1}", {{"a", 1}}}, + {"{\"a\" // c\n: 1}", {{"a", 1}}}, + {R"({"a": 1, "b" /* c */ : 2})", {{"a", 1}, {"b", 2}}}, + {R"({"a": 1 /* c */ , "b": 2})", {{"a", 1}, {"b", 2}}}, + {"{\"a\": 1 // c\n, \"b\": 2}", {{"a", 1}, {"b", 2}}}, + {"[1 /* c */ , 2]", {1, 2}}, + {"[1 // c\n, 2]", {1, 2}}, + {"{\"a\" /* c */ /* d */ : [1 // c\n , 2 /**/ ] /**/ , \"b\" : 3}", {{"a", {1, 2}}, {"b", 3}}} + }; + for (const auto& input : inputs) + { + CAPTURE(input.first) + CHECK(json::parse(input.first, nullptr, true, true) == input.second); + CHECK(json::accept(input.first, true)); + } + } + + SECTION("ignored, with trailing commas") + { + CHECK(json::parse(std::string("[1 /* c */ , ]"), nullptr, true, true, true) == json({1})); + CHECK(json::parse(std::string("{\"a\": 1 /* c */ , }"), nullptr, true, true, true) == json({{"a", 1}})); + CHECK_THROWS_WITH_AS(_ = json::parse(std::string("[1 /* c */ , ]"), nullptr, true, true), + "[json.exception.parse_error.101] parse error at line 1, column 14: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error); + CHECK_THROWS_WITH_AS(_ = json::parse(std::string("{\"a\": 1 /* c */ , }"), nullptr, true, true), + "[json.exception.parse_error.101] parse error at line 1, column 19: syntax error while parsing object key - unexpected '}'; expected string literal", json::parse_error); + } + + SECTION("not ignored") + { + CHECK_THROWS_WITH_AS(_ = json::parse(std::string("{\"a\" /* c */ : 1}")), + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing object separator - invalid literal; last read: '\"a\" /'; expected ':'", json::parse_error); + CHECK_THROWS_WITH_AS(_ = json::parse(std::string("{\"a\": 1, \"b\" /* c */ : 2}")), + "[json.exception.parse_error.101] parse error at line 1, column 14: syntax error while parsing object separator - invalid literal; last read: '\"b\" /'; expected ':'", json::parse_error); + CHECK_THROWS_WITH_AS(_ = json::parse(std::string("{\"a\": 1 /* c */ , \"b\": 2}")), + "[json.exception.parse_error.101] parse error at line 1, column 9: syntax error while parsing object - invalid literal; last read: '1 /'; expected '}'", json::parse_error); + CHECK_THROWS_WITH_AS(_ = json::parse(std::string("[1 /* c */ , 2]")), + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing array - invalid literal; last read: '1 /'; expected ']'", json::parse_error); + CHECK(!json::accept(std::string("[1 /* c */ , 2]"))); + } + } + #if JSON_DIAGNOSTIC_POSITIONS // Macro for all test cases for start_pos and end_pos #define SETUP_TESTCASES() \ diff --git a/tests/src/unit-conversions2.cpp b/tests/src/unit-conversions2.cpp index eca482b83..c543e4ff8 100644 --- a/tests/src/unit-conversions2.cpp +++ b/tests/src/unit-conversions2.cpp @@ -191,8 +191,10 @@ TEST_CASE("value conversion") { enum class bool_enum : bool { off, on }; - CHECK(json(bool_enum::off).get() == bool_enum::off); - CHECK(json(bool_enum::on).get() == bool_enum::on); + // the extra parentheses keep doctest from printing the enum via its + // underlying type, which MSVC 2015 reports as C4800 + CHECK((json(bool_enum::off).get() == bool_enum::off)); + CHECK((json(bool_enum::on).get() == bool_enum::on)); } #endif @@ -851,8 +853,11 @@ TEST_CASE("std::optional") CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&); // the conversion is noexcept exactly when converting the contained value is + // (except with MSVC 2017, where it is never noexcept, see to_json.hpp) +#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1920 static_assert(!std::is_nothrow_constructible&>::value); static_assert(std::is_nothrow_constructible&>::value); +#endif } #endif } diff --git a/tests/src/unit-custom-base-class.cpp b/tests/src/unit-custom-base-class.cpp index b9e544705..9718d1cda 100644 --- a/tests/src/unit-custom-base-class.cpp +++ b/tests/src/unit-custom-base-class.cpp @@ -38,20 +38,7 @@ class json_metadata }; template -using json_with_metadata = - nlohmann::basic_json < - std::map, - std::vector, - std::string, - bool, - std::int64_t, - std::uint64_t, - double, - std::allocator, - nlohmann::adl_serializer, - std::vector, - json_metadata - >; +using json_with_metadata = nlohmann::json::with_base_class_t>; TEST_CASE("JSON Node Metadata") { @@ -268,19 +255,7 @@ class visitor_adaptor void do_visit(const Ptr& ptr, const Fnc& fnc) const; }; -using json_with_visitor_t = nlohmann::basic_json < - std::map, - std::vector, - std::string, - bool, - std::int64_t, - std::uint64_t, - double, - std::allocator, - nlohmann::adl_serializer, - std::vector, - visitor_adaptor - >; +using json_with_visitor_t = nlohmann::json::with_base_class_t; template void visitor_adaptor::visit(const Fnc& fnc) const diff --git a/tests/src/unit-custom-object-type.cpp b/tests/src/unit-custom-object-type.cpp index a579e0b2d..0eaaf2d3c 100644 --- a/tests/src/unit-custom-object-type.cpp +++ b/tests/src/unit-custom-object-type.cpp @@ -10,7 +10,9 @@ #include +#include #include +#include #include #include #include @@ -196,6 +198,198 @@ struct void_erase_map : std::map using void_erase_json = nlohmann::basic_json; +// wraps an iterator, but only offers the LegacyForwardIterator operations, +// like the iterators of std::unordered_map and other hash maps +template +class forward_only_iterator +{ + BaseIterator m_it{}; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + + forward_only_iterator() = default; + explicit forward_only_iterator(BaseIterator it) : m_it(it) {} + + BaseIterator base() const + { + return m_it; + } + + reference operator*() const + { + return *m_it; + } + pointer operator->() const + { + return &*m_it; + } + forward_only_iterator& operator++() + { + ++m_it; + return *this; + } + forward_only_iterator operator++(int) + { + auto result = *this; + ++m_it; + return result; + } + + friend bool operator==(const forward_only_iterator& lhs, const forward_only_iterator& rhs) + { + return lhs.m_it == rhs.m_it; + } + friend bool operator!=(const forward_only_iterator& lhs, const forward_only_iterator& rhs) + { + return lhs.m_it != rhs.m_it; + } +}; + +// An ObjectType whose iterators are forward-only, as those of hash maps are; +// it has no rbegin() and its iterators no operator--. A hash map is not used +// directly for the same reason as in no_key_compare_map above. +template +class forward_only_map +{ + using map_t = std::map; + map_t data; + + public: + using key_type = typename map_t::key_type; + using mapped_type = typename map_t::mapped_type; + using value_type = typename map_t::value_type; + using size_type = typename map_t::size_type; + using allocator_type = typename map_t::allocator_type; + using iterator = forward_only_iterator; + using const_iterator = forward_only_iterator; + + forward_only_map() noexcept(std::is_nothrow_default_constructible::value) : data() {} + + template + forward_only_map(InputIt first, InputIt last) : data(first, last) {} + + iterator begin() noexcept + { + return iterator(data.begin()); + } + iterator end() noexcept + { + return iterator(data.end()); + } + const_iterator begin() const noexcept + { + return const_iterator(data.begin()); + } + const_iterator end() const noexcept + { + return const_iterator(data.end()); + } + const_iterator cbegin() const noexcept + { + return const_iterator(data.cbegin()); + } + const_iterator cend() const noexcept + { + return const_iterator(data.cend()); + } + + bool empty() const noexcept + { + return data.empty(); + } + size_type size() const noexcept + { + return data.size(); + } + size_type max_size() const noexcept + { + return data.max_size(); + } + void clear() noexcept + { + data.clear(); + } + + iterator find(const key_type& key) + { + return iterator(data.find(key)); + } + const_iterator find(const key_type& key) const + { + return const_iterator(data.find(key)); + } + size_type count(const key_type& key) const + { + return data.count(key); + } + + std::pair emplace(const key_type& key, const mapped_type& value) + { + const auto result = data.emplace(key, value); + return {iterator(result.first), result.second}; + } + + std::pair insert(const value_type& value) + { + const auto result = data.insert(value); + return {iterator(result.first), result.second}; + } + + template + void insert(InputIt first, InputIt last) + { + data.insert(first, last); + } + + mapped_type& operator[](const key_type& key) + { + return data[key]; + } + + mapped_type& at(const key_type& key) + { + return data.at(key); + } + const mapped_type& at(const key_type& key) const + { + return data.at(key); + } + + iterator erase(iterator pos) + { + return iterator(data.erase(pos.base())); + } + iterator erase(iterator first, iterator last) + { + return iterator(data.erase(first.base(), last.base())); + } + size_type erase(const key_type& key) + { + return data.erase(key); + } + + void swap(forward_only_map& other) noexcept(noexcept(data.swap(other.data))) + { + data.swap(other.data); + } + + friend bool operator==(const forward_only_map& lhs, const forward_only_map& rhs) + { + return lhs.data == rhs.data; + } + friend bool operator<(const forward_only_map& lhs, const forward_only_map& rhs) + { + return lhs.data < rhs.data; + } +}; + +using forward_only_json = nlohmann::basic_json; + } // namespace TEST_CASE("object type whose erase() returns void") @@ -322,3 +516,46 @@ TEST_CASE("object type without key_compare") } } + +TEST_CASE("object type with forward-only iterators") +{ + CHECK(std::is_same::iterator_category, + std::forward_iterator_tag>::value); + + SECTION("destroying nested objects and arrays") + { + forward_only_json j; + j["a"] = 1; + j["b"]["c"] = "x"; + j["b"]["d"] = forward_only_json::array(); + j["b"]["d"].push_back(forward_only_json::object()); + j["b"]["d"].push_back(true); + j["b"]["e"]["f"]["g"] = nullptr; + j["h"] = forward_only_json::object(); + j["i"]["j"] = 2; + + CHECK(j.size() == 4); + CHECK(j["b"].size() == 3); + CHECK(j["b"]["d"].size() == 2); + CHECK(j["b"]["e"]["f"]["g"].is_null()); + + CHECK(j.erase("b") == 1); + CHECK(j.size() == 3); + j = 42; + CHECK(j == 42); + } + + SECTION("destroying a deeply nested object") + { + constexpr std::size_t depth = 100000; + forward_only_json j; + forward_only_json* cur = &j; + for (std::size_t i = 0; i < depth; ++i) + { + (*cur)["s"] = i; + cur = &(*cur)["o"]; + } + CHECK(j["o"]["o"]["s"] == 2); + // destroyed at the end of scope without recursing per level + } +} diff --git a/tests/src/unit-delete_deprecated_functions.cpp b/tests/src/unit-delete_deprecated_functions.cpp new file mode 100644 index 000000000..a1d895370 --- /dev/null +++ b/tests/src/unit-delete_deprecated_functions.cpp @@ -0,0 +1,229 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +// This file tests the opt-in JSON_DELETE_DEPRECATED_FUNCTIONS, so it defines the +// macro itself instead of relying on the build configuration. +#ifdef JSON_DELETE_DEPRECATED_FUNCTIONS + #undef JSON_DELETE_DEPRECATED_FUNCTIONS +#endif +#define JSON_DELETE_DEPRECATED_FUNCTIONS 1 + +#include +using nlohmann::json; + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +template +struct make_void +{ + using type = void; +}; + +template +using void_t = typename make_void::type; + +// A deleted function is still found by overload resolution, but naming it in an +// unevaluated operand is ill-formed, so each of the following traits is false +// exactly if the expression selects a deleted (or no) function. +#define JSON_TEST_DETECT(name, expr) \ + template \ + struct name : std::false_type {}; \ + template \ + struct name> : std::true_type {} + +using ptr_t = const std::uint8_t*; + +JSON_TEST_DETECT(from_cbor_ptr_len, J::from_cbor(std::declval(), std::declval())); +JSON_TEST_DETECT(from_msgpack_ptr_len, J::from_msgpack(std::declval(), std::declval())); +JSON_TEST_DETECT(from_ubjson_ptr_len, J::from_ubjson(std::declval(), std::declval())); +JSON_TEST_DETECT(from_bjdata_ptr_len, J::from_bjdata(std::declval(), std::declval())); +JSON_TEST_DETECT(from_bon8_ptr_len, J::from_bon8(std::declval(), std::declval())); +JSON_TEST_DETECT(from_bson_ptr_len, J::from_bson(std::declval(), std::declval())); + +JSON_TEST_DETECT(from_cbor_ptr_ptr, J::from_cbor(std::declval(), std::declval())); +JSON_TEST_DETECT(from_msgpack_ptr_ptr, J::from_msgpack(std::declval(), std::declval())); +JSON_TEST_DETECT(from_ubjson_ptr_ptr, J::from_ubjson(std::declval(), std::declval())); +JSON_TEST_DETECT(from_bjdata_ptr_ptr, J::from_bjdata(std::declval(), std::declval())); +JSON_TEST_DETECT(from_bon8_ptr_ptr, J::from_bon8(std::declval(), std::declval())); +JSON_TEST_DETECT(from_bson_ptr_ptr, J::from_bson(std::declval(), std::declval())); + +JSON_TEST_DETECT(from_cbor_init_list, J::from_cbor({std::declval(), std::declval()})); +JSON_TEST_DETECT(from_msgpack_init_list, J::from_msgpack({std::declval(), std::declval()})); +JSON_TEST_DETECT(from_ubjson_init_list, J::from_ubjson({std::declval(), std::declval()})); +JSON_TEST_DETECT(from_bson_init_list, J::from_bson({std::declval(), std::declval()})); + +JSON_TEST_DETECT(parse_init_list, J::parse({std::declval(), std::declval()})); +JSON_TEST_DETECT(accept_init_list, J::accept({std::declval(), std::declval()})); +JSON_TEST_DETECT(sax_parse_init_list, J::sax_parse({std::declval(), std::declval()}, std::declval*>())); +JSON_TEST_DETECT(parse_ptr_ptr, J::parse(std::declval(), std::declval())); + +JSON_TEST_DETECT(iterator_wrapper, J::iterator_wrapper(std::declval())); +JSON_TEST_DETECT(iterator_wrapper_const, J::iterator_wrapper(std::declval())); +JSON_TEST_DETECT(items, std::declval().items()); + +JSON_TEST_DETECT(json_ltlt_istream, std::declval() << std::declval()); +JSON_TEST_DETECT(istream_gtgt_json, std::declval() >> std::declval()); +JSON_TEST_DETECT(json_gtgt_ostream, std::declval() >> std::declval()); +JSON_TEST_DETECT(ostream_ltlt_json, std::declval() << std::declval()); + +JSON_TEST_DETECT(ptr_eq_ptr, std::declval() == std::declval()); +JSON_TEST_DETECT(ptr_ne_ptr, std::declval() != std::declval()); +JSON_TEST_DETECT(ptr_eq_string, std::declval() == std::declval()); +JSON_TEST_DETECT(string_eq_ptr, std::declval() == std::declval()); +JSON_TEST_DETECT(ptr_eq_c_string, std::declval() == std::declval()); +JSON_TEST_DETECT(c_string_eq_ptr, std::declval() == std::declval()); +JSON_TEST_DETECT(ptr_ne_string, std::declval() != std::declval()); +JSON_TEST_DETECT(string_ne_ptr, std::declval() != std::declval()); +JSON_TEST_DETECT(ptr_to_string, std::declval().to_string()); + +// json_pointer with a basic_json type as template argument +template +using legacy_ptr_t = const nlohmann::json_pointer& ; +JSON_TEST_DETECT(legacy_ptr_value, std::declval().value(std::declval>(), 0)); +JSON_TEST_DETECT(legacy_ptr_value_rvalue, std::declval().value(std::declval>(), std::string())); +JSON_TEST_DETECT(legacy_ptr_contains, std::declval().contains(std::declval>())); +JSON_TEST_DETECT(legacy_ptr_subscript, std::declval()[std::declval>()]); +JSON_TEST_DETECT(legacy_ptr_subscript_const, std::declval()[std::declval>()]); +JSON_TEST_DETECT(legacy_ptr_at, std::declval().at(std::declval>())); +JSON_TEST_DETECT(legacy_ptr_at_const, std::declval().at(std::declval>())); +JSON_TEST_DETECT(ptr_value, std::declval().value(std::declval(), 0)); +JSON_TEST_DETECT(ptr_at, std::declval().at(std::declval())); + +#undef JSON_TEST_DETECT +} // namespace + +TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS") +{ + // MSVC 2015 does not treat selecting a deleted function in decltype as a + // substitution failure, so the traits cannot tell deleted functions apart + // there; calling them still fails to compile +#if !(defined(_MSC_VER) && _MSC_VER < 1910) + SECTION("from_* with a pointer and a length") + { + // the overloads are deleted rather than removed, so the length cannot + // silently bind to the strict parameter of from_*(InputType&&, bool) + CHECK_FALSE(from_cbor_ptr_len::value); + CHECK_FALSE(from_msgpack_ptr_len::value); + CHECK_FALSE(from_ubjson_ptr_len::value); + CHECK_FALSE(from_bjdata_ptr_len::value); + CHECK_FALSE(from_bon8_ptr_len::value); + CHECK_FALSE(from_bson_ptr_len::value); + + // the replacement + CHECK(from_cbor_ptr_ptr::value); + CHECK(from_msgpack_ptr_ptr::value); + CHECK(from_ubjson_ptr_ptr::value); + CHECK(from_bjdata_ptr_ptr::value); + CHECK(from_bon8_ptr_ptr::value); + CHECK(from_bson_ptr_ptr::value); + } + + SECTION("initializer lists of a pointer and a length") + { + CHECK_FALSE(from_cbor_init_list::value); + CHECK_FALSE(from_msgpack_init_list::value); + CHECK_FALSE(from_ubjson_init_list::value); + CHECK_FALSE(from_bson_init_list::value); + CHECK_FALSE(parse_init_list::value); + CHECK_FALSE(accept_init_list::value); + CHECK_FALSE(sax_parse_init_list::value); + + // the replacement + CHECK(parse_ptr_ptr::value); + } + + SECTION("iterator_wrapper") + { + CHECK_FALSE(iterator_wrapper::value); + CHECK_FALSE(iterator_wrapper_const::value); + + // the replacement + CHECK(items::value); + } + + SECTION("stream operators with reversed operands") + { + CHECK_FALSE(json_ltlt_istream::value); + CHECK_FALSE(json_gtgt_ostream::value); + + // the replacement + CHECK(istream_gtgt_json::value); + CHECK(ostream_ltlt_json::value); + } + + SECTION("json_pointer") + { + // conversion to a string + CHECK_FALSE(std::is_constructible::value); + CHECK_FALSE(std::is_convertible::value); + + // comparison with a string + CHECK_FALSE(ptr_eq_string::value); + CHECK_FALSE(string_eq_ptr::value); + CHECK_FALSE(ptr_eq_c_string::value); + CHECK_FALSE(c_string_eq_ptr::value); + CHECK_FALSE(ptr_ne_string::value); + CHECK_FALSE(string_ne_ptr::value); + + // the replacement + CHECK(ptr_to_string::value); + CHECK(ptr_eq_ptr::value); + CHECK(ptr_ne_ptr::value); + } + + SECTION("json_pointer with a basic_json type as template argument") + { + CHECK_FALSE(legacy_ptr_value::value); + CHECK_FALSE(legacy_ptr_value_rvalue::value); + CHECK_FALSE(legacy_ptr_contains::value); + CHECK_FALSE(legacy_ptr_subscript::value); + CHECK_FALSE(legacy_ptr_subscript_const::value); + CHECK_FALSE(legacy_ptr_at::value); + CHECK_FALSE(legacy_ptr_at_const::value); + + // the replacement + CHECK(ptr_value::value); + CHECK(ptr_at::value); + } + +#endif + + SECTION("the non-deprecated functions still work") + { + const json j = {{"a", {1, 2}}}; + const auto cbor = json::to_cbor(j); + CHECK(json::from_cbor(cbor.data(), cbor.data() + cbor.size()) == j); + + const json::json_pointer ptr("/a/1"); + CHECK(ptr == json::json_pointer("/a/1")); + CHECK(ptr.to_string() == "/a/1"); + CHECK(j[ptr] == 2); + CHECK(j.at(ptr) == 2); + CHECK(j.value(ptr, 0) == 2); + CHECK(j.contains(ptr)); + + std::ostringstream os; + os << j; + CHECK(os.str() == R"({"a":[1,2]})"); + std::istringstream is(os.str()); + json parsed; + is >> parsed; + CHECK(parsed == j); + } +} diff --git a/tests/src/unit-deserialization.cpp b/tests/src/unit-deserialization.cpp index 2f9ff63fa..ca9b63112 100644 --- a/tests/src/unit-deserialization.cpp +++ b/tests/src/unit-deserialization.cpp @@ -16,6 +16,14 @@ #define JSON_TEST_STRICT_NUL_HANDLING_ENABLED 1 #endif +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; #ifdef JSON_TEST_NO_GLOBAL_UDLS @@ -291,6 +299,7 @@ TEST_CASE("deserialization") })); } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED SECTION("operator<<") { std::stringstream ss; @@ -299,6 +308,7 @@ TEST_CASE("deserialization") j << ss; CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); } +#endif SECTION("operator>>") { @@ -423,6 +433,7 @@ TEST_CASE("deserialization") CHECK_THROWS_WITH_AS(_ = json::parse(nullptr), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&); } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED SECTION("operator<<") { std::stringstream ss; @@ -430,6 +441,7 @@ TEST_CASE("deserialization") json j; CHECK_THROWS_WITH_AS(j << ss, "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); } +#endif SECTION("operator>>") { @@ -1148,9 +1160,9 @@ TEST_CASE("deserialization") { std::istringstream s(bom + "123 456"); json j; - j << s; + s >> j; CHECK(j == 123); - j << s; + s >> j; CHECK(j == 456); } } diff --git a/tests/src/unit-diagnostics-optimized.cpp b/tests/src/unit-diagnostics-optimized.cpp new file mode 100644 index 000000000..44473982e --- /dev/null +++ b/tests/src/unit-diagnostics-optimized.cpp @@ -0,0 +1,86 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +// Regression test for https://github.com/nlohmann/json/issues/5742: with +// JSON_DIAGNOSTICS, GCC (12 to at least 16) reported a false -Warray-bounds +// error in the inlined set_parents() at -O3. The type of a new string was set +// before the string was allocated, so GCC had to assume that operator new +// could change it again and checked the object branch of set_parents() +// against the string's allocation. Setting the type after creating the value +// avoids this. The warning depends on GCC's inlining decisions, so the +// sections cover two patterns that trigger it on different GCC versions +// (#4819 and #5742). +// On GCC, this file is compiled with -O3 -Werror=array-bounds (see +// tests/CMakeLists.txt), so the test fails to build if the warning returns. + +#include "doctest_compatibility.h" + +#ifdef JSON_DIAGNOSTICS + #undef JSON_DIAGNOSTICS +#endif + +#define JSON_DIAGNOSTICS 1 + +#include +using nlohmann::json; + +#include +#include +#include +#include + +// the static table in to_json has an exit-time destructor +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") + +namespace +{ +enum class diag_color +{ + red, + green, + blue +}; + +void to_json(json& j, const diag_color& c) +{ + static const std::pair m[] = // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + { + {diag_color::red, "r"}, + {diag_color::green, "g"}, + {diag_color::blue, "b"}, + }; + const auto* it = std::find_if(std::begin(m), std::end(m), [c](const std::pair& p) + { + return p.first == c; + }); + j = ((it != std::end(m)) ? it : std::begin(m))->second; // like NLOHMANN_JSON_SERIALIZE_ENUM +} +} // namespace + +TEST_CASE("diagnostics with optimization") +{ + SECTION("issue #4819 - object in vector") + { + std::vector jsons{}; + jsons.emplace_back(json({{"key", "value"}})); + CHECK(jsons.back()["key"] == "value"); + } + + SECTION("issue #5742 - string values from a static table") + { + json j = json::array(); + j.push_back(diag_color::red); + j.push_back(diag_color::green); + j.push_back(diag_color::blue); + CHECK(j.dump() == R"(["r","g","b"])"); + CHECK_THROWS_WITH_AS(j[1].get(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error); + } +} + +DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-element_access2.cpp b/tests/src/unit-element_access2.cpp index 9a7a58e6b..1b59d8add 100644 --- a/tests/src/unit-element_access2.cpp +++ b/tests/src/unit-element_access2.cpp @@ -1551,6 +1551,10 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j // count(0) used to compile and then crash instead of failing to compile using nlohmann::detail::is_detected; + // MSVC 2015 does not treat selecting a deleted function in decltype as + // a substitution failure, so it detects the deleted overloads as + // callable; calling them still fails to compile +#if !(defined(_MSC_VER) && _MSC_VER < 1910) CHECK_FALSE(is_detected::value); CHECK_FALSE(is_detected::value); CHECK_FALSE(is_detected::value); @@ -1562,6 +1566,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j // another integral literal type must be rejected as well, not just int CHECK_FALSE(is_detected::value); +#endif // the valid overloads must remain callable CHECK(is_detected::value); diff --git a/tests/src/unit-enum_keyed_maps.cpp b/tests/src/unit-enum_keyed_maps.cpp new file mode 100644 index 000000000..a6ced6711 --- /dev/null +++ b/tests/src/unit-enum_keyed_maps.cpp @@ -0,0 +1,246 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +// skip tests if JSON_DisableEnumSerialization=ON (#4384) +#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1) + #define SKIP_TESTS_FOR_ENUM_SERIALIZATION +#endif + +// This file tests the opt-in JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS, so it defines +// the macro itself rather than relying on a -D flag, and runs in every build. +// The default behavior is tested in unit-enum_keyed_maps_default.cpp. +#ifdef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + #undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS +#endif + +#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 1 + +#include +using nlohmann::json; +using nlohmann::ordered_json; + +#include +#include +#include +#include +#include +#include +#include + +#define STRINGIZE_EX(x) #x +#define STRINGIZE(x) STRINGIZE_EX(x) + +// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") + +namespace +{ +// std::hash is only required for enums since C++14 +struct enum_hash +{ + template + std::size_t operator()(T t) const noexcept + { + return static_cast(t); + } +}; +} // namespace + +// the example from #4378 +enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class) +{ + TS_STOPPED, + TS_RUNNING, + TS_COMPLETED, + TS_INVALID = -1, +}; + +// 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}, + {TS_STOPPED, "stopped"}, + {TS_RUNNING, "running"}, + {TS_COMPLETED, "completed"}, +}) + +enum class color {red, green, blue}; // blue is not mapped and falls back to "red" + +// 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(color, +{ + {color::red, "red"}, + {color::green, "green"}, +}) + +enum class strict_color {red, green, blue}; // blue is not mapped + +// 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(strict_color, +{ + {strict_color::red, "red"}, + {strict_color::green, "green"}, +}) + +enum class digit {zero, one}; + +// 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(digit, +{ + {digit::zero, 0}, + {digit::one, 1}, +}) + +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION +enum class plain {zero, one}; // serialized as integer +#endif + +TEST_CASE("JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS") +{ + SECTION("the macro is part of the ABI tag") + { + const std::string ns = STRINGIZE(NLOHMANN_JSON_NAMESPACE); + CHECK(ns.find("_ekmo") != std::string::npos); + } + + SECTION("std::map (#4378)") + { + using task_map = std::map; + const task_map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}}; + const json j = m; + CHECK(j == json::parse(R"({"stopped":"aa","completed":"bb"})")); + CHECK(j.get() == m); + + json j2; + j2["x"] = m; + CHECK(j2.dump() == R"({"x":{"completed":"bb","stopped":"aa"}})"); + } + + SECTION("std::map with custom comparator") + { + using task_map = std::map>; + const task_map m = {{TS_STOPPED, 1}, {TS_RUNNING, 2}}; + const json j = m; + CHECK(j == json::parse(R"({"stopped":1,"running":2})")); + CHECK(j.get() == m); + } + + SECTION("std::unordered_map") + { + using task_map = std::unordered_map; + const task_map m = {{TS_STOPPED, 1}, {TS_RUNNING, 2}}; + const json j = m; + CHECK(j == json::parse(R"({"stopped":1,"running":2})")); + CHECK(j.get() == m); + } + + SECTION("nested maps") + { + using nested_map = std::map>; + const nested_map m = {{color::green, {{TS_RUNNING, 1}}}, {color::red, {}}}; + const json j = m; + CHECK(j == json::parse(R"({"green":{"running":1},"red":{}})")); + CHECK(j.get() == m); + } + + SECTION("ordered_json keeps the order of the map") + { + using task_map = std::map; + const task_map m = {{TS_STOPPED, 1}, {TS_RUNNING, 2}, {TS_COMPLETED, 3}}; + const ordered_json j = m; + CHECK(j.dump() == R"({"stopped":1,"running":2,"completed":3})"); + CHECK(j.get() == m); + } + + SECTION("empty map") + { + const json j = std::map(); + CHECK(j.is_object()); + CHECK(j.empty()); + } + + SECTION("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT") + { + using color_map = std::map; + const color_map m = {{strict_color::red, 1}, {strict_color::green, 2}}; + const json j = m; + CHECK(j == json::parse(R"({"red":1,"green":2})")); + CHECK(j.get() == m); + + const color_map unmapped = {{strict_color::blue, 1}}; + json _; + CHECK_THROWS_WITH_AS(_ = unmapped, + "[json.exception.out_of_range.410] enum value out of range for strict_color", json::out_of_range&); + } + + SECTION("arrays of [key, value] pairs are still read") + { + using task_map = std::map; + const task_map m = {{TS_STOPPED, 1}}; + CHECK(json::parse(R"([["stopped",1]])").get() == m); + } + + SECTION("other containers are not affected") + { + const std::vector> pairs = {{TS_STOPPED, 1}}; + const std::map string_keys = {{"a", TS_STOPPED}}; + const std::map int_keys = {{1, 2}}; + CHECK(json(pairs) == json::parse(R"([["stopped",1]])")); + CHECK(json(string_keys) == json::parse(R"({"a":"stopped"})")); + CHECK(json(int_keys) == json::parse("[[1,2]]")); + } + + SECTION("maps with non-unique keys are still stored as arrays of pairs") + { + const std::multimap mm = {{TS_STOPPED, 1}, {TS_STOPPED, 2}}; + const std::unordered_multimap umm = {{TS_RUNNING, 3}, {TS_RUNNING, 3}}; + CHECK(json(mm) == json::parse(R"([["stopped",1],["stopped",2]])")); + CHECK(json(umm) == json::parse(R"([["running",3],["running",3]])")); + } + + SECTION("keys that do not serialize to strings") + { + const std::map null_key = {{TS_INVALID, 1}}; + const std::map number_key = {{digit::zero, 1}}; + json j = "unchanged"; + + // mapped to null + CHECK_THROWS_WITH_AS(j = null_key, + "[json.exception.type_error.302] type must be string, but is null", json::type_error&); + + // mapped to a number + CHECK_THROWS_WITH_AS(j = number_key, + "[json.exception.type_error.302] type must be string, but is number", json::type_error&); + +#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION + // enum without NLOHMANN_JSON_SERIALIZE_ENUM + const std::map plain_key = {{plain::zero, 1}}; + CHECK_THROWS_WITH_AS(j = plain_key, + "[json.exception.type_error.302] type must be string, but is number", json::type_error&); +#endif + + CHECK(j == "unchanged"); + } + + SECTION("keys that serialize to the same string") + { + const std::map m = {{color::red, 1}, {color::blue, 2}}; + json j = "unchanged"; + + // color::blue is not mapped and falls back to "red" + CHECK_THROWS_WITH_AS(j = m, + "[json.exception.type_error.318] duplicate object key 'red'", json::type_error&); + + CHECK(j == "unchanged"); + } +} + +DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-enum_keyed_maps_default.cpp b/tests/src/unit-enum_keyed_maps_default.cpp new file mode 100644 index 000000000..5638b37e1 --- /dev/null +++ b/tests/src/unit-enum_keyed_maps_default.cpp @@ -0,0 +1,144 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +// This file tests maps with enum keys with the default setting of +// JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS (or whatever a -D flag sets it to). +// unit-enum_keyed_maps.cpp tests JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS=1. +// These tests are not part of unit-conversions.cpp, because that object file +// is already too big for the MinGW linker of some compilers. + +#include +using nlohmann::json; + +#include +#include +#include +#include +#include + +// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") + +enum class cards {kreuz, pik, herz, karo}; + +// 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"}, + {cards::pik, "pik"}, + {cards::herz, "herz"}, + {cards::karo, "karo"} +}) + +enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class) +{ + TS_STOPPED, + TS_RUNNING, + TS_COMPLETED, + TS_INVALID = -1, +}; + +// 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}, + {TS_STOPPED, "stopped"}, + {TS_RUNNING, "running"}, + {TS_COMPLETED, "completed"}, +}) + +enum class strict_cards {kreuz, pik, herz, karo, andere}; // andere not included in mapping + +// 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"}, + {strict_cards::pik, "pik"}, + {strict_cards::herz, "herz"}, + {strict_cards::karo, "karo"} +}) + +namespace +{ +// std::hash is only required for enums since C++14 +struct enum_hash +{ + template + std::size_t operator()(T t) const noexcept + { + return static_cast(t); + } +}; +} // namespace + +// see unit-enum_keyed_maps.cpp for JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS=1 +TEST_CASE("maps with enum keys") +{ + using task_map = std::map; + using task_umap = std::unordered_map; + using task_gmap = std::map>; + using nested_map = std::map>; + using strict_map = std::map; + using int_map = std::map; + using int_umap = std::unordered_map; + + const task_map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}}; + +#if !JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS + SECTION("stored as array of pairs") + { + CHECK(json(m) == json::parse(R"([["stopped","aa"],["completed","bb"]])")); + CHECK(json(task_umap {{TS_RUNNING, "cc"}}) == json::parse(R"([["running","cc"]])")); + } +#endif + + SECTION("read from array of pairs") + { + CHECK(json::parse(R"([["stopped","aa"],["completed","bb"]])").get() == m); + } + + SECTION("read from object (#4378)") + { + const json j = json::parse(R"({"stopped":"aa","completed":"bb"})"); + CHECK(j.get() == m); + CHECK(j.get() == task_umap(m.begin(), m.end())); + CHECK(j.get() == task_gmap(m.begin(), m.end())); + CHECK(json::parse(R"({"kreuz":{"stopped":1}})").get() == nested_map {{cards::kreuz, {{TS_STOPPED, 1}}}}); + CHECK(nlohmann::ordered_json::parse(R"({"stopped":"aa","completed":"bb"})").get() == m); + + // object keys go through the enum's from_json + strict_map sm; + CHECK_THROWS_WITH_AS(json::parse(R"({"what?":1})").get_to(sm), + "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&); + } + + SECTION("objects are only read for enum keys") + { + // built rather than parsed, so that the messages do not gain a byte + // range with JSON_DIAGNOSTIC_POSITIONS + const json j = {{"1", 2}}; + int_map im; + int_umap ium; + CHECK_THROWS_WITH_AS(j.get_to(im), + "[json.exception.type_error.302] type must be array, but is object", json::type_error&); + CHECK_THROWS_WITH_AS(j.get_to(ium), + "[json.exception.type_error.302] type must be array, but is object", json::type_error&); + } + + SECTION("other types are rejected") + { + task_map tm; + CHECK_THROWS_WITH_AS(json("stopped").get_to(tm), + "[json.exception.type_error.302] type must be array, but is string", json::type_error&); + } +} + +DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-hash.cpp b/tests/src/unit-hash.cpp index 382dfcaa2..e70b39b5a 100644 --- a/tests/src/unit-hash.cpp +++ b/tests/src/unit-hash.cpp @@ -12,8 +12,10 @@ using json = nlohmann::json; using ordered_json = nlohmann::ordered_json; +#include #include #include +#include namespace { @@ -91,6 +93,9 @@ TEST_CASE("hash") // Collect hashes for different JSON values and make sure that they are distinct // We cannot compare against fixed values, because the implementation of // std::hash may differ between compilers. + // + // numbers that compare equal under operator== (0 == 0U == 0.0) must hash + // equally, so they are only inserted once below and checked separately. std::set hashes; @@ -107,10 +112,7 @@ TEST_CASE("hash") // number hashes.insert(std::hash {}(json(0))); - hashes.insert(std::hash {}(json(static_cast(0)))); - hashes.insert(std::hash {}(json(-1))); - hashes.insert(std::hash {}(json(0.0))); hashes.insert(std::hash {}(json(42.23))); // array @@ -132,7 +134,36 @@ TEST_CASE("hash") // discarded hashes.insert(std::hash {}(json(json::value_t::discarded))); - CHECK(hashes.size() == 21); + CHECK(hashes.size() == 19); + + // numbers that compare equal under operator== must hash equally, + // regardless of which of number_integer, number_unsigned, or + // number_float actually holds the value + CHECK(json(0) == json(static_cast(0))); + CHECK(json(0) == json(0.0)); + CHECK(std::hash {}(json(0)) == std::hash {}(json(static_cast(0)))); + CHECK(std::hash {}(json(0)) == std::hash {}(json(0.0))); + CHECK(std::hash {}(json(-1)) == std::hash {}(json(-1.0))); + + // a std::unordered_set relies on this same consistency between == and hash + const std::unordered_set numbers {json(0), json(static_cast(0)), json(0.0)}; + CHECK(numbers.size() == 1); + + // -0.0 compares equal to 0 and 0.0 + CHECK(json(-0.0) == json(0)); + CHECK(std::hash {}(json(-0.0)) == std::hash {}(json(0))); + CHECK(std::hash {}(json(-0.0)) == std::hash {}(json(0.0))); + + // the ends of the integer ranges, which equal floats exactly + const auto int_min = (std::numeric_limits::min)(); + const auto int_max = (std::numeric_limits::max)(); + const auto two_63 = json::number_unsigned_t(1) << 63U; + CHECK(json(int_min) == json(-9223372036854775808.0)); + CHECK(std::hash {}(json(int_min)) == std::hash {}(json(-9223372036854775808.0))); + CHECK(json(two_63) == json(9223372036854775808.0)); + CHECK(std::hash {}(json(two_63)) == std::hash {}(json(9223372036854775808.0))); + CHECK(json(json::number_unsigned_t(int_max)) == json(int_max)); + CHECK(std::hash {}(json(json::number_unsigned_t(int_max))) == std::hash {}(json(int_max))); } TEST_CASE("hash") @@ -156,10 +187,7 @@ TEST_CASE("hash") // number hashes.insert(std::hash {}(ordered_json(0))); - hashes.insert(std::hash {}(ordered_json(static_cast(0)))); - hashes.insert(std::hash {}(ordered_json(-1))); - hashes.insert(std::hash {}(ordered_json(0.0))); hashes.insert(std::hash {}(ordered_json(42.23))); // array @@ -181,7 +209,10 @@ TEST_CASE("hash") // discarded hashes.insert(std::hash {}(ordered_json(ordered_json::value_t::discarded))); - CHECK(hashes.size() == 21); + CHECK(hashes.size() == 19); + + CHECK(std::hash {}(ordered_json(0)) == std::hash {}(ordered_json(static_cast(0)))); + CHECK(std::hash {}(ordered_json(0)) == std::hash {}(ordered_json(0.0))); } TEST_CASE("hash of deeply nested values") diff --git a/tests/src/unit-items.cpp b/tests/src/unit-items.cpp index 81959db8d..71b0522a8 100644 --- a/tests/src/unit-items.cpp +++ b/tests/src/unit-items.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; @@ -19,6 +27,7 @@ DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING("-Wrange-loop-construct") +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED TEST_CASE("iterator_wrapper") { SECTION("object") @@ -715,6 +724,7 @@ TEST_CASE("iterator_wrapper") } } } +#endif TEST_CASE("items()") { diff --git a/tests/src/unit-json_pointer.cpp b/tests/src/unit-json_pointer.cpp index 74c4976c5..86293b116 100644 --- a/tests/src/unit-json_pointer.cpp +++ b/tests/src/unit-json_pointer.cpp @@ -9,6 +9,14 @@ #include "doctest_compatibility.h" #define JSON_TESTS_PRIVATE +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; #ifdef JSON_TEST_NO_GLOBAL_UDLS @@ -630,7 +638,9 @@ TEST_CASE("JSON pointers") std::stringstream ss; ss << ptr; CHECK(ptr.to_string() == ptr_str); +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED CHECK(std::string(ptr) == ptr_str); +#endif CHECK(ss.str() == ptr_str); } } @@ -810,8 +820,6 @@ TEST_CASE("JSON pointers") SECTION("equality comparison") { - const char* ptr_cpstring = "/foo/bar"; - const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) std::string ptr_string{"/foo/bar"}; auto ptr1 = json::json_pointer(ptr_string); auto ptr2 = json::json_pointer(ptr_string); @@ -821,6 +829,12 @@ TEST_CASE("JSON pointers") CHECK(ptr1 == ptr2); + CHECK_FALSE(ptr1 != ptr2); + +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED + const char* ptr_cpstring = "/foo/bar"; + const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) + CHECK(ptr1 == "/foo/bar"); CHECK(ptr1 == ptr_cpstring); CHECK(ptr1 == ptr_castring); @@ -831,8 +845,6 @@ TEST_CASE("JSON pointers") CHECK(ptr_castring == ptr1); CHECK(ptr_string == ptr1); - CHECK_FALSE(ptr1 != ptr2); - CHECK_FALSE(ptr1 != "/foo/bar"); CHECK_FALSE(ptr1 != ptr_cpstring); CHECK_FALSE(ptr1 != ptr_castring); @@ -854,6 +866,7 @@ TEST_CASE("JSON pointers") CHECK_THROWS_WITH_AS("/~~" == ptr1, "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); } +#endif } SECTION("less-than comparison") @@ -905,6 +918,7 @@ TEST_CASE("JSON pointers") json_ptr_j ptr_j{ptr_string}; json_ptr_oj ptr_oj{ptr_string}; +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED CHECK(j.contains(ptr)); CHECK(j.contains(ptr_j)); CHECK(j.contains(ptr_oj)); @@ -917,6 +931,7 @@ TEST_CASE("JSON pointers") CHECK(j.value(ptr, "x") == j.value(ptr_j, "x")); CHECK(j.value(ptr, "x") == j.value(ptr_oj, "x")); +#endif CHECK(ptr == ptr_j); CHECK(ptr == ptr_oj); diff --git a/tests/src/unit-large_json.cpp b/tests/src/unit-large_json.cpp index 40025729a..6ce5626d8 100644 --- a/tests/src/unit-large_json.cpp +++ b/tests/src/unit-large_json.cpp @@ -13,6 +13,7 @@ using nlohmann::json; #include #include +#include #include TEST_CASE("tests on very large JSONs") @@ -354,3 +355,199 @@ TEST_CASE("tests on deeply nested JSONs") } } +namespace +{ +json nested_array(const std::size_t depth, json leaf) +{ + json j = std::move(leaf); + for (std::size_t i = 0; i < depth; ++i) + { + json a = json::array(); + a.push_back(std::move(j)); + j = std::move(a); + } + return j; +} + +json nested_object(const std::size_t depth, json leaf) +{ + json j = std::move(leaf); + for (std::size_t i = 0; i < depth; ++i) + { + json o = json::object(); + o["k"] = std::move(j); + j = std::move(o); + } + return j; +} +} // namespace + +TEST_CASE("issue #5392 - binary writers on deeply nested values") +{ + // 200 is past the point where the writers stop recursing, and still + // shallow enough that from_* and operator== (which still recurse) are fine. + const json deep_array = nested_array(200, json(0)); + const json deep_object = nested_object(200, json("x")); + const json empty_array = nested_array(200, json::array()); + const json empty_object = nested_object(200, json::object()); + const json mixed = nested_object(80, nested_array(80, json(true))); + + SECTION("roundtrip past the recursion bound") + { + CHECK(json::from_cbor(json::to_cbor(deep_array)) == deep_array); + CHECK(json::from_msgpack(json::to_msgpack(deep_array)) == deep_array); + CHECK(json::from_ubjson(json::to_ubjson(deep_array)) == deep_array); + CHECK(json::from_ubjson(json::to_ubjson(deep_array, true, false)) == deep_array); + CHECK(json::from_ubjson(json::to_ubjson(deep_array, true, true)) == deep_array); + CHECK(json::from_bjdata(json::to_bjdata(deep_array)) == deep_array); + + CHECK(json::from_cbor(json::to_cbor(deep_object)) == deep_object); + CHECK(json::from_msgpack(json::to_msgpack(deep_object)) == deep_object); + CHECK(json::from_ubjson(json::to_ubjson(deep_object)) == deep_object); + CHECK(json::from_ubjson(json::to_ubjson(deep_object, true, true)) == deep_object); + CHECK(json::from_bjdata(json::to_bjdata(deep_object)) == deep_object); + + CHECK(json::from_cbor(json::to_cbor(empty_array)) == empty_array); + CHECK(json::from_msgpack(json::to_msgpack(empty_array)) == empty_array); + CHECK(json::from_ubjson(json::to_ubjson(empty_array)) == empty_array); + CHECK(json::from_ubjson(json::to_ubjson(empty_array, true, true)) == empty_array); + + CHECK(json::from_cbor(json::to_cbor(empty_object)) == empty_object); + CHECK(json::from_msgpack(json::to_msgpack(empty_object)) == empty_object); + CHECK(json::from_ubjson(json::to_ubjson(empty_object)) == empty_object); + + CHECK(json::from_cbor(json::to_cbor(mixed)) == mixed); + CHECK(json::from_msgpack(json::to_msgpack(mixed)) == mixed); + CHECK(json::from_ubjson(json::to_ubjson(mixed)) == mixed); + CHECK(json::from_bjdata(json::to_bjdata(mixed)) == mixed); + } + + SECTION("the two ways of writing a value meet at the bound") + { + for (std::size_t depth = 120; depth <= 140; ++depth) + { + CAPTURE(depth); + + const json array = nested_array(depth, json(7)); + CHECK(json::from_cbor(json::to_cbor(array)) == array); + CHECK(json::from_msgpack(json::to_msgpack(array)) == array); + CHECK(json::from_ubjson(json::to_ubjson(array, true, true)) == array); + + const json object = nested_object(depth, json(7)); + CHECK(json::from_cbor(json::to_cbor(object)) == object); + CHECK(json::from_msgpack(json::to_msgpack(object)) == object); + CHECK(json::from_bjdata(json::to_bjdata(object)) == object); + } + } + + SECTION("a BJData ndarray below the bound is still an ndarray") + { + const json ndarray = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", {2, 3}}, {"_ArrayData_", {1, 2, 3, 4, 5, 6}}}); + const json invalid = json({{"_ArrayType_", "nope"}, {"_ArraySize_", {1}}, {"_ArrayData_", {1}}}); + + const json deep_ndarray = nested_array(140, ndarray); + const json deep_invalid = nested_array(140, invalid); + + CHECK(json::from_bjdata(json::to_bjdata(deep_ndarray)) == deep_ndarray); + CHECK(json::from_bjdata(json::to_bjdata(deep_invalid)) == deep_invalid); + CHECK(json::from_bjdata(json::to_bjdata(ndarray)) == ndarray); + } + + SECTION("byte-exact across the switch-over") + { + // nested one-element arrays around the recursion bound: the exact + // bytes a writer produces do not depend on whether it stayed on the + // call stack or moved to the heap one partway through + for (const std::size_t depth : + { + nlohmann::detail::recursion_depth_limit() - 1, nlohmann::detail::recursion_depth_limit(), + nlohmann::detail::recursion_depth_limit() + 1, nlohmann::detail::recursion_depth_limit() + 2 + }) + { + CAPTURE(depth); + const json array = nested_array(depth, json(0)); + + std::vector expected_cbor(depth, 0x81); + expected_cbor.push_back(0x00); + CHECK(json::to_cbor(array) == expected_cbor); + + std::vector expected_msgpack(depth, 0x91); + expected_msgpack.push_back(0x00); + CHECK(json::to_msgpack(array) == expected_msgpack); + + std::string expected_ubjson(depth, '['); + expected_ubjson += "i"; + expected_ubjson += '\0'; + expected_ubjson.append(depth, ']'); + const auto packed_ubjson = json::to_ubjson(array); + CHECK(std::string(packed_ubjson.begin(), packed_ubjson.end()) == expected_ubjson); + } + } + + SECTION("a deep object, and a BJData ndarray, past the recursion bound") + { + const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 50; + + const json object = nested_object(depth, json(42)); + CHECK(json::from_cbor(json::to_cbor(object)) == object); + CHECK(json::from_msgpack(json::to_msgpack(object)) == object); + CHECK(json::from_ubjson(json::to_ubjson(object, true, true)) == object); + CHECK(json::from_bjdata(json::to_bjdata(object)) == object); + + const json ndarray = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", {2, 3}}, {"_ArrayData_", {1, 2, 3, 4, 5, 6}}}); + const json deep_ndarray = nested_array(depth, ndarray); + CHECK(json::from_bjdata(json::to_bjdata(deep_ndarray)) == deep_ndarray); + } + + SECTION("a discarded value past the recursion bound still throws type_error.321") + { + const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 50; + const json discarded_leaf(json::value_t::discarded); + const json deep_discarded = nested_array(depth, discarded_leaf); + + CHECK_THROWS_WITH_AS(json::to_cbor(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error); + CHECK_THROWS_WITH_AS(json::to_msgpack(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error); + CHECK_THROWS_WITH_AS(json::to_ubjson(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error); + CHECK_THROWS_WITH_AS(json::to_bjdata(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error); + } + + SECTION("does not overflow the C++ stack") + { + const std::size_t depth = 100000; + const json j = json::parse(std::string(depth, '[') + "0" + std::string(depth, ']')); + + std::vector packed; + CHECK_NOTHROW(packed = json::to_cbor(j)); + CHECK(json::from_cbor(packed) == j); + + CHECK_NOTHROW(packed = json::to_msgpack(j)); + CHECK(json::from_msgpack(packed) == j); + + CHECK_NOTHROW(packed = json::to_ubjson(j)); + CHECK(json::from_ubjson(packed) == j); + + CHECK_NOTHROW(packed = json::to_ubjson(j, true, false)); + CHECK(json::from_ubjson(packed) == j); + + CHECK_NOTHROW(packed = json::to_bjdata(j)); + CHECK(json::from_bjdata(packed) == j); + } + + SECTION("regression test for https://issues.oss-fuzz.com/issues/566583014") + { + // 200000 nested one-element CBOR arrays, the innermost holding null; + // round-tripping this used to recurse once per level on the way back + // out through to_cbor(), deep enough to overflow the stack + std::vector v(200000, 0x81); + v.push_back(0xf6); + const json j = json::from_cbor(v); + CHECK(json::to_cbor(j) == v); + + // the MessagePack analogue: fixarray of 1 nesting down to nil + std::vector v_msgpack(200000, 0x91); + v_msgpack.push_back(0xc0); + const json j_msgpack = json::from_msgpack(v_msgpack); + CHECK(json::to_msgpack(j_msgpack) == v_msgpack); + } +} + diff --git a/tests/src/unit-msgpack-cpp17.cpp b/tests/src/unit-msgpack-cpp17.cpp new file mode 100644 index 000000000..6ae4d6d56 --- /dev/null +++ b/tests/src/unit-msgpack-cpp17.cpp @@ -0,0 +1,99 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +// This file contains the C++17-only part of unit-msgpack.cpp (std::byte +// input). It is kept in a separate translation unit so the (much larger) +// unit-msgpack.cpp does not need to be compiled and run a second time just +// for this one test case (#5418). + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; + +#ifdef JSON_HAS_CPP_17 +#include +#include + +// Test suite for verifying MessagePack handling with std::byte input +TEST_CASE("MessagePack with std::byte") +{ + + SECTION("std::byte compatibility") + { + SECTION("vector roundtrip") + { + json original = + { + {"name", "test"}, + {"value", 42}, + {"array", {1, 2, 3}} + }; + + std::vector temp = json::to_msgpack(original); + // Convert the uint8_t vector to std::byte vector + std::vector msgpack_data(temp.size()); + for (size_t i = 0; i < temp.size(); ++i) + { + msgpack_data[i] = std::byte(temp[i]); + } + // Deserialize from std::byte vector back to JSON + json from_bytes; + CHECK_NOTHROW(from_bytes = json::from_msgpack(msgpack_data)); + + CHECK(from_bytes == original); + } + + SECTION("empty vector") + { + const std::vector empty_data; + CHECK_THROWS_WITH_AS([&]() + { + [[maybe_unused]] auto result = json::from_msgpack(empty_data); + return true; + } + (), + "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input", + json::parse_error&); + } + + SECTION("comparison with workaround") + { + json original = + { + {"string", "hello"}, + {"integer", 42}, + {"float", 3.14}, + {"boolean", true}, + {"null", nullptr}, + {"array", {1, 2, 3}}, + {"object", {{"key", "value"}}} + }; + + std::vector temp = json::to_msgpack(original); + + std::vector msgpack_data(temp.size()); + for (size_t i = 0; i < temp.size(); ++i) + { + msgpack_data[i] = std::byte(temp[i]); + } + // Attempt direct deserialization using std::byte input + const json direct_result = json::from_msgpack(msgpack_data); + + // Test the workaround approach: reinterpret as unsigned char* and use iterator range + const auto* const char_start = reinterpret_cast(msgpack_data.data()); + const auto* const char_end = char_start + msgpack_data.size(); + json workaround_result = json::from_msgpack(char_start, char_end); + + // Verify that the final deserialized JSON matches the original JSON + CHECK(direct_result == workaround_result); + CHECK(direct_result == original); + } + } +} +#endif diff --git a/tests/src/unit-msgpack.cpp b/tests/src/unit-msgpack.cpp index c4b447d64..b705f94b7 100644 --- a/tests/src/unit-msgpack.cpp +++ b/tests/src/unit-msgpack.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; #ifdef JSON_TEST_NO_GLOBAL_UDLS @@ -33,10 +41,49 @@ TEST_CASE("MessagePack") { SECTION("discarded") { - // discarded values are not serialized + // a discarded value cannot be serialized to MessagePack json const j = json::value_t::discarded; - const auto result = json::to_msgpack(j); - CHECK(result.empty()); + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error&); + } + + SECTION("discarded values nested in a container") + { + json const discarded = json::value_t::discarded; + + SECTION("in an array") + { + json const j = {1, discarded, 2}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] (/1) cannot serialize discarded value to MessagePack", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error&); +#endif + } + + SECTION("as an object value") + { + json j; + j["a"] = 1; + j["b"] = discarded; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] (/b) cannot serialize discarded value to MessagePack", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error&); +#endif + } + + SECTION("nested deeper (array in object in array)") + { + json inner_array = {1, discarded}; + json middle_object; + middle_object["x"] = inner_array; + json const j = {middle_object}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] (/0/x/1) cannot serialize discarded value to MessagePack", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_msgpack(j), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error&); +#endif + } } SECTION("null") @@ -1795,8 +1842,10 @@ TEST_CASE("MessagePack input that cannot be read is discarded by every overload" CHECK_THROWS_AS(_ = json::from_msgpack(input.begin(), input.end()), json::parse_error&); CHECK(json::from_msgpack(input, true, false).is_discarded()); CHECK(json::from_msgpack(input.begin(), input.end(), true, false).is_discarded()); +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED CHECK(json::from_msgpack(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_msgpack({input.data(), input.size()}, true, false).is_discarded()); +#endif } TEST_CASE("MessagePack SAX parsing stops at every event") @@ -2099,12 +2148,14 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip()) CHECK(j1 == j2); } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED { INFO_WITH_TEMP(filename + ": uint8_t* and size"); json j2; CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()})); CHECK(j1 == j2); } +#endif { INFO_WITH_TEMP(filename + ": output to output adapters"); @@ -2122,85 +2173,6 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip()) } } -#ifdef JSON_HAS_CPP_17 -// Test suite for verifying MessagePack handling with std::byte input -TEST_CASE("MessagePack with std::byte") -{ - - SECTION("std::byte compatibility") - { - SECTION("vector roundtrip") - { - json original = - { - {"name", "test"}, - {"value", 42}, - {"array", {1, 2, 3}} - }; - - std::vector temp = json::to_msgpack(original); - // Convert the uint8_t vector to std::byte vector - std::vector msgpack_data(temp.size()); - for (size_t i = 0; i < temp.size(); ++i) - { - msgpack_data[i] = std::byte(temp[i]); - } - // Deserialize from std::byte vector back to JSON - json from_bytes; - CHECK_NOTHROW(from_bytes = json::from_msgpack(msgpack_data)); - - CHECK(from_bytes == original); - } - - SECTION("empty vector") - { - const std::vector empty_data; - CHECK_THROWS_WITH_AS([&]() - { - [[maybe_unused]] auto result = json::from_msgpack(empty_data); - return true; - } - (), - "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input", - json::parse_error&); - } - - SECTION("comparison with workaround") - { - json original = - { - {"string", "hello"}, - {"integer", 42}, - {"float", 3.14}, - {"boolean", true}, - {"null", nullptr}, - {"array", {1, 2, 3}}, - {"object", {{"key", "value"}}} - }; - - std::vector temp = json::to_msgpack(original); - - std::vector msgpack_data(temp.size()); - for (size_t i = 0; i < temp.size(); ++i) - { - msgpack_data[i] = std::byte(temp[i]); - } - // Attempt direct deserialization using std::byte input - const json direct_result = json::from_msgpack(msgpack_data); - - // Test the workaround approach: reinterpret as unsigned char* and use iterator range - const auto* const char_start = reinterpret_cast(msgpack_data.data()); - const auto* const char_end = char_start + msgpack_data.size(); - json workaround_result = json::from_msgpack(char_start, char_end); - - // Verify that the final deserialized JSON matches the original JSON - CHECK(direct_result == workaround_result); - CHECK(direct_result == original); - } - } -} -#endif - // the fake sizes below do not fit into a 32-bit std::size_t // with clang and libstdc++ 10, the std::filesystem::path conversion that // C++17 builds consider for every string type is ambiguous for a class @@ -2510,3 +2482,43 @@ TEST_CASE("MessagePack numbers use the active union member (see #5644)") CHECK(json::from_msgpack(result) == j); } } + +TEST_CASE("MessagePack large strings and binaries (chunked reader)") +{ + // get_msgpack_string()/get_msgpack_binary() both read through get_binary(), + // which reads in bounded chunks (binary_reader.hpp, chunk_size == 4096); + // make sure roundtripping is correct for lengths around and beyond that + // chunk size, for both vector (iterator) and pointer inputs. + for (const std::size_t len : + { + std::size_t{0}, std::size_t{1}, std::size_t{4095}, std::size_t{4096}, + std::size_t{4097}, std::size_t{8192}, std::size_t{100000} + }) + { + CAPTURE(len) + + // string + const json j_string = std::string(len, 'x'); + const std::vector v_string = json::to_msgpack(j_string); + CHECK(json::from_msgpack(v_string) == j_string); + // pointer input exercises the std::memcpy fast path + CHECK(json::from_msgpack(reinterpret_cast(v_string.data()), + reinterpret_cast(v_string.data()) + v_string.size()) == j_string); + + // binary + const json j_binary = json::binary(std::vector(len, 0xCD)); + const std::vector v_binary = json::to_msgpack(j_binary); + CHECK(json::from_msgpack(v_binary) == j_binary); + CHECK(json::from_msgpack(reinterpret_cast(v_binary.data()), + reinterpret_cast(v_binary.data()) + v_binary.size()) == j_binary); + + // a truncated payload must still be reported as an error + if (len > 16) + { + std::vector truncated = v_string; + truncated.resize(truncated.size() - 8); + json _; + CHECK_THROWS_AS(_ = json::from_msgpack(truncated), json::parse_error); + } + } +} diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index 79ca5a770..d084e6432 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -40,7 +40,9 @@ using ordered_json = nlohmann::ordered_json; #endif #include +#include #include +#include #include #include #include @@ -107,6 +109,84 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") using float_json = nlohmann::basic_json; +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +namespace +{ +// An allocator whose allocate() can be told to fail on demand, so tests can +// check that ~basic_json() tolerates - in fact, after #5135, never even +// triggers - an allocation failure. This replaces an earlier version of +// this test that overrode the process-wide ::operator new/::operator +// delete, which affected every allocation in the whole unit-regression2 +// binary rather than just the values under test. +std::size_t failing_allocator_allocations = 0; +std::size_t failing_allocator_deallocations = 0; +bool fail_next_allocation = false; + +template +struct failing_allocator : std::allocator +{ + using std::allocator::allocator; + + failing_allocator() noexcept = default; + template + failing_allocator(const failing_allocator& /*unused*/) noexcept {} // NOLINT(google-explicit-constructor) + + T* allocate(std::size_t n) + { + if (fail_next_allocation) + { + fail_next_allocation = false; + throw std::bad_alloc(); + } + ++failing_allocator_allocations; + return std::allocator::allocate(n); + } + + void deallocate(T* p, std::size_t n) + { + ++failing_allocator_deallocations; + std::allocator::deallocate(p, n); + } + + template + struct rebind + { + using other = failing_allocator; + }; +}; + +using failing_json = nlohmann::basic_json; +using failing_ordered_json = nlohmann::basic_json; + +// builds `depth` levels of nesting around a scalar, iteratively (never +// recursing: each wrap only moves the previous, already-built value, which +// is O(1)), each level an array or an object depending on `nest_objects` +template +BasicJsonType make_deep_nest(std::size_t depth, bool nest_objects) +{ + BasicJsonType v = 0; + for (std::size_t i = 0; i < depth; ++i) + { + if (nest_objects) + { + BasicJsonType wrapper = BasicJsonType::object(); + wrapper["x"] = std::move(v); + v = std::move(wrapper); + } + else + { + BasicJsonType wrapper = BasicJsonType::array(); + wrapper.push_back(std::move(v)); + v = std::move(wrapper); + } + } + return v; +} +} // namespace +#endif + ///////////////////////////////////////////////////////////////////// // for #1647 ///////////////////////////////////////////////////////////////////// @@ -569,7 +649,7 @@ TEST_CASE("regression tests 2") SECTION("issue #2067 - cannot serialize binary data to text JSON") { const std::array data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}}; - const json j = json::from_msgpack(data.data(), data.size()); + const json j = json::from_msgpack(data.begin(), data.end()); // dump() is nodiscard; this only checks that dumping does not throw CHECK_NOTHROW( utils::ignore_return_value( @@ -808,6 +888,15 @@ TEST_CASE("regression tests 2") CHECK(j == k); } + SECTION("issue #4552 - UTF-8 invalid characters are not always ignored when dumping with error_handler_t::ignore") + { + json node; + node["test"] = "test\334\005"; + CHECK(node.dump(-1, ' ', false, json::error_handler_t::ignore) == "{\"test\":\"test\\u0005\"}"); + CHECK(node.dump(-1, ' ', false, json::error_handler_t::keep) == "{\"test\":\"test\334\\u0005\"}"); + CHECK(node.dump(-1, ' ', true, json::error_handler_t::keep) == "{\"test\":\"test\334\\u0005\"}"); + } + #ifdef JSON_HAS_CPP_17 SECTION("issue #5066 - MSVC converts json to std::variant via the conversion operator") { @@ -940,4 +1029,211 @@ TEST_CASE("regression test - excessive binary container size honors allow_except CHECK(json::from_cbor(std::vector {0x9b, 0, 0, 0, 0, 0, 0, 0, 0x02}, true, false).is_discarded()); } +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +TEST_CASE("regression test #5135 - destructor never allocates, even under memory pressure") +{ + // Before the fix, ~basic_json() flattened a nested array/object into a + // heap-allocated std::vector to avoid recursing; that allocation could + // itself throw bad_alloc, which escapes a noexcept destructor and + // terminates the program. destroy() no longer allocates anything, so + // none of the sections below ever observe fail_next_allocation being + // consumed: CHECK(fail_next_allocation) confirms it was never touched. + + SECTION("the original report: a small, mixed array/object nest") + { + failing_allocator_allocations = 0; + failing_allocator_deallocations = 0; + { + const failing_json j = failing_json::array( + { + failing_json::array({1, 2}), + failing_json::object({{"key", failing_json::array({3})}}) + }); + fail_next_allocation = true; + } // j is destroyed here, with every further allocation set to fail + + CHECK(fail_next_allocation); + fail_next_allocation = false; + CHECK(failing_allocator_deallocations > 0); + } + + SECTION("100000-deep nested array") + { + std::size_t allocations_before = 0; + { + const auto j = make_deep_nest(100000, false); + allocations_before = failing_allocator_allocations; + fail_next_allocation = true; + } + + CHECK(fail_next_allocation); + fail_next_allocation = false; + CHECK(failing_allocator_allocations == allocations_before); + } + + SECTION("100000-deep nested object") + { + std::size_t allocations_before = 0; + { + const auto j = make_deep_nest(100000, true); + allocations_before = failing_allocator_allocations; + fail_next_allocation = true; + } + + CHECK(fail_next_allocation); + fail_next_allocation = false; + CHECK(failing_allocator_allocations == allocations_before); + } + + SECTION("100000-deep nested ordered_json") + { + std::size_t allocations_before = 0; + { + const auto j = make_deep_nest(100000, true); + allocations_before = failing_allocator_allocations; + fail_next_allocation = true; + } + + CHECK(fail_next_allocation); + fail_next_allocation = false; + CHECK(failing_allocator_allocations == allocations_before); + } + + SECTION("wide and deep: 1000 arrays of 1000 elements, each a small nested object") + { + std::size_t allocations_before = 0; + { + failing_json wide = failing_json::array(); + for (std::size_t i = 0; i < 1000; ++i) + { + failing_json inner = failing_json::array(); + for (std::size_t k = 0; k < 1000; ++k) + { + inner.push_back(failing_json::object({{"a", 1}, {"b", failing_json::array({1, 2, 3})}})); + } + wide.push_back(std::move(inner)); + } + + allocations_before = failing_allocator_allocations; + fail_next_allocation = true; + } + + CHECK(fail_next_allocation); + fail_next_allocation = false; + CHECK(failing_allocator_allocations == allocations_before); + } +} +#endif + +namespace +{ +// a single-element chain of `depth` arrays, built iteratively (never +// recursing: each wrap only moves the previous, already-built value) +template +BasicJsonType make_single_chain(std::size_t depth) +{ + BasicJsonType v = 1; + for (std::size_t i = 0; i < depth; ++i) + { + BasicJsonType wrapper = BasicJsonType::array(); + wrapper.push_back(std::move(v)); + v = std::move(wrapper); + } + return v; +} + +// copies value first, to make sure nothing was corrupted by building it, +// then lets both the copy and the original destruct via normal scope exit +template +void check_destroy_edge_case(const BasicJsonType& value) +{ + const BasicJsonType copy = value; // NOLINT(performance-unnecessary-copy-initialization): the copy is the point + CHECK(copy == value); +} +} // namespace + +TEST_CASE_TEMPLATE("regression test #5135 - destroy() edge cases", BasicJsonType, json, ordered_json) +{ + using binary_t = typename BasicJsonType::binary_t; + + SECTION("mix of empty objects, empty arrays, non-empty containers, and scalars") + { + BasicJsonType root = BasicJsonType::array(); + root.push_back(BasicJsonType::object()); + root.push_back(BasicJsonType::array()); + root.push_back(BasicJsonType::object({{"k", 1}})); + root.push_back(BasicJsonType::array({1, 2, 3})); + root.push_back(nullptr); + root.push_back(true); + root.push_back(42); + root.push_back(3.14); + root.push_back("a string"); + root.push_back(BasicJsonType(binary_t({1, 2, 3}))); + check_destroy_edge_case(root); + } + + SECTION("container child in first position only") + { + BasicJsonType root = BasicJsonType::array({BasicJsonType::array({1, 2}), 3, 4, 5}); + check_destroy_edge_case(root); + } + + SECTION("container child in last position only") + { + BasicJsonType root = BasicJsonType::array({1, 2, 3, BasicJsonType::array({4, 5})}); + check_destroy_edge_case(root); + } + + SECTION("container children in first and last position") + { + BasicJsonType root = BasicJsonType::array({BasicJsonType::array({1}), 2, 3, BasicJsonType::array({4})}); + check_destroy_edge_case(root); + } + + SECTION("single-element chain, 1000 levels deep") + { + auto root = make_single_chain(1000); + check_destroy_edge_case(root); + } + + SECTION("top-level empty array") + { + BasicJsonType root = BasicJsonType::array(); + check_destroy_edge_case(root); + } + + SECTION("top-level empty object") + { + BasicJsonType root = BasicJsonType::object(); + check_destroy_edge_case(root); + } + + SECTION("object whose last child is a non-empty array whose last child is an empty object") + { + BasicJsonType inner_array = BasicJsonType::array({1, 2, BasicJsonType::object()}); + BasicJsonType root = BasicJsonType::object({{"a", 1}, {"b", inner_array}}); + check_destroy_edge_case(root); + } + + SECTION("destruction via erase() on a deeply nested child") + { + BasicJsonType root = BasicJsonType::array(); + root.push_back(make_single_chain(500)); + root.push_back(BasicJsonType::object({{"k", BasicJsonType::array({1, 2, 3})}})); + // erase() must destroy the removed subtree without recursing or + // allocating beyond what erase() itself needs + root.erase(0); + CAPTURE(root.size()) + CHECK(root.size() == 1); + } + + SECTION("destruction via assignment on a deep tree") + { + auto root = make_single_chain(2000); + // assigning a new value destroys the old one in place + root = nullptr; + CHECK(root.is_null()); + } +} + DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-regression3.cpp b/tests/src/unit-regression3.cpp index 95b2b6d4f..69a95fb9b 100644 --- a/tests/src/unit-regression3.cpp +++ b/tests/src/unit-regression3.cpp @@ -22,6 +22,14 @@ // scoped enum, so get() (needed below to get>() // from a plain JSON array, not just from an already-binary value) relies on // enum serialization being enabled +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1) #define SKIP_TESTS_FOR_ENUM_SERIALIZATION #endif @@ -533,7 +541,7 @@ TEST_CASE("regression tests 3") } #endif -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION SECTION("issue #4916 - constructing array from C++20 ranges view does not work") { std::vector nums{1, 2, 37, 42, 21}; @@ -548,7 +556,7 @@ TEST_CASE("regression tests 3") #endif // owning_view is not available in libstdc++ < 12 -#if JSON_HAS_RANGES && !defined(__MINGW32__) && !(defined(__GLIBCXX__) && _GLIBCXX_RELEASE < 12) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !(defined(__GLIBCXX__) && _GLIBCXX_RELEASE < 12) SECTION("issue #4916 - constructing array from prvalue C++20 ranges view (owning_view)") { json const j(std::vector {1, 2, 37, 42, 21} | std::views::filter([](int i) @@ -560,7 +568,7 @@ TEST_CASE("regression tests 3") } #endif -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION SECTION("issue #4916 - constructing array from C++20 transform view (prvalue elements)") { std::vector nums{1, 2, 3}; @@ -862,6 +870,50 @@ TEST_CASE("issue #5338 - truncated CBOR tagged binary subtype is rejected") } } +TEST_CASE("issue #5676 - SAX parsing of CBOR tags") +{ + const json expected = json::binary({1, 2, 3}, 42); + const auto cbor = json::to_cbor(expected); + + nlohmann::detail::json_sax_acceptor acceptor; + CHECK_FALSE(json::sax_parse(cbor, &acceptor, json::input_format_t::cbor)); + CHECK_FALSE(json::sax_parse(cbor, &acceptor, json::input_format_t::cbor, + true, false, false, json::cbor_tag_handler_t::error)); + + CHECK(json::sax_parse(cbor, &acceptor, json::input_format_t::cbor, + true, false, false, json::cbor_tag_handler_t::ignore)); + + json parsed; + nlohmann::detail::json_sax_dom_parser sax(parsed); + CHECK(json::sax_parse(cbor, &sax, json::input_format_t::cbor, + true, false, false, json::cbor_tag_handler_t::store)); + CHECK(parsed == expected); + + json iterator_parsed; + nlohmann::detail::json_sax_dom_parser iterator_sax(iterator_parsed); + CHECK(json::sax_parse(cbor.begin(), cbor.end(), &iterator_sax, json::input_format_t::cbor, + true, false, false, json::cbor_tag_handler_t::store)); + CHECK(iterator_parsed == expected); + +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED + json span_parsed; + nlohmann::detail::json_sax_dom_parser span_sax(span_parsed); + CHECK(json::sax_parse(nlohmann::detail::span_input_adapter(cbor.data(), cbor.size()), &span_sax, + json::input_format_t::cbor, true, false, false, json::cbor_tag_handler_t::store)); + CHECK(span_parsed == expected); +#endif + + const std::string text = "null"; + CHECK(json::sax_parse(text, &acceptor, json::input_format_t::json, + true, false, false, json::cbor_tag_handler_t::store)); + CHECK(json::sax_parse(text.begin(), text.end(), &acceptor, json::input_format_t::json, + true, false, false, json::cbor_tag_handler_t::store)); +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED + CHECK(json::sax_parse(nlohmann::detail::span_input_adapter(text.data(), text.size()), &acceptor, + json::input_format_t::json, true, false, false, json::cbor_tag_handler_t::store)); +#endif +} + TEST_CASE("issue #5402 - update(merge_objects=true) overwrites a primitive with an object") { json t = {{"k", 1}}; @@ -920,4 +972,12 @@ TEST_CASE("regression test #5476 - array type without reserve()") } } +TEST_CASE("issue #5317 - nested indefinite-length CBOR string chunks are rejected") +{ + json _; + CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x7F, 0x7F, 0x61, 0x61, 0xFF, 0xFF})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: indefinite-length string is not allowed inside indefinite-length string; last byte: 0x7F", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0x5F, 0x5F, 0x41, 0x61, 0xFF, 0xFF})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR binary: indefinite-length binary array is not allowed inside indefinite-length binary array; last byte: 0x5F", json::parse_error&); + CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector({0xA1, 0x7F, 0x7F, 0xFF, 0xFF, 0x01})), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing CBOR string: indefinite-length string is not allowed inside indefinite-length string; last byte: 0x7F", json::parse_error&); +} + DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-serialization.cpp b/tests/src/unit-serialization.cpp index 4b959021e..1aa2111e7 100644 --- a/tests/src/unit-serialization.cpp +++ b/tests/src/unit-serialization.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; @@ -48,6 +56,7 @@ TEST_CASE("serialization") } } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED SECTION("operator>>") { SECTION("no given width") @@ -79,6 +88,7 @@ TEST_CASE("serialization") "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]"); } } +#endif SECTION("dump") { @@ -92,6 +102,8 @@ TEST_CASE("serialization") CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\""); CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\""); + CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"ä\xA9ü\""); + CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"\\u00e4\xA9\\u00fc\""); } SECTION("invalid character (regression guard for shared UTF-8 decoder, see #5529)") @@ -114,6 +126,8 @@ TEST_CASE("serialization") CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\""); CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\""); + CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"123\xC2\""); + CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"123\xC2\""); } SECTION("unexpected character") @@ -126,6 +140,39 @@ TEST_CASE("serialization") CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\""); CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\""); + CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"123\xF1\xB0\x34\x35\x36\""); + CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"123\xF1\xB0\x34\x35\x36\""); + } + + SECTION("keep: valid characters are still escaped") + { + // an invalid byte followed by characters that must be escaped + const json j = "\xC2\"\\\n\xFF\x05"; + CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"\xC2\\\"\\\\\\n\xFF\\u0005\""); + CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"\xC2\\\"\\\\\\n\xFF\\u0005\""); + } + + SECTION("keep: truncated multibyte sequences") + { + CHECK(json("\xF0\x9F\x98").dump(-1, ' ', false, json::error_handler_t::keep) == "\"\xF0\x9F\x98\""); + CHECK(json("\xF0\x9F\x98").dump(-1, ' ', true, json::error_handler_t::keep) == "\"\xF0\x9F\x98\""); + CHECK(json("\xF0\x9F\x98" "a").dump(-1, ' ', false, json::error_handler_t::keep) == "\"\xF0\x9F\x98" "a\""); + CHECK(json("\xF0\x9F\x98" "a").dump(-1, ' ', true, json::error_handler_t::keep) == "\"\xF0\x9F\x98" "a\""); + } + + SECTION("keep: long string with many invalid bytes") + { + // exceeds the internal string buffer several times + std::string input; + std::string expected = "\""; + for (int i = 0; i < 2000; ++i) + { + input += "\xFF\xE2\x82\n\xC3\xA4"; + expected += "\xFF\xE2\x82\\n\xC3\xA4"; + } + expected += "\""; + const json j = input; + CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == expected); } SECTION("U+FFFD Substitution of Maximal Subparts") @@ -799,3 +846,185 @@ TEST_CASE("serializer buffers are flushed mid-string and mid-binary") CHECK(j.dump(2) == "{\n \"bytes\": [" + expected_pretty_bytes + "],\n \"subtype\": null\n}"); } } + +TEST_CASE("serialization boundary values for the write buffer") +{ + // write_buffer is a std::array (write_buffer_size). put_string() + // guards it with two checks, and each must be exercised exactly on and one + // past its own boundary: a heap overflow in a different manual buffer path + // (the dump(1100) indent buffer) once survived 100% line coverage because + // every test that touched it only ever grew the buffer by a single step, + // never landing on the exact edge of the comparison that protects it. + // + // - straight-through: put_string() bypasses write_buffer entirely and + // writes directly to the output adapter once `length >= write_buffer.size()`. + // - flush-then-copy: otherwise, if `write_buffer_pos + length > write_buffer.size()`, + // put_string() flushes what is pending and then memcpy's the new run into + // the freshly emptied buffer. + + SECTION("top-level string exercises the straight-through guard (length >= 1024)") + { + // dump() of a bare string writes the opening quote with put_char() + // (write_buffer_pos: 0 -> 1), then the body with put_string(). With + // write_buffer_pos == 1, `1 + length > 1024` and `length >= 1024` flip + // together at length 1024, so 1023/1024/1025 cover "just under", + // "exactly at" and "just over" the guard in one move: 1023 is copied + // into the buffer (filling it exactly), 1024 and 1025 bypass it. + for (const std::size_t len : + { + std::size_t{1023}, std::size_t{1024}, std::size_t{1025} + }) + { + CAPTURE(len) + const std::string body(len, 'a'); + const json j = body; + const std::string expected = '"' + body + '"'; + + CHECK(j.dump() == expected); + + std::ostringstream o; + o << j; + CHECK(o.str() == expected); + } + } + + SECTION("string nested in an array exercises the flush-then-copy guard") + { + // json::array({body}) writes '[' then '"' before the body, so + // write_buffer_pos == 2 when put_string() is entered for it. The + // body's last byte then lands at logical offset 2 + len: len == 1022 + // lands exactly on offset 1024 (2 + 1022 == write_buffer.size(), so the + // strict "> " guard does not fire and the body fits snugly), while + // len == 1023 lands one past it at offset 1025 (2 + 1023 > 1024), + // which must flush what's pending before copying the body in. + for (const std::size_t len : + { + std::size_t{1022}, std::size_t{1023} + }) + { + CAPTURE(len) + const std::string body(len, 'a'); + const json j = json::array({body}); + const std::string expected = "[\"" + body + "\"]"; + + CHECK(j.dump() == expected); + + std::ostringstream o; + o << j; + CHECK(o.str() == expected); + + CHECK(json::parse(j.dump()) == j); + } + } +} + +TEST_CASE("serialization boundary values for the string buffer") +{ + // string_buffer is a std::array. dump_escaped_impl() flushes it + // mid-string once fewer than 13 bytes remain (`string_buffer.size() - bytes + // < 13`), 13 being one more than the most a single code point can ever + // write at once (a surrogate pair: two back-to-back "\uXXXX" escapes, 12 + // bytes). Every write into string_buffer that this check protects happens + // in steps of 2 (a simple "\\x" escape) or 6 (one "\uXXXX" unit), so + // `bytes` only ever takes even values at the point the check runs - the + // tightest values actually reachable are therefore 498 (512 - 498 == 14, + // one simple escape away from the threshold) and 500 (512 - 500 == 12, + // where the flush fires immediately and resets bytes to 0). + + SECTION("a run of 2-byte escapes lands bytes on, and one step past, the flush threshold") + { + for (const int count : + { + 249, 250, 251 + }) + { + CAPTURE(count) + const json j = std::string(static_cast(count), '\n'); + std::string expected = "\""; + for (int i = 0; i < count; ++i) + { + expected += "\\n"; + } + expected += '"'; + CHECK(j.dump() == expected); + } + } + + SECTION("an ASCII prefix leaves the tightest reachable margin before a 12-byte surrogate pair") + { + // U+1F600 (the "\xF0\x9F\x98\x80" UTF-8 bytes) is dumped under + // ensure_ascii as the 12-byte surrogate pair "\ud83d\ude00"; that + // write happens in a single step with no intermediate flush check, so + // it is the write most exposed by an off-by-one in the "< 13" guard. + // A prefix of 249 newlines leaves exactly 14 bytes of headroom + // (512 - 498), the smallest margin the guard ever actually allows + // into a new code point; 250 newlines instead trigger the guard's own + // flush first, so the emoji starts from a freshly emptied (512-byte) + // buffer, and 251 repeats that with one more escape already past the + // reset. Together they cover the margin the guard allows landing on, + // one step before, and one step after - all must still produce the + // identical, correct escapes. + for (const int prefix_count : + { + 249, 250, 251 + }) + { + CAPTURE(prefix_count) + const std::string prefix(static_cast(prefix_count), '\n'); + const std::string emoji = "\xF0\x9F\x98\x80"; + const json j = prefix + emoji; + + std::string expected_prefix; + for (int i = 0; i < prefix_count; ++i) + { + expected_prefix += "\\n"; + } + + // newline escaping does not depend on ensure_ascii: only the + // emoji differs (raw UTF-8 bytes vs. a \u-escaped surrogate pair) + std::string expected_raw = "\""; + expected_raw += expected_prefix; + expected_raw += emoji; + expected_raw += '"'; + std::string expected_ascii = "\""; + expected_ascii += expected_prefix; + expected_ascii += R"(\ud83d\ude00")"; + CHECK(j.dump(-1, ' ', false) == expected_raw); + CHECK(j.dump(-1, ' ', true) == expected_ascii); + CHECK(json::parse(j.dump(-1, ' ', true)) == j); + CHECK(json::parse(j.dump(-1, ' ', false)) == j); + } + } + + SECTION("SWAR bulk-copy stride: k plain bytes followed by a byte handled individually") + { + // string_bulk_run()/find_ascii_copyable_run() (string_scan.hpp) scan 8 + // bytes at a time and fall back to a byte-at-a-time tail scan for + // what is left over. k from 0 to 17 spans zero, one and two full + // 8-byte strides plus a 1-byte tail, so every possible stopping point + // within and right after the SIMD stride is covered. + for (std::size_t k = 0; k <= 17; ++k) + { + CAPTURE(k) + const std::string prefix(k, 'a'); + + // (a) the run is stopped by a quote that must itself be escaped + { + const json j = prefix + "\""; + CHECK(j.dump() == '"' + prefix + "\\\"" + '"'); + } + + // (b) the run is stopped by a control character + { + const json j = prefix + "\x01"; + CHECK(j.dump() == '"' + prefix + "\\u0001" + '"'); + } + + // (c) the run is stopped by a non-ASCII byte under ensure_ascii + { + const json j = prefix + "\xC3\xA9"; // prefix + 'é' + CHECK(j.dump(-1, ' ', true) == '"' + prefix + "\\u00e9" + '"'); + } + } + } +} diff --git a/tests/src/unit-ubjson.cpp b/tests/src/unit-ubjson.cpp index 80ca214a4..4cce74dff 100644 --- a/tests/src/unit-ubjson.cpp +++ b/tests/src/unit-ubjson.cpp @@ -8,6 +8,14 @@ #include "doctest_compatibility.h" +// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command +// line *before* including json.hpp, since the library #undefs it once the header +// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the +// tests of deprecated functions are skipped if these functions are deleted +#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1) + #define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED +#endif + #include using nlohmann::json; @@ -27,10 +35,59 @@ TEST_CASE("UBJSON") { SECTION("discarded") { - // discarded values are not serialized + // a discarded value cannot be serialized to UBJSON json const j = json::value_t::discarded; - const auto result = json::to_ubjson(j); - CHECK(result.empty()); + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error&); + } + + SECTION("discarded values nested in a container") + { + json const discarded = json::value_t::discarded; + + SECTION("in an array") + { + json const j = {1, discarded, 2}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] (/1) cannot serialize discarded value to UBJSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error&); +#endif + } + + SECTION("as an object value") + { + json j; + j["a"] = 1; + j["b"] = discarded; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] (/b) cannot serialize discarded value to UBJSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error&); +#endif + } + + SECTION("nested deeper (array in object in array)") + { + json inner_array = {1, discarded}; + json middle_object; + middle_object["x"] = inner_array; + json const j = {middle_object}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] (/0/x/1) cannot serialize discarded value to UBJSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_ubjson(j), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error&); +#endif + } + + SECTION("optimized array of all-discarded elements") + { + json const j = {discarded, discarded}; +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_ubjson(j, true, true), "[json.exception.type_error.321] (/0) cannot serialize discarded value to UBJSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_ubjson(j, true, true), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error&); +#endif + } } SECTION("null") @@ -745,6 +802,32 @@ TEST_CASE("UBJSON") CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec2), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A", json::parse_error); std::vector const vec3 = {'H', 'i', 2, '1', '.'}; CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec3), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1.", json::parse_error); + // Reject NULs where they are read, including trailing NULs and payloads cut off after one. + SECTION("NUL in high-precision number (issue #5753)") + { + for (const auto& vec : std::vector> + { + {'H', 'i', 3, '1', 0, 'x'}, + {'H', 'i', 2, '1', 0}, + {'H', 'i', 3, '1', 0} + }) + { + CAPTURE(vec) + CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text; last byte: 0x00", json::parse_error); + CHECK(json::from_ubjson(vec, true, false).is_discarded()); + CHECK(json::from_ubjson(vec, false, false).is_discarded()); + } + + std::vector const nested = {'[', 'H', 'i', 3, '1', 0, 'x', ']'}; + CHECK_THROWS_WITH_AS(_ = json::from_ubjson(nested), "[json.exception.parse_error.115] parse error at byte 6: syntax error while parsing UBJSON high-precision number: invalid number text; last byte: 0x00", json::parse_error); + CHECK(json::from_ubjson(nested, true, false).is_discarded()); + + std::vector const valid = {'H', 'i', 1, '1'}; + const auto j = json::from_ubjson(valid); + CHECK(j.is_number_unsigned()); + CHECK(j == json(1)); + } + std::vector const vec_overflow = {'H', 'i', 5, '1', 'e', '4', '0', '0'}; CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec_overflow), "[json.exception.out_of_range.406] number overflow parsing '1e400'", json::out_of_range&); std::vector const vec4 = {'H', 2, '1', '0'}; @@ -2091,9 +2174,14 @@ TEST_CASE("UBJSON") SECTION("discarded") { + // a discarded value cannot be serialized to UBJSON, even as part + // of an optimized array of a single (here: valueless) type json const j = {json::value_t::discarded, json::value_t::discarded}; - std::vector expected = {'[', '$', 'N', '#', 'i', 2}; - CHECK(json::to_ubjson(j, true, true) == expected); +#if JSON_DIAGNOSTICS + CHECK_THROWS_WITH_AS(json::to_ubjson(j, true, true), "[json.exception.type_error.321] (/0) cannot serialize discarded value to UBJSON", json::type_error&); +#else + CHECK_THROWS_WITH_AS(json::to_ubjson(j, true, true), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error&); +#endif } } } @@ -2212,8 +2300,10 @@ TEST_CASE("UBJSON input that cannot be read is discarded by every overload") CHECK_THROWS_AS(_ = json::from_ubjson(input.begin(), input.end()), json::parse_error&); CHECK(json::from_ubjson(input, true, false).is_discarded()); CHECK(json::from_ubjson(input.begin(), input.end(), true, false).is_discarded()); +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED CHECK(json::from_ubjson(input.data(), input.size(), true, false).is_discarded()); CHECK(json::from_ubjson({input.data(), input.size()}, true, false).is_discarded()); +#endif } TEST_CASE("UBJSON SAX parsing stops at every event") @@ -2961,12 +3051,14 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip()) CHECK(j1 == j2); } +#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED { INFO_WITH_TEMP(filename + ": uint8_t* and size"); json j2; CHECK_NOTHROW(j2 = json::from_ubjson({packed.data(), packed.size()})); CHECK(j1 == j2); } +#endif { INFO_WITH_TEMP(filename + ": output to output adapters"); @@ -3216,3 +3308,43 @@ TEST_CASE("UBJSON and BJData integer markers at every range edge") } } } + +TEST_CASE("UBJSON large strings (chunked reader)") +{ + // get_ubjson_string() reads through get_string(), which reads in bounded + // chunks (binary_reader.hpp, chunk_size == 4096); make sure roundtripping + // is correct for lengths around and beyond that chunk size, for both + // vector (iterator) and pointer inputs. + // + // A binary value is not included here: plain UBJSON (unlike BJData, see + // the "BJData large strings and binaries" test) has no reader-side binary + // type, so even the optimized uint8_t-array encoding of a binary value is + // read back element-by-element as a JSON array of numbers rather than + // through get_binary() - it never reaches the chunked path this test is + // about (see the "roundtrip only works to an array of numbers" case + // above). + for (const std::size_t len : + { + std::size_t{0}, std::size_t{1}, std::size_t{4095}, std::size_t{4096}, + std::size_t{4097}, std::size_t{8192}, std::size_t{100000} + }) + { + CAPTURE(len) + + const json j_string = std::string(len, 'x'); + const std::vector v_string = json::to_ubjson(j_string); + CHECK(json::from_ubjson(v_string) == j_string); + // pointer input exercises the std::memcpy fast path + CHECK(json::from_ubjson(reinterpret_cast(v_string.data()), + reinterpret_cast(v_string.data()) + v_string.size()) == j_string); + + // a truncated payload must still be reported as an error + if (len > 16) + { + std::vector truncated = v_string; + truncated.resize(truncated.size() - 8); + json _; + CHECK_THROWS_AS(_ = json::from_ubjson(truncated), json::parse_error); + } + } +} diff --git a/tests/src/unit-udt.cpp b/tests/src/unit-udt.cpp index 5ad72b208..8bc04c0ba 100644 --- a/tests/src/unit-udt.cpp +++ b/tests/src/unit-udt.cpp @@ -23,6 +23,7 @@ using nlohmann::json; using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) #endif +#include #include #include #include @@ -684,8 +685,7 @@ static std::ostream& operator<<(std::ostream& os, small_pod l) TEST_CASE("custom serializer for pods" * doctest::test_suite("udt")) { using custom_json = - nlohmann::basic_json; + nlohmann::json::with_json_serializer_t; auto p = udt::small_pod{42, '/', 42}; custom_json const j = p; @@ -703,7 +703,7 @@ TEST_CASE("custom serializer for pods" * doctest::test_suite("udt")) template struct another_adl_serializer; -using custom_json = nlohmann::basic_json; +using custom_json = nlohmann::json::with_json_serializer_t; template struct another_adl_serializer @@ -734,6 +734,80 @@ TEST_CASE("custom serializer that does adl by default" * doctest::test_suite("ud CHECK(me == cj.get()); } +TEST_CASE("with_*_t aliases" * doctest::test_suite("udt")) +{ + // a custom base class used to check with_base_class_t + struct custom_base_class {}; + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + CHECK(std::is_same>, + nlohmann::basic_json>>::value); + + CHECK(std::is_same, + nlohmann::basic_json, custom_base_class>>::value); + + // with_string_t on ordered_json must keep ordered_map as the object type + CHECK(std::is_same, + nlohmann::basic_json>>::value); + + // the aliases are members of the resulting type, so they can be chained + CHECK(std::is_same::with_float_t, + nlohmann::basic_json>>::value); + CHECK(std::is_same::with_integers_t, + json::with_integers_t::with_float_t>::value); + + // replacing the object type of json with ordered_map yields ordered_json + CHECK(std::is_same, nlohmann::ordered_json>::value); + CHECK(std::is_same, json>::value); +} + TEST_CASE("different basic_json types conversions") { SECTION("null") diff --git a/tests/src/unit-unicode.cpp b/tests/src/unit-unicode.cpp new file mode 100644 index 000000000..0207659ea --- /dev/null +++ b/tests/src/unit-unicode.cpp @@ -0,0 +1,1633 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; + +#include +#include +#include +#include "make_test_data_available.hpp" +#include "test_utils.hpp" + +// this test suite uses static variables with non-trivial destructors +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") + +namespace +{ +void check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4); + +void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) +{ + static std::string json_string; + json_string.clear(); + + CAPTURE(byte1) + CAPTURE(byte2) + CAPTURE(byte3) + CAPTURE(byte4) + + json_string += std::string(1, static_cast(byte1)); + + if (byte2 != -1) + { + json_string += std::string(1, static_cast(byte2)); + } + + if (byte3 != -1) + { + json_string += std::string(1, static_cast(byte3)); + } + + if (byte4 != -1) + { + json_string += std::string(1, static_cast(byte4)); + } + + CAPTURE(json_string) + + // store the string in a JSON value + static json j; + static json j2; + j = json_string; + j2 = "abc" + json_string + "xyz"; + + static std::string s_ignored; + static std::string s_ignored2; + static std::string s_ignored_ascii; + static std::string s_ignored2_ascii; + static std::string s_replaced; + static std::string s_replaced2; + static std::string s_replaced_ascii; + static std::string s_replaced2_ascii; + static std::string s_kept; + static std::string s_kept2; + static std::string s_kept_ascii; + + // dumping with ignore/replace/keep must not throw in any case + s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore); + s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore); + s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore); + s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore); + s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace); + s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace); + s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace); + s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace); + s_kept = j.dump(-1, ' ', false, json::error_handler_t::keep); + s_kept2 = j2.dump(-1, ' ', false, json::error_handler_t::keep); + s_kept_ascii = j.dump(-1, ' ', true, json::error_handler_t::keep); + + if (success_expected) + { + static std::string s_strict; + // strict mode must not throw if success is expected + s_strict = j.dump(); + // all dumps should agree on the string + CHECK(s_strict == s_ignored); + CHECK(s_strict == s_replaced); + CHECK(s_strict == s_kept); + } + else + { + // strict mode must throw if success is not expected + // dump() is nodiscard; the exception is thrown by dump() itself before it would return + CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); + // ignore and replace must create different dumps + CHECK(s_ignored != s_replaced); + + // check that replace string contains a replacement character + CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos); + + // ignore drops the invalid bytes, keep copies them + CHECK(s_ignored != s_kept); + CHECK(s_ignored_ascii != s_kept_ascii); + + // unless a byte needs escaping, keep copies the input unchanged + const bool needs_escaping = std::any_of(json_string.begin(), json_string.end(), [](char c) + { + return static_cast(c) < 0x20 || c == '"' || c == '\\'; + }); + if (!needs_escaping) + { + CHECK(s_kept == "\"" + json_string + "\""); + } + } + + // check that prefix and suffix are preserved + CHECK(s_ignored2.substr(1, 3) == "abc"); + CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz"); + CHECK(s_ignored2_ascii.substr(1, 3) == "abc"); + CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz"); + CHECK(s_replaced2.substr(1, 3) == "abc"); + CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz"); + CHECK(s_replaced2_ascii.substr(1, 3) == "abc"); + CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz"); + CHECK(s_kept2.substr(1, 3) == "abc"); + CHECK(s_kept2.substr(s_kept2.size() - 4, 3) == "xyz"); +} + +void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4); + +// create and check a JSON string with up to four UTF-8 bytes +void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) +{ + static std::string json_string; + json_string = "\""; + + CAPTURE(byte1) + json_string += std::string(1, static_cast(byte1)); + + if (byte2 != -1) + { + CAPTURE(byte2) + json_string += std::string(1, static_cast(byte2)); + } + + if (byte3 != -1) + { + CAPTURE(byte3) + json_string += std::string(1, static_cast(byte3)); + } + + if (byte4 != -1) + { + CAPTURE(byte4) + json_string += std::string(1, static_cast(byte4)); + } + + json_string += "\""; + + CAPTURE(json_string) + + json _; + if (success_expected) + { + CHECK_NOTHROW(_ = json::parse(json_string)); + } + else + { + CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&); + } +} +} // namespace + +TEST_CASE("Unicode") +{ + SECTION("\\uxxxx sequences") + { + // create an escaped string from a code point + const auto codepoint_to_unicode = [](std::size_t cp) + { + // code points are represented as a six-character sequence: a + // reverse solidus, followed by the lowercase letter u, followed + // by four hexadecimal digits that encode the character's code + // point; formatted by hand as this is called ~1.1M times (#5418) + std::string result = "\\u"; + for (int shift = 12; shift >= 0; shift -= 4) + { + result += "0123456789abcdef"[(cp >> shift) & 0xFu]; + } + return result; + }; + + SECTION("correct sequences") + { + // generate all UTF-8 code points; in total, 1112064 code points are + // generated: 0x1FFFFF code points - 2048 invalid values between + // 0xD800 and 0xDFFF. + for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp) + { + // string to store the code point as in \uxxxx format + std::string json_text = "\""; + + // decide whether to use one or two \uxxxx sequences + if (cp < 0x10000u) + { + // The Unicode standard permanently reserves these code point + // values for UTF-16 encoding of the high and low surrogates, and + // they will never be assigned a character, so there should be no + // reason to encode them. The official Unicode standard says that + // no UTF forms, including UTF-16, can encode these code points. + if (cp >= 0xD800u && cp <= 0xDFFFu) + { + // if we would not skip these code points, we would get a + // "missing low surrogate" exception + continue; + } + + // code points in the Basic Multilingual Plane can be + // represented with one \uxxxx sequence + json_text += codepoint_to_unicode(cp); + } + else + { + // To escape an extended character that is not in the Basic + // Multilingual Plane, the character is represented as a + // 12-character sequence, encoding the UTF-16 surrogate pair + const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu); + const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu); + json_text += codepoint_to_unicode(codepoint1) + codepoint_to_unicode(codepoint2); + } + + json_text += "\""; + CAPTURE(json_text) + json _; + CHECK_NOTHROW(_ = json::parse(json_text)); + } + } + + SECTION("incorrect sequences") + { + SECTION("incorrect surrogate values") + { + json _; + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uDC00\\uDC00\""), "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uDC00'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD7FF\\uDC00\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uD7FF\\uDC00'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800]\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800]'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\v\""), "[json.exception.parse_error.101] parse error at line 1, column 9: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\v'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\u123\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\uD800\\u123\"'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\uDBFF\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uDBFF'", json::parse_error&); + + CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\uE000\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uE000'", json::parse_error&); + } + } + +#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) + SECTION("incorrect sequences") + { + SECTION("high surrogate without low surrogate") + { + // D800..DBFF are high surrogates and must be followed by low + // surrogates DC00..DFFF; here, nothing follows + for (std::size_t cp = 0xD800u; cp <= 0xDBFFu; ++cp) + { + std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; + CAPTURE(json_text) + CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); + } + } + + SECTION("high surrogate with wrong low surrogate") + { + // D800..DBFF are high surrogates and must be followed by low + // surrogates DC00..DFFF; here a different sequence follows + for (std::size_t cp1 = 0xD800u; cp1 <= 0xDBFFu; ++cp1) + { + for (std::size_t cp2 = 0x0000u; cp2 <= 0xFFFFu; ++cp2) + { + if (0xDC00u <= cp2 && cp2 <= 0xDFFFu) + { + continue; + } + + std::string json_text = "\"" + codepoint_to_unicode(cp1) + codepoint_to_unicode(cp2) + "\""; + CAPTURE(json_text) + CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); + } + } + } + + SECTION("low surrogate without high surrogate") + { + // low surrogates DC00..DFFF must follow high surrogates; here, + // they occur alone + for (std::size_t cp = 0xDC00u; cp <= 0xDFFFu; ++cp) + { + std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; + CAPTURE(json_text) + CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); + } + } + + } +#endif + } + + SECTION("read all unicode characters") + { + // read a file with all Unicode characters stored as single-character + // strings in a JSON array + std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json"); + json j; + CHECK_NOTHROW(f >> j); + + // the array has 1112064 + 1 elements (a terminating "null" value) + // Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between + // 0xD800 and 0xDFFF. + CHECK(j.size() == 1112065); + + SECTION("check JSON Pointers") + { + for (const auto& s : j) + { + // skip non-string JSON values + if (!s.is_string()) + { + continue; + } + + auto ptr = s.get(); + + // tilde must be followed by 0 or 1 + if (ptr == "~") + { + ptr += "0"; + } + + // JSON Pointers must begin with "/" + ptr.insert(0, "/"); + + CHECK_NOTHROW(json::json_pointer("/" + ptr)); + + // check escape/unescape roundtrip + auto escaped = nlohmann::detail::escape(ptr); + nlohmann::detail::unescape(escaped); + CHECK(escaped == ptr); + } + } + } + + SECTION("ignore byte-order-mark") + { + SECTION("in a stream") + { + // read a file with a UTF-8 BOM + std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/bom.json"); + json j; + CHECK_NOTHROW(f >> j); + } + + SECTION("with an iterator") + { + std::string i = "\xef\xbb\xbf{\n \"foo\": true\n}"; + json _; + CHECK_NOTHROW(_ = json::parse(i.begin(), i.end())); + } + } + + SECTION("error for incomplete/wrong BOM") + { + json _; + CHECK_THROWS_AS(_ = json::parse("\xef\xbb"), json::parse_error&); + CHECK_THROWS_AS(_ = json::parse("\xef\xbb\xbb"), json::parse_error&); + } +} + +namespace +{ +void roundtrip(bool success_expected, const std::string& s); + +void roundtrip(bool success_expected, const std::string& s) +{ + CAPTURE(s) + json _; + + // create JSON string value + const json j = s; + // create JSON text + const std::string ps = std::string("\"") + s + "\""; + + if (success_expected) + { + // serialization succeeds + // dump() is nodiscard; this only checks that dumping does not throw + CHECK_NOTHROW(utils::ignore_return_value(j.dump())); + + // exclude parse test for U+0000 + if (s[0] != '\0') + { + // parsing JSON text succeeds + CHECK_NOTHROW(_ = json::parse(ps)); + } + + // roundtrip succeeds + CHECK_NOTHROW(_ = json::parse(j.dump())); + + // after roundtrip, the same string is stored + const json jr = json::parse(j.dump()); + CHECK(jr.get() == s); + } + else + { + // serialization fails + // dump() is nodiscard; the exception is thrown by dump() itself before it would return + CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); + + // parsing JSON text fails + CHECK_THROWS_AS(_ = json::parse(ps), json::parse_error&); + } +} +} // namespace + +TEST_CASE("Markus Kuhn's UTF-8 decoder capability and stress test") +{ + // Markus Kuhn - 2015-08-28 - CC BY 4.0 + // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + + SECTION("1 Some correct UTF-8 text") + { + roundtrip(true, "κόσμε"); + } + + SECTION("2 Boundary condition test cases") + { + SECTION("2.1 First possible sequence of a certain length") + { + // 2.1.1 1 byte (U-00000000) + roundtrip(true, std::string("\0", 1)); + // 2.1.2 2 bytes (U-00000080) + roundtrip(true, "\xc2\x80"); + // 2.1.3 3 bytes (U-00000800) + roundtrip(true, "\xe0\xa0\x80"); + // 2.1.4 4 bytes (U-00010000) + roundtrip(true, "\xf0\x90\x80\x80"); + + // 2.1.5 5 bytes (U-00200000) + roundtrip(false, "\xF8\x88\x80\x80\x80"); + // 2.1.6 6 bytes (U-04000000) + roundtrip(false, "\xFC\x84\x80\x80\x80\x80"); + } + + SECTION("2.2 Last possible sequence of a certain length") + { + // 2.2.1 1 byte (U-0000007F) + roundtrip(true, "\x7f"); + // 2.2.2 2 bytes (U-000007FF) + roundtrip(true, "\xdf\xbf"); + // 2.2.3 3 bytes (U-0000FFFF) + roundtrip(true, "\xef\xbf\xbf"); + + // 2.2.4 4 bytes (U-001FFFFF) + roundtrip(false, "\xF7\xBF\xBF\xBF"); + // 2.2.5 5 bytes (U-03FFFFFF) + roundtrip(false, "\xFB\xBF\xBF\xBF\xBF"); + // 2.2.6 6 bytes (U-7FFFFFFF) + roundtrip(false, "\xFD\xBF\xBF\xBF\xBF\xBF"); + } + + SECTION("2.3 Other boundary conditions") + { + // 2.3.1 U-0000D7FF = ed 9f bf + roundtrip(true, "\xed\x9f\xbf"); + // 2.3.2 U-0000E000 = ee 80 80 + roundtrip(true, "\xee\x80\x80"); + // 2.3.3 U-0000FFFD = ef bf bd + roundtrip(true, "\xef\xbf\xbd"); + // 2.3.4 U-0010FFFF = f4 8f bf bf + roundtrip(true, "\xf4\x8f\xbf\xbf"); + + // 2.3.5 U-00110000 = f4 90 80 80 + roundtrip(false, "\xf4\x90\x80\x80"); + } + } + + SECTION("3 Malformed sequences") + { + SECTION("3.1 Unexpected continuation bytes") + { + // Each unexpected continuation byte should be separately signalled as a + // malformed sequence of its own. + + // 3.1.1 First continuation byte 0x80 + roundtrip(false, "\x80"); + // 3.1.2 Last continuation byte 0xbf + roundtrip(false, "\xbf"); + + // 3.1.3 2 continuation bytes + roundtrip(false, "\x80\xbf"); + // 3.1.4 3 continuation bytes + roundtrip(false, "\x80\xbf\x80"); + // 3.1.5 4 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf"); + // 3.1.6 5 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf\x80"); + // 3.1.7 6 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf\x80\xbf"); + // 3.1.8 7 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf\x80\xbf\x80"); + + // 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf) + roundtrip(false, "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"); + } + + SECTION("3.2 Lonely start characters") + { + // 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf) + roundtrip(false, "\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf"); + // 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef) + roundtrip(false, "\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef"); + // 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7) + roundtrip(false, "\xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7"); + // 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb) + roundtrip(false, "\xf8 \xf9 \xfa \xfb"); + // 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd) + roundtrip(false, "\xfc \xfd"); + } + + SECTION("3.3 Sequences with last continuation byte missing") + { + // All bytes of an incomplete sequence should be signalled as a single + // malformed sequence, i.e., you should see only a single replacement + // character in each of the next 10 tests. (Characters as in section 2) + + // 3.3.1 2-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xc0"); + // 3.3.2 3-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xe0\x80"); + // 3.3.3 4-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xf0\x80\x80"); + // 3.3.4 5-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xf8\x80\x80\x80"); + // 3.3.5 6-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xfc\x80\x80\x80\x80"); + // 3.3.6 2-byte sequence with last byte missing (U-000007FF) + roundtrip(false, "\xdf"); + // 3.3.7 3-byte sequence with last byte missing (U-0000FFFF) + roundtrip(false, "\xef\xbf"); + // 3.3.8 4-byte sequence with last byte missing (U-001FFFFF) + roundtrip(false, "\xf7\xbf\xbf"); + // 3.3.9 5-byte sequence with last byte missing (U-03FFFFFF) + roundtrip(false, "\xfb\xbf\xbf\xbf"); + // 3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF) + roundtrip(false, "\xfd\xbf\xbf\xbf\xbf"); + } + + SECTION("3.4 Concatenation of incomplete sequences") + { + // All the 10 sequences of 3.3 concatenated, you should see 10 malformed + // sequences being signalled: + roundtrip(false, "\xc0\xe0\x80\xf0\x80\x80\xf8\x80\x80\x80\xfc\x80\x80\x80\x80\xdf\xef\xbf\xf7\xbf\xbf\xfb\xbf\xbf\xbf\xfd\xbf\xbf\xbf\xbf"); + } + + SECTION("3.5 Impossible bytes") + { + // The following two bytes cannot appear in a correct UTF-8 string + + // 3.5.1 fe + roundtrip(false, "\xfe"); + // 3.5.2 ff + roundtrip(false, "\xff"); + // 3.5.3 fe fe ff ff + roundtrip(false, "\xfe\xfe\xff\xff"); + } + } + + SECTION("4 Overlong sequences") + { + // The following sequences are not malformed according to the letter of + // the Unicode 2.0 standard. However, they are longer then necessary and + // a correct UTF-8 encoder is not allowed to produce them. A "safe UTF-8 + // decoder" should reject them just like malformed sequences for two + // reasons: (1) It helps to debug applications if overlong sequences are + // not treated as valid representations of characters, because this helps + // to spot problems more quickly. (2) Overlong sequences provide + // alternative representations of characters, that could maliciously be + // used to bypass filters that check only for ASCII characters. For + // instance, a 2-byte encoded line feed (LF) would not be caught by a + // line counter that counts only 0x0a bytes, but it would still be + // processed as a line feed by an unsafe UTF-8 decoder later in the + // pipeline. From a security point of view, ASCII compatibility of UTF-8 + // sequences means also, that ASCII characters are *only* allowed to be + // represented by ASCII bytes in the range 0x00-0x7f. To ensure this + // aspect of ASCII compatibility, use only "safe UTF-8 decoders" that + // reject overlong UTF-8 sequences for which a shorter encoding exists. + + SECTION("4.1 Examples of an overlong ASCII character") + { + // With a safe UTF-8 decoder, all the following five overlong + // representations of the ASCII character slash ("/") should be rejected + // like a malformed UTF-8 sequence, for instance by substituting it with + // a replacement character. If you see a slash below, you do not have a + // safe UTF-8 decoder! + + // 4.1.1 U+002F = c0 af + roundtrip(false, "\xc0\xaf"); + // 4.1.2 U+002F = e0 80 af + roundtrip(false, "\xe0\x80\xaf"); + // 4.1.3 U+002F = f0 80 80 af + roundtrip(false, "\xf0\x80\x80\xaf"); + // 4.1.4 U+002F = f8 80 80 80 af + roundtrip(false, "\xf8\x80\x80\x80\xaf"); + // 4.1.5 U+002F = fc 80 80 80 80 af + roundtrip(false, "\xfc\x80\x80\x80\x80\xaf"); + } + + SECTION("4.2 Maximum overlong sequences") + { + // Below you see the highest Unicode value that is still resulting in an + // overlong sequence if represented with the given number of bytes. This + // is a boundary test for safe UTF-8 decoders. All five characters should + // be rejected like malformed UTF-8 sequences. + + // 4.2.1 U-0000007F = c1 bf + roundtrip(false, "\xc1\xbf"); + // 4.2.2 U-000007FF = e0 9f bf + roundtrip(false, "\xe0\x9f\xbf"); + // 4.2.3 U-0000FFFF = f0 8f bf bf + roundtrip(false, "\xf0\x8f\xbf\xbf"); + // 4.2.4 U-001FFFFF = f8 87 bf bf bf + roundtrip(false, "\xf8\x87\xbf\xbf\xbf"); + // 4.2.5 U-03FFFFFF = fc 83 bf bf bf bf + roundtrip(false, "\xfc\x83\xbf\xbf\xbf\xbf"); + } + + SECTION("4.3 Overlong representation of the NUL character") + { + // The following five sequences should also be rejected like malformed + // UTF-8 sequences and should not be treated like the ASCII NUL + // character. + + // 4.3.1 U+0000 = c0 80 + roundtrip(false, "\xc0\x80"); + // 4.3.2 U+0000 = e0 80 80 + roundtrip(false, "\xe0\x80\x80"); + // 4.3.3 U+0000 = f0 80 80 80 + roundtrip(false, "\xf0\x80\x80\x80"); + // 4.3.4 U+0000 = f8 80 80 80 80 + roundtrip(false, "\xf8\x80\x80\x80\x80"); + // 4.3.5 U+0000 = fc 80 80 80 80 80 + roundtrip(false, "\xfc\x80\x80\x80\x80\x80"); + } + } + + SECTION("5 Illegal code positions") + { + // The following UTF-8 sequences should be rejected like malformed + // sequences, because they never represent valid ISO 10646 characters and + // a UTF-8 decoder that accepts them might introduce security problems + // comparable to overlong UTF-8 sequences. + + SECTION("5.1 Single UTF-16 surrogates") + { + // 5.1.1 U+D800 = ed a0 80 + roundtrip(false, "\xed\xa0\x80"); + // 5.1.2 U+DB7F = ed ad bf + roundtrip(false, "\xed\xad\xbf"); + // 5.1.3 U+DB80 = ed ae 80 + roundtrip(false, "\xed\xae\x80"); + // 5.1.4 U+DBFF = ed af bf + roundtrip(false, "\xed\xaf\xbf"); + // 5.1.5 U+DC00 = ed b0 80 + roundtrip(false, "\xed\xb0\x80"); + // 5.1.6 U+DF80 = ed be 80 + roundtrip(false, "\xed\xbe\x80"); + // 5.1.7 U+DFFF = ed bf bf + roundtrip(false, "\xed\xbf\xbf"); + } + + SECTION("5.2 Paired UTF-16 surrogates") + { + // 5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 + roundtrip(false, "\xed\xa0\x80\xed\xb0\x80"); + // 5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf + roundtrip(false, "\xed\xa0\x80\xed\xbf\xbf"); + // 5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 + roundtrip(false, "\xed\xad\xbf\xed\xb0\x80"); + // 5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf + roundtrip(false, "\xed\xad\xbf\xed\xbf\xbf"); + // 5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 + roundtrip(false, "\xed\xae\x80\xed\xb0\x80"); + // 5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf + roundtrip(false, "\xed\xae\x80\xed\xbf\xbf"); + // 5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 + roundtrip(false, "\xed\xaf\xbf\xed\xb0\x80"); + // 5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf + roundtrip(false, "\xed\xaf\xbf\xed\xbf\xbf"); + } + + SECTION("5.3 Noncharacter code positions") + { + // The following "noncharacters" are "reserved for internal use" by + // applications, and according to older versions of the Unicode Standard + // "should never be interchanged". Unicode Corrigendum #9 dropped the + // latter restriction. Nevertheless, their presence in incoming UTF-8 data + // can remain a potential security risk, depending on what use is made of + // these codes subsequently. Examples of such internal use: + // + // - Some file APIs with 16-bit characters may use the integer value -1 + // = U+FFFF to signal an end-of-file (EOF) or error condition. + // + // - In some UTF-16 receivers, code point U+FFFE might trigger a + // byte-swap operation (to convert between UTF-16LE and UTF-16BE). + // + // With such internal use of noncharacters, it may be desirable and safer + // to block those code points in UTF-8 decoders, as they should never + // occur legitimately in incoming UTF-8 data, and could trigger unsafe + // behaviour in subsequent processing. + + // Particularly problematic noncharacters in 16-bit applications: + + // 5.3.1 U+FFFE = ef bf be + roundtrip(true, "\xef\xbf\xbe"); + // 5.3.2 U+FFFF = ef bf bf + roundtrip(true, "\xef\xbf\xbf"); + + // 5.3.3 U+FDD0 .. U+FDEF + roundtrip(true, "\xEF\xB7\x90"); + roundtrip(true, "\xEF\xB7\x91"); + roundtrip(true, "\xEF\xB7\x92"); + roundtrip(true, "\xEF\xB7\x93"); + roundtrip(true, "\xEF\xB7\x94"); + roundtrip(true, "\xEF\xB7\x95"); + roundtrip(true, "\xEF\xB7\x96"); + roundtrip(true, "\xEF\xB7\x97"); + roundtrip(true, "\xEF\xB7\x98"); + roundtrip(true, "\xEF\xB7\x99"); + roundtrip(true, "\xEF\xB7\x9A"); + roundtrip(true, "\xEF\xB7\x9B"); + roundtrip(true, "\xEF\xB7\x9C"); + roundtrip(true, "\xEF\xB7\x9D"); + roundtrip(true, "\xEF\xB7\x9E"); + roundtrip(true, "\xEF\xB7\x9F"); + roundtrip(true, "\xEF\xB7\xA0"); + roundtrip(true, "\xEF\xB7\xA1"); + roundtrip(true, "\xEF\xB7\xA2"); + roundtrip(true, "\xEF\xB7\xA3"); + roundtrip(true, "\xEF\xB7\xA4"); + roundtrip(true, "\xEF\xB7\xA5"); + roundtrip(true, "\xEF\xB7\xA6"); + roundtrip(true, "\xEF\xB7\xA7"); + roundtrip(true, "\xEF\xB7\xA8"); + roundtrip(true, "\xEF\xB7\xA9"); + roundtrip(true, "\xEF\xB7\xAA"); + roundtrip(true, "\xEF\xB7\xAB"); + roundtrip(true, "\xEF\xB7\xAC"); + roundtrip(true, "\xEF\xB7\xAD"); + roundtrip(true, "\xEF\xB7\xAE"); + roundtrip(true, "\xEF\xB7\xAF"); + + // 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) + roundtrip(true, "\xF0\x9F\xBF\xBF"); + roundtrip(true, "\xF0\xAF\xBF\xBF"); + roundtrip(true, "\xF0\xBF\xBF\xBF"); + roundtrip(true, "\xF1\x8F\xBF\xBF"); + roundtrip(true, "\xF1\x9F\xBF\xBF"); + roundtrip(true, "\xF1\xAF\xBF\xBF"); + roundtrip(true, "\xF1\xBF\xBF\xBF"); + roundtrip(true, "\xF2\x8F\xBF\xBF"); + roundtrip(true, "\xF2\x9F\xBF\xBF"); + roundtrip(true, "\xF2\xAF\xBF\xBF"); + } + } +} + +TEST_CASE("Unicode RFC 3629") +{ + SECTION("RFC 3629") + { + /* + RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as + follows: + + A UTF-8 string is a sequence of octets representing a sequence of UCS + characters. An octet sequence is valid UTF-8 only if it matches the + following syntax, which is derived from the rules for encoding UTF-8 + and is expressed in the ABNF of [RFC2234]. + + UTF8-octets = *( UTF8-char ) + UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 + UTF8-1 = %x00-7F + UTF8-2 = %xC2-DF UTF8-tail + UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / + %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) + UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / + %xF4 %x80-8F 2( UTF8-tail ) + UTF8-tail = %x80-BF + */ + + SECTION("ill-formed first byte") + { + for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + + for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("UTF8-1 (x00-x7F)") + { + SECTION("well-formed") + { + for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1) + { + // unescaped control characters are parse errors in JSON + if (0x00 <= byte1 && byte1 <= 0x1F) + { + check_utf8string(false, byte1); + continue; + } + + // a single quote is a parse error in JSON + if (byte1 == 0x22) + { + check_utf8string(false, byte1); + continue; + } + + // a single backslash is a parse error in JSON + if (byte1 == 0x5C) + { + check_utf8string(false, byte1); + continue; + } + + // all other characters are OK + check_utf8string(true, byte1); + check_utf8dump(true, byte1); + } + } + } + + SECTION("UTF8-2 (xC2-xDF UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + check_utf8string(true, byte1, byte2); + check_utf8dump(true, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: wrong second byte") + { + for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 && byte2 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + } + + SECTION("UTF8-3 (xE0 xA0-BF UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + check_utf8dump(true, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0xA0 <= byte2 && byte2 <= 0xBF) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0xA0, 0xBF)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + } + + SECTION("UTF8-3 (xE1-xEC UTF8-tail UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + check_utf8dump(true, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 && byte2 <= 0xBF) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + } + + SECTION("UTF8-3 (xED x80-9F UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + check_utf8dump(true, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 && byte2 <= 0x9F) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0x9F)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + } + + SECTION("UTF8-3 (xEE-xEF UTF8-tail UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(true, byte1, byte2, byte3); + check_utf8dump(true, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 && byte2 <= 0xBF) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + } + + SECTION("UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(true, byte1, byte2, byte3, byte4); + check_utf8dump(true, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing fourth byte") + { + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x90 <= byte2 && byte2 <= 0xBF) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (const int byte4 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x90, 0xBF)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + for (const int byte4 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong fourth byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x90, 0xBF)) + { + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + { + // skip correct fourth byte + if (0x80 <= byte4 && byte4 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + } + + SECTION("UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(true, byte1, byte2, byte3, byte4); + check_utf8dump(true, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing fourth byte") + { + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 && byte2 <= 0xBF) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (const int byte4 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + for (const int byte4 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong fourth byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + { + // skip correct fourth byte + if (0x80 <= byte4 && byte4 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + } + + SECTION("UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)") + { + SECTION("well-formed") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) + { + check_utf8string(true, byte1, byte2, byte3, byte4); + check_utf8dump(true, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: missing second byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + check_utf8string(false, byte1); + check_utf8dump(false, byte1); + } + } + + SECTION("ill-formed: missing third byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + { + check_utf8string(false, byte1, byte2); + check_utf8dump(false, byte1, byte2); + } + } + } + + SECTION("ill-formed: missing fourth byte") + { + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) + { + for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) + { + check_utf8string(false, byte1, byte2, byte3); + check_utf8dump(false, byte1, byte2, byte3); + } + } + } + } + + SECTION("ill-formed: wrong second byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) + { + // skip correct second byte + if (0x80 <= byte2 && byte2 <= 0x8F) + { + continue; + } + + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (const int byte4 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong third byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0x8F)) + { + for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) + { + // skip correct third byte + if (0x80 <= byte3 && byte3 <= 0xBF) + { + continue; + } + + for (const int byte4 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + + SECTION("ill-formed: wrong fourth byte") + { + // the other bytes take the ends of each byte class, see utils::utf8_continuation_bytes (#5418) + for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) + { + for (const int byte2 : utils::utf8_continuation_bytes(0x80, 0x8F)) + { + for (const int byte3 : utils::utf8_continuation_bytes(0x80, 0xBF)) + { + for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) + { + // skip correct fourth byte + if (0x80 <= byte4 && byte4 <= 0xBF) + { + continue; + } + + check_utf8string(false, byte1, byte2, byte3, byte4); + check_utf8dump(false, byte1, byte2, byte3, byte4); + } + } + } + } + } + } + } +} + +DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-unicode1.cpp b/tests/src/unit-unicode1.cpp deleted file mode 100644 index 2d744003a..000000000 --- a/tests/src/unit-unicode1.cpp +++ /dev/null @@ -1,623 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.12.0 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann -// SPDX-License-Identifier: MIT - -#include "doctest_compatibility.h" - -// for some reason including this after the json header leads to linker errors with VS 2017... -#include -#include -using nlohmann::json; - -#include -#include -#include -#include "make_test_data_available.hpp" -#include "test_utils.hpp" - -TEST_CASE("Unicode (1/5)" * doctest::skip()) -{ - SECTION("\\uxxxx sequences") - { - // create an escaped string from a code point - const auto codepoint_to_unicode = [](std::size_t cp) - { - // code points are represented as a six-character sequence: a - // reverse solidus, followed by the lowercase letter u, followed - // by four hexadecimal digits that encode the character's code - // point - std::stringstream ss; - ss << "\\u" << std::setw(4) << std::setfill('0') << std::hex << cp; - return ss.str(); - }; - - SECTION("correct sequences") - { - // generate all UTF-8 code points; in total, 1112064 code points are - // generated: 0x1FFFFF code points - 2048 invalid values between - // 0xD800 and 0xDFFF. - for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp) - { - // string to store the code point as in \uxxxx format - std::string json_text = "\""; - - // decide whether to use one or two \uxxxx sequences - if (cp < 0x10000u) - { - // The Unicode standard permanently reserves these code point - // values for UTF-16 encoding of the high and low surrogates, and - // they will never be assigned a character, so there should be no - // reason to encode them. The official Unicode standard says that - // no UTF forms, including UTF-16, can encode these code points. - if (cp >= 0xD800u && cp <= 0xDFFFu) - { - // if we would not skip these code points, we would get a - // "missing low surrogate" exception - continue; - } - - // code points in the Basic Multilingual Plane can be - // represented with one \uxxxx sequence - json_text += codepoint_to_unicode(cp); - } - else - { - // To escape an extended character that is not in the Basic - // Multilingual Plane, the character is represented as a - // 12-character sequence, encoding the UTF-16 surrogate pair - const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu); - const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu); - json_text += codepoint_to_unicode(codepoint1) + codepoint_to_unicode(codepoint2); - } - - json_text += "\""; - CAPTURE(json_text) - json _; - CHECK_NOTHROW(_ = json::parse(json_text)); - } - } - - SECTION("incorrect sequences") - { - SECTION("incorrect surrogate values") - { - json _; - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uDC00\\uDC00\""), "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uDC00'", json::parse_error&); - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD7FF\\uDC00\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uD7FF\\uDC00'", json::parse_error&); - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800]\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800]'", json::parse_error&); - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\v\""), "[json.exception.parse_error.101] parse error at line 1, column 9: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\v'", json::parse_error&); - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\u123\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\uD800\\u123\"'", json::parse_error&); - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\uDBFF\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uDBFF'", json::parse_error&); - - CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD800\\uE000\""), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uE000'", json::parse_error&); - } - } - -#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) - SECTION("incorrect sequences") - { - SECTION("high surrogate without low surrogate") - { - // D800..DBFF are high surrogates and must be followed by low - // surrogates DC00..DFFF; here, nothing follows - for (std::size_t cp = 0xD800u; cp <= 0xDBFFu; ++cp) - { - std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; - CAPTURE(json_text) - CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); - } - } - - SECTION("high surrogate with wrong low surrogate") - { - // D800..DBFF are high surrogates and must be followed by low - // surrogates DC00..DFFF; here a different sequence follows - for (std::size_t cp1 = 0xD800u; cp1 <= 0xDBFFu; ++cp1) - { - for (std::size_t cp2 = 0x0000u; cp2 <= 0xFFFFu; ++cp2) - { - if (0xDC00u <= cp2 && cp2 <= 0xDFFFu) - { - continue; - } - - std::string json_text = "\"" + codepoint_to_unicode(cp1) + codepoint_to_unicode(cp2) + "\""; - CAPTURE(json_text) - CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); - } - } - } - - SECTION("low surrogate without high surrogate") - { - // low surrogates DC00..DFFF must follow high surrogates; here, - // they occur alone - for (std::size_t cp = 0xDC00u; cp <= 0xDFFFu; ++cp) - { - std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; - CAPTURE(json_text) - CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); - } - } - - } -#endif - } - - SECTION("read all unicode characters") - { - // read a file with all Unicode characters stored as single-character - // strings in a JSON array - std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json"); - json j; - CHECK_NOTHROW(f >> j); - - // the array has 1112064 + 1 elements (a terminating "null" value) - // Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between - // 0xD800 and 0xDFFF. - CHECK(j.size() == 1112065); - - SECTION("check JSON Pointers") - { - for (const auto& s : j) - { - // skip non-string JSON values - if (!s.is_string()) - { - continue; - } - - auto ptr = s.get(); - - // tilde must be followed by 0 or 1 - if (ptr == "~") - { - ptr += "0"; - } - - // JSON Pointers must begin with "/" - ptr.insert(0, "/"); - - CHECK_NOTHROW(json::json_pointer("/" + ptr)); - - // check escape/unescape roundtrip - auto escaped = nlohmann::detail::escape(ptr); - nlohmann::detail::unescape(escaped); - CHECK(escaped == ptr); - } - } - } - - SECTION("ignore byte-order-mark") - { - SECTION("in a stream") - { - // read a file with a UTF-8 BOM - std::ifstream f(TEST_DATA_DIRECTORY "/json_nlohmann_tests/bom.json"); - json j; - CHECK_NOTHROW(f >> j); - } - - SECTION("with an iterator") - { - std::string i = "\xef\xbb\xbf{\n \"foo\": true\n}"; - json _; - CHECK_NOTHROW(_ = json::parse(i.begin(), i.end())); - } - } - - SECTION("error for incomplete/wrong BOM") - { - json _; - CHECK_THROWS_AS(_ = json::parse("\xef\xbb"), json::parse_error&); - CHECK_THROWS_AS(_ = json::parse("\xef\xbb\xbb"), json::parse_error&); - } -} - -namespace -{ -void roundtrip(bool success_expected, const std::string& s); - -void roundtrip(bool success_expected, const std::string& s) -{ - CAPTURE(s) - json _; - - // create JSON string value - const json j = s; - // create JSON text - const std::string ps = std::string("\"") + s + "\""; - - if (success_expected) - { - // serialization succeeds - // dump() is nodiscard; this only checks that dumping does not throw - CHECK_NOTHROW(utils::ignore_return_value(j.dump())); - - // exclude parse test for U+0000 - if (s[0] != '\0') - { - // parsing JSON text succeeds - CHECK_NOTHROW(_ = json::parse(ps)); - } - - // roundtrip succeeds - CHECK_NOTHROW(_ = json::parse(j.dump())); - - // after roundtrip, the same string is stored - const json jr = json::parse(j.dump()); - CHECK(jr.get() == s); - } - else - { - // serialization fails - // dump() is nodiscard; the exception is thrown by dump() itself before it would return - CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); - - // parsing JSON text fails - CHECK_THROWS_AS(_ = json::parse(ps), json::parse_error&); - } -} -} // namespace - -TEST_CASE("Markus Kuhn's UTF-8 decoder capability and stress test") -{ - // Markus Kuhn - 2015-08-28 - CC BY 4.0 - // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt - - SECTION("1 Some correct UTF-8 text") - { - roundtrip(true, "κόσμε"); - } - - SECTION("2 Boundary condition test cases") - { - SECTION("2.1 First possible sequence of a certain length") - { - // 2.1.1 1 byte (U-00000000) - roundtrip(true, std::string("\0", 1)); - // 2.1.2 2 bytes (U-00000080) - roundtrip(true, "\xc2\x80"); - // 2.1.3 3 bytes (U-00000800) - roundtrip(true, "\xe0\xa0\x80"); - // 2.1.4 4 bytes (U-00010000) - roundtrip(true, "\xf0\x90\x80\x80"); - - // 2.1.5 5 bytes (U-00200000) - roundtrip(false, "\xF8\x88\x80\x80\x80"); - // 2.1.6 6 bytes (U-04000000) - roundtrip(false, "\xFC\x84\x80\x80\x80\x80"); - } - - SECTION("2.2 Last possible sequence of a certain length") - { - // 2.2.1 1 byte (U-0000007F) - roundtrip(true, "\x7f"); - // 2.2.2 2 bytes (U-000007FF) - roundtrip(true, "\xdf\xbf"); - // 2.2.3 3 bytes (U-0000FFFF) - roundtrip(true, "\xef\xbf\xbf"); - - // 2.2.4 4 bytes (U-001FFFFF) - roundtrip(false, "\xF7\xBF\xBF\xBF"); - // 2.2.5 5 bytes (U-03FFFFFF) - roundtrip(false, "\xFB\xBF\xBF\xBF\xBF"); - // 2.2.6 6 bytes (U-7FFFFFFF) - roundtrip(false, "\xFD\xBF\xBF\xBF\xBF\xBF"); - } - - SECTION("2.3 Other boundary conditions") - { - // 2.3.1 U-0000D7FF = ed 9f bf - roundtrip(true, "\xed\x9f\xbf"); - // 2.3.2 U-0000E000 = ee 80 80 - roundtrip(true, "\xee\x80\x80"); - // 2.3.3 U-0000FFFD = ef bf bd - roundtrip(true, "\xef\xbf\xbd"); - // 2.3.4 U-0010FFFF = f4 8f bf bf - roundtrip(true, "\xf4\x8f\xbf\xbf"); - - // 2.3.5 U-00110000 = f4 90 80 80 - roundtrip(false, "\xf4\x90\x80\x80"); - } - } - - SECTION("3 Malformed sequences") - { - SECTION("3.1 Unexpected continuation bytes") - { - // Each unexpected continuation byte should be separately signalled as a - // malformed sequence of its own. - - // 3.1.1 First continuation byte 0x80 - roundtrip(false, "\x80"); - // 3.1.2 Last continuation byte 0xbf - roundtrip(false, "\xbf"); - - // 3.1.3 2 continuation bytes - roundtrip(false, "\x80\xbf"); - // 3.1.4 3 continuation bytes - roundtrip(false, "\x80\xbf\x80"); - // 3.1.5 4 continuation bytes - roundtrip(false, "\x80\xbf\x80\xbf"); - // 3.1.6 5 continuation bytes - roundtrip(false, "\x80\xbf\x80\xbf\x80"); - // 3.1.7 6 continuation bytes - roundtrip(false, "\x80\xbf\x80\xbf\x80\xbf"); - // 3.1.8 7 continuation bytes - roundtrip(false, "\x80\xbf\x80\xbf\x80\xbf\x80"); - - // 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf) - roundtrip(false, "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"); - } - - SECTION("3.2 Lonely start characters") - { - // 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf) - roundtrip(false, "\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf"); - // 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef) - roundtrip(false, "\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef"); - // 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7) - roundtrip(false, "\xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7"); - // 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb) - roundtrip(false, "\xf8 \xf9 \xfa \xfb"); - // 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd) - roundtrip(false, "\xfc \xfd"); - } - - SECTION("3.3 Sequences with last continuation byte missing") - { - // All bytes of an incomplete sequence should be signalled as a single - // malformed sequence, i.e., you should see only a single replacement - // character in each of the next 10 tests. (Characters as in section 2) - - // 3.3.1 2-byte sequence with last byte missing (U+0000) - roundtrip(false, "\xc0"); - // 3.3.2 3-byte sequence with last byte missing (U+0000) - roundtrip(false, "\xe0\x80"); - // 3.3.3 4-byte sequence with last byte missing (U+0000) - roundtrip(false, "\xf0\x80\x80"); - // 3.3.4 5-byte sequence with last byte missing (U+0000) - roundtrip(false, "\xf8\x80\x80\x80"); - // 3.3.5 6-byte sequence with last byte missing (U+0000) - roundtrip(false, "\xfc\x80\x80\x80\x80"); - // 3.3.6 2-byte sequence with last byte missing (U-000007FF) - roundtrip(false, "\xdf"); - // 3.3.7 3-byte sequence with last byte missing (U-0000FFFF) - roundtrip(false, "\xef\xbf"); - // 3.3.8 4-byte sequence with last byte missing (U-001FFFFF) - roundtrip(false, "\xf7\xbf\xbf"); - // 3.3.9 5-byte sequence with last byte missing (U-03FFFFFF) - roundtrip(false, "\xfb\xbf\xbf\xbf"); - // 3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF) - roundtrip(false, "\xfd\xbf\xbf\xbf\xbf"); - } - - SECTION("3.4 Concatenation of incomplete sequences") - { - // All the 10 sequences of 3.3 concatenated, you should see 10 malformed - // sequences being signalled: - roundtrip(false, "\xc0\xe0\x80\xf0\x80\x80\xf8\x80\x80\x80\xfc\x80\x80\x80\x80\xdf\xef\xbf\xf7\xbf\xbf\xfb\xbf\xbf\xbf\xfd\xbf\xbf\xbf\xbf"); - } - - SECTION("3.5 Impossible bytes") - { - // The following two bytes cannot appear in a correct UTF-8 string - - // 3.5.1 fe - roundtrip(false, "\xfe"); - // 3.5.2 ff - roundtrip(false, "\xff"); - // 3.5.3 fe fe ff ff - roundtrip(false, "\xfe\xfe\xff\xff"); - } - } - - SECTION("4 Overlong sequences") - { - // The following sequences are not malformed according to the letter of - // the Unicode 2.0 standard. However, they are longer then necessary and - // a correct UTF-8 encoder is not allowed to produce them. A "safe UTF-8 - // decoder" should reject them just like malformed sequences for two - // reasons: (1) It helps to debug applications if overlong sequences are - // not treated as valid representations of characters, because this helps - // to spot problems more quickly. (2) Overlong sequences provide - // alternative representations of characters, that could maliciously be - // used to bypass filters that check only for ASCII characters. For - // instance, a 2-byte encoded line feed (LF) would not be caught by a - // line counter that counts only 0x0a bytes, but it would still be - // processed as a line feed by an unsafe UTF-8 decoder later in the - // pipeline. From a security point of view, ASCII compatibility of UTF-8 - // sequences means also, that ASCII characters are *only* allowed to be - // represented by ASCII bytes in the range 0x00-0x7f. To ensure this - // aspect of ASCII compatibility, use only "safe UTF-8 decoders" that - // reject overlong UTF-8 sequences for which a shorter encoding exists. - - SECTION("4.1 Examples of an overlong ASCII character") - { - // With a safe UTF-8 decoder, all the following five overlong - // representations of the ASCII character slash ("/") should be rejected - // like a malformed UTF-8 sequence, for instance by substituting it with - // a replacement character. If you see a slash below, you do not have a - // safe UTF-8 decoder! - - // 4.1.1 U+002F = c0 af - roundtrip(false, "\xc0\xaf"); - // 4.1.2 U+002F = e0 80 af - roundtrip(false, "\xe0\x80\xaf"); - // 4.1.3 U+002F = f0 80 80 af - roundtrip(false, "\xf0\x80\x80\xaf"); - // 4.1.4 U+002F = f8 80 80 80 af - roundtrip(false, "\xf8\x80\x80\x80\xaf"); - // 4.1.5 U+002F = fc 80 80 80 80 af - roundtrip(false, "\xfc\x80\x80\x80\x80\xaf"); - } - - SECTION("4.2 Maximum overlong sequences") - { - // Below you see the highest Unicode value that is still resulting in an - // overlong sequence if represented with the given number of bytes. This - // is a boundary test for safe UTF-8 decoders. All five characters should - // be rejected like malformed UTF-8 sequences. - - // 4.2.1 U-0000007F = c1 bf - roundtrip(false, "\xc1\xbf"); - // 4.2.2 U-000007FF = e0 9f bf - roundtrip(false, "\xe0\x9f\xbf"); - // 4.2.3 U-0000FFFF = f0 8f bf bf - roundtrip(false, "\xf0\x8f\xbf\xbf"); - // 4.2.4 U-001FFFFF = f8 87 bf bf bf - roundtrip(false, "\xf8\x87\xbf\xbf\xbf"); - // 4.2.5 U-03FFFFFF = fc 83 bf bf bf bf - roundtrip(false, "\xfc\x83\xbf\xbf\xbf\xbf"); - } - - SECTION("4.3 Overlong representation of the NUL character") - { - // The following five sequences should also be rejected like malformed - // UTF-8 sequences and should not be treated like the ASCII NUL - // character. - - // 4.3.1 U+0000 = c0 80 - roundtrip(false, "\xc0\x80"); - // 4.3.2 U+0000 = e0 80 80 - roundtrip(false, "\xe0\x80\x80"); - // 4.3.3 U+0000 = f0 80 80 80 - roundtrip(false, "\xf0\x80\x80\x80"); - // 4.3.4 U+0000 = f8 80 80 80 80 - roundtrip(false, "\xf8\x80\x80\x80\x80"); - // 4.3.5 U+0000 = fc 80 80 80 80 80 - roundtrip(false, "\xfc\x80\x80\x80\x80\x80"); - } - } - - SECTION("5 Illegal code positions") - { - // The following UTF-8 sequences should be rejected like malformed - // sequences, because they never represent valid ISO 10646 characters and - // a UTF-8 decoder that accepts them might introduce security problems - // comparable to overlong UTF-8 sequences. - - SECTION("5.1 Single UTF-16 surrogates") - { - // 5.1.1 U+D800 = ed a0 80 - roundtrip(false, "\xed\xa0\x80"); - // 5.1.2 U+DB7F = ed ad bf - roundtrip(false, "\xed\xad\xbf"); - // 5.1.3 U+DB80 = ed ae 80 - roundtrip(false, "\xed\xae\x80"); - // 5.1.4 U+DBFF = ed af bf - roundtrip(false, "\xed\xaf\xbf"); - // 5.1.5 U+DC00 = ed b0 80 - roundtrip(false, "\xed\xb0\x80"); - // 5.1.6 U+DF80 = ed be 80 - roundtrip(false, "\xed\xbe\x80"); - // 5.1.7 U+DFFF = ed bf bf - roundtrip(false, "\xed\xbf\xbf"); - } - - SECTION("5.2 Paired UTF-16 surrogates") - { - // 5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 - roundtrip(false, "\xed\xa0\x80\xed\xb0\x80"); - // 5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf - roundtrip(false, "\xed\xa0\x80\xed\xbf\xbf"); - // 5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 - roundtrip(false, "\xed\xad\xbf\xed\xb0\x80"); - // 5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf - roundtrip(false, "\xed\xad\xbf\xed\xbf\xbf"); - // 5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 - roundtrip(false, "\xed\xae\x80\xed\xb0\x80"); - // 5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf - roundtrip(false, "\xed\xae\x80\xed\xbf\xbf"); - // 5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 - roundtrip(false, "\xed\xaf\xbf\xed\xb0\x80"); - // 5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf - roundtrip(false, "\xed\xaf\xbf\xed\xbf\xbf"); - } - - SECTION("5.3 Noncharacter code positions") - { - // The following "noncharacters" are "reserved for internal use" by - // applications, and according to older versions of the Unicode Standard - // "should never be interchanged". Unicode Corrigendum #9 dropped the - // latter restriction. Nevertheless, their presence in incoming UTF-8 data - // can remain a potential security risk, depending on what use is made of - // these codes subsequently. Examples of such internal use: - // - // - Some file APIs with 16-bit characters may use the integer value -1 - // = U+FFFF to signal an end-of-file (EOF) or error condition. - // - // - In some UTF-16 receivers, code point U+FFFE might trigger a - // byte-swap operation (to convert between UTF-16LE and UTF-16BE). - // - // With such internal use of noncharacters, it may be desirable and safer - // to block those code points in UTF-8 decoders, as they should never - // occur legitimately in incoming UTF-8 data, and could trigger unsafe - // behaviour in subsequent processing. - - // Particularly problematic noncharacters in 16-bit applications: - - // 5.3.1 U+FFFE = ef bf be - roundtrip(true, "\xef\xbf\xbe"); - // 5.3.2 U+FFFF = ef bf bf - roundtrip(true, "\xef\xbf\xbf"); - - // 5.3.3 U+FDD0 .. U+FDEF - roundtrip(true, "\xEF\xB7\x90"); - roundtrip(true, "\xEF\xB7\x91"); - roundtrip(true, "\xEF\xB7\x92"); - roundtrip(true, "\xEF\xB7\x93"); - roundtrip(true, "\xEF\xB7\x94"); - roundtrip(true, "\xEF\xB7\x95"); - roundtrip(true, "\xEF\xB7\x96"); - roundtrip(true, "\xEF\xB7\x97"); - roundtrip(true, "\xEF\xB7\x98"); - roundtrip(true, "\xEF\xB7\x99"); - roundtrip(true, "\xEF\xB7\x9A"); - roundtrip(true, "\xEF\xB7\x9B"); - roundtrip(true, "\xEF\xB7\x9C"); - roundtrip(true, "\xEF\xB7\x9D"); - roundtrip(true, "\xEF\xB7\x9E"); - roundtrip(true, "\xEF\xB7\x9F"); - roundtrip(true, "\xEF\xB7\xA0"); - roundtrip(true, "\xEF\xB7\xA1"); - roundtrip(true, "\xEF\xB7\xA2"); - roundtrip(true, "\xEF\xB7\xA3"); - roundtrip(true, "\xEF\xB7\xA4"); - roundtrip(true, "\xEF\xB7\xA5"); - roundtrip(true, "\xEF\xB7\xA6"); - roundtrip(true, "\xEF\xB7\xA7"); - roundtrip(true, "\xEF\xB7\xA8"); - roundtrip(true, "\xEF\xB7\xA9"); - roundtrip(true, "\xEF\xB7\xAA"); - roundtrip(true, "\xEF\xB7\xAB"); - roundtrip(true, "\xEF\xB7\xAC"); - roundtrip(true, "\xEF\xB7\xAD"); - roundtrip(true, "\xEF\xB7\xAE"); - roundtrip(true, "\xEF\xB7\xAF"); - - // 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) - roundtrip(true, "\xF0\x9F\xBF\xBF"); - roundtrip(true, "\xF0\xAF\xBF\xBF"); - roundtrip(true, "\xF0\xBF\xBF\xBF"); - roundtrip(true, "\xF1\x8F\xBF\xBF"); - roundtrip(true, "\xF1\x9F\xBF\xBF"); - roundtrip(true, "\xF1\xAF\xBF\xBF"); - roundtrip(true, "\xF1\xBF\xBF\xBF"); - roundtrip(true, "\xF2\x8F\xBF\xBF"); - roundtrip(true, "\xF2\x9F\xBF\xBF"); - roundtrip(true, "\xF2\xAF\xBF\xBF"); - } - } -} diff --git a/tests/src/unit-unicode2.cpp b/tests/src/unit-unicode2.cpp deleted file mode 100644 index a9649b4de..000000000 --- a/tests/src/unit-unicode2.cpp +++ /dev/null @@ -1,612 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.12.0 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann -// SPDX-License-Identifier: MIT - -#include "doctest_compatibility.h" - -// for some reason including this after the json header leads to linker errors with VS 2017... -#include - -#include -using nlohmann::json; - -#include -#include -#include -#include -#include "make_test_data_available.hpp" -#include "test_utils.hpp" - -// this test suite uses static variables with non-trivial destructors -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") - -namespace -{ -extern size_t calls; -size_t calls = 0; - -void check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - static std::string json_string; - json_string.clear(); - - CAPTURE(byte1) - CAPTURE(byte2) - CAPTURE(byte3) - CAPTURE(byte4) - - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - json_string += std::string(1, static_cast(byte4)); - } - - CAPTURE(json_string) - - // store the string in a JSON value - static json j; - static json j2; - j = json_string; - j2 = "abc" + json_string + "xyz"; - - static std::string s_ignored; - static std::string s_ignored2; - static std::string s_ignored_ascii; - static std::string s_ignored2_ascii; - static std::string s_replaced; - static std::string s_replaced2; - static std::string s_replaced_ascii; - static std::string s_replaced2_ascii; - - // dumping with ignore/replace must not throw in any case - s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore); - s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore); - s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace); - s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace); - - if (success_expected) - { - static std::string s_strict; - // strict mode must not throw if success is expected - s_strict = j.dump(); - // all dumps should agree on the string - CHECK(s_strict == s_ignored); - CHECK(s_strict == s_replaced); - } - else - { - // strict mode must throw if success is not expected - // dump() is nodiscard; the exception is thrown by dump() itself before it would return - CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); - // ignore and replace must create different dumps - CHECK(s_ignored != s_replaced); - - // check that replace string contains a replacement character - CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos); - } - - // check that prefix and suffix are preserved - CHECK(s_ignored2.substr(1, 3) == "abc"); - CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz"); - CHECK(s_ignored2_ascii.substr(1, 3) == "abc"); - CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz"); - CHECK(s_replaced2.substr(1, 3) == "abc"); - CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz"); - CHECK(s_replaced2_ascii.substr(1, 3) == "abc"); - CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz"); -} - -void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -// create and check a JSON string with up to four UTF-8 bytes -void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - if (++calls % 100000 == 0) - { - std::cout << calls << " of 455355 UTF-8 strings checked" << std::endl; // NOLINT(performance-avoid-endl) - } - - static std::string json_string; - json_string = "\""; - - CAPTURE(byte1) - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - CAPTURE(byte2) - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - CAPTURE(byte3) - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - CAPTURE(byte4) - json_string += std::string(1, static_cast(byte4)); - } - - json_string += "\""; - - CAPTURE(json_string) - - json _; - if (success_expected) - { - CHECK_NOTHROW(_ = json::parse(json_string)); - } - else - { - CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&); - } -} -} // namespace - -TEST_CASE("Unicode (2/5)" * doctest::skip()) -{ - SECTION("RFC 3629") - { - /* - RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as - follows: - - A UTF-8 string is a sequence of octets representing a sequence of UCS - characters. An octet sequence is valid UTF-8 only if it matches the - following syntax, which is derived from the rules for encoding UTF-8 - and is expressed in the ABNF of [RFC2234]. - - UTF8-octets = *( UTF8-char ) - UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 - UTF8-1 = %x00-7F - UTF8-2 = %xC2-DF UTF8-tail - UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - %xF4 %x80-8F 2( UTF8-tail ) - UTF8-tail = %x80-BF - */ - - SECTION("ill-formed first byte") - { - for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - - for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("UTF8-1 (x00-x7F)") - { - SECTION("well-formed") - { - for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1) - { - // unescaped control characters are parse errors in JSON - if (0x00 <= byte1 && byte1 <= 0x1F) - { - check_utf8string(false, byte1); - continue; - } - - // a single quote is a parse error in JSON - if (byte1 == 0x22) - { - check_utf8string(false, byte1); - continue; - } - - // a single backslash is a parse error in JSON - if (byte1 == 0x5C) - { - check_utf8string(false, byte1); - continue; - } - - // all other characters are OK - check_utf8string(true, byte1); - check_utf8dump(true, byte1); - } - } - } - - SECTION("UTF8-2 (xC2-xDF UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - check_utf8string(true, byte1, byte2); - check_utf8dump(true, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 && byte2 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - } - - SECTION("UTF8-3 (xE0 xA0-BF UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(true, byte1, byte2, byte3); - check_utf8dump(true, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0xA0 <= byte2 && byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1) - { - for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - } - - SECTION("UTF8-3 (xE1-xEC UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(true, byte1, byte2, byte3); - check_utf8dump(true, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 && byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - } - - SECTION("UTF8-3 (xED x80-9F UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(true, byte1, byte2, byte3); - check_utf8dump(true, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 && byte2 <= 0x9F) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xED; byte1 <= 0xED; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - } - - SECTION("UTF8-3 (xEE-xEF UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(true, byte1, byte2, byte3); - check_utf8dump(true, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 && byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - } - } -} - -DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-unicode3.cpp b/tests/src/unit-unicode3.cpp deleted file mode 100644 index 12c12eea4..000000000 --- a/tests/src/unit-unicode3.cpp +++ /dev/null @@ -1,326 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.12.0 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann -// SPDX-License-Identifier: MIT - -#include "doctest_compatibility.h" - -// for some reason including this after the json header leads to linker errors with VS 2017... -#include - -#include -using nlohmann::json; - -#include -#include -#include -#include -#include "make_test_data_available.hpp" -#include "test_utils.hpp" - -// this test suite uses static variables with non-trivial destructors -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") - -namespace -{ -extern size_t calls; -size_t calls = 0; - -void check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - static std::string json_string; - json_string.clear(); - - CAPTURE(byte1) - CAPTURE(byte2) - CAPTURE(byte3) - CAPTURE(byte4) - - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - json_string += std::string(1, static_cast(byte4)); - } - - CAPTURE(json_string) - - // store the string in a JSON value - static json j; - static json j2; - j = json_string; - j2 = "abc" + json_string + "xyz"; - - static std::string s_ignored; - static std::string s_ignored2; - static std::string s_ignored_ascii; - static std::string s_ignored2_ascii; - static std::string s_replaced; - static std::string s_replaced2; - static std::string s_replaced_ascii; - static std::string s_replaced2_ascii; - - // dumping with ignore/replace must not throw in any case - s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore); - s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore); - s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace); - s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace); - - if (success_expected) - { - static std::string s_strict; - // strict mode must not throw if success is expected - s_strict = j.dump(); - // all dumps should agree on the string - CHECK(s_strict == s_ignored); - CHECK(s_strict == s_replaced); - } - else - { - // strict mode must throw if success is not expected - // dump() is nodiscard; the exception is thrown by dump() itself before it would return - CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); - // ignore and replace must create different dumps - CHECK(s_ignored != s_replaced); - - // check that replace string contains a replacement character - CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos); - } - - // check that prefix and suffix are preserved - CHECK(s_ignored2.substr(1, 3) == "abc"); - CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz"); - CHECK(s_ignored2_ascii.substr(1, 3) == "abc"); - CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz"); - CHECK(s_replaced2.substr(1, 3) == "abc"); - CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz"); - CHECK(s_replaced2_ascii.substr(1, 3) == "abc"); - CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz"); -} - -void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -// create and check a JSON string with up to four UTF-8 bytes -void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - if (++calls % 100000 == 0) - { - std::cout << calls << " of 1641521 UTF-8 strings checked" << std::endl; // NOLINT(performance-avoid-endl) - } - - static std::string json_string; - json_string = "\""; - - CAPTURE(byte1) - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - CAPTURE(byte2) - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - CAPTURE(byte3) - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - CAPTURE(byte4) - json_string += std::string(1, static_cast(byte4)); - } - - json_string += "\""; - - CAPTURE(json_string) - - json _; - if (success_expected) - { - CHECK_NOTHROW(_ = json::parse(json_string)); - } - else - { - CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&); - } -} -} // namespace - -TEST_CASE("Unicode (3/5)" * doctest::skip()) -{ - SECTION("RFC 3629") - { - /* - RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as - follows: - - A UTF-8 string is a sequence of octets representing a sequence of UCS - characters. An octet sequence is valid UTF-8 only if it matches the - following syntax, which is derived from the rules for encoding UTF-8 - and is expressed in the ABNF of [RFC2234]. - - UTF8-octets = *( UTF8-char ) - UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 - UTF8-1 = %x00-7F - UTF8-2 = %xC2-DF UTF8-tail - UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - %xF4 %x80-8F 2( UTF8-tail ) - UTF8-tail = %x80-BF - */ - - SECTION("UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(true, byte1, byte2, byte3, byte4); - check_utf8dump(true, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing fourth byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x90 <= byte2 && byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong fourth byte") - { - for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1) - { - for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) - { - // skip correct fourth byte - if (0x80 <= byte4 && byte4 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - } - } -} - -DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-unicode4.cpp b/tests/src/unit-unicode4.cpp deleted file mode 100644 index 43cf7095e..000000000 --- a/tests/src/unit-unicode4.cpp +++ /dev/null @@ -1,326 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.12.0 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann -// SPDX-License-Identifier: MIT - -#include "doctest_compatibility.h" - -// for some reason including this after the json header leads to linker errors with VS 2017... -#include - -#include -using nlohmann::json; - -#include -#include -#include -#include -#include "make_test_data_available.hpp" -#include "test_utils.hpp" - -// this test suite uses static variables with non-trivial destructors -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") - -namespace -{ -extern size_t calls; -size_t calls = 0; - -void check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - static std::string json_string; - json_string.clear(); - - CAPTURE(byte1) - CAPTURE(byte2) - CAPTURE(byte3) - CAPTURE(byte4) - - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - json_string += std::string(1, static_cast(byte4)); - } - - CAPTURE(json_string) - - // store the string in a JSON value - static json j; - static json j2; - j = json_string; - j2 = "abc" + json_string + "xyz"; - - static std::string s_ignored; - static std::string s_ignored2; - static std::string s_ignored_ascii; - static std::string s_ignored2_ascii; - static std::string s_replaced; - static std::string s_replaced2; - static std::string s_replaced_ascii; - static std::string s_replaced2_ascii; - - // dumping with ignore/replace must not throw in any case - s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore); - s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore); - s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace); - s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace); - - if (success_expected) - { - static std::string s_strict; - // strict mode must not throw if success is expected - s_strict = j.dump(); - // all dumps should agree on the string - CHECK(s_strict == s_ignored); - CHECK(s_strict == s_replaced); - } - else - { - // strict mode must throw if success is not expected - // dump() is nodiscard; the exception is thrown by dump() itself before it would return - CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); - // ignore and replace must create different dumps - CHECK(s_ignored != s_replaced); - - // check that replace string contains a replacement character - CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos); - } - - // check that prefix and suffix are preserved - CHECK(s_ignored2.substr(1, 3) == "abc"); - CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz"); - CHECK(s_ignored2_ascii.substr(1, 3) == "abc"); - CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz"); - CHECK(s_replaced2.substr(1, 3) == "abc"); - CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz"); - CHECK(s_replaced2_ascii.substr(1, 3) == "abc"); - CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz"); -} - -void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -// create and check a JSON string with up to four UTF-8 bytes -void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - if (++calls % 100000 == 0) - { - std::cout << calls << " of 5517507 UTF-8 strings checked" << std::endl; // NOLINT(performance-avoid-endl) - } - - static std::string json_string; - json_string = "\""; - - CAPTURE(byte1) - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - CAPTURE(byte2) - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - CAPTURE(byte3) - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - CAPTURE(byte4) - json_string += std::string(1, static_cast(byte4)); - } - - json_string += "\""; - - CAPTURE(json_string) - - json _; - if (success_expected) - { - CHECK_NOTHROW(_ = json::parse(json_string)); - } - else - { - CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&); - } -} -} // namespace - -TEST_CASE("Unicode (4/5)" * doctest::skip()) -{ - SECTION("RFC 3629") - { - /* - RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as - follows: - - A UTF-8 string is a sequence of octets representing a sequence of UCS - characters. An octet sequence is valid UTF-8 only if it matches the - following syntax, which is derived from the rules for encoding UTF-8 - and is expressed in the ABNF of [RFC2234]. - - UTF8-octets = *( UTF8-char ) - UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 - UTF8-1 = %x00-7F - UTF8-2 = %xC2-DF UTF8-tail - UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - %xF4 %x80-8F 2( UTF8-tail ) - UTF8-tail = %x80-BF - */ - - SECTION("UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(true, byte1, byte2, byte3, byte4); - check_utf8dump(true, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing fourth byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 && byte2 <= 0xBF) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong fourth byte") - { - for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) - { - // skip correct fourth byte - if (0x80 <= byte4 && byte4 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - } - } -} - -DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tests/src/unit-unicode5.cpp b/tests/src/unit-unicode5.cpp deleted file mode 100644 index bc0312820..000000000 --- a/tests/src/unit-unicode5.cpp +++ /dev/null @@ -1,326 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ (supporting code) -// | | |__ | | | | | | version 3.12.0 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann -// SPDX-License-Identifier: MIT - -#include "doctest_compatibility.h" - -// for some reason including this after the json header leads to linker errors with VS 2017... -#include - -#include -using nlohmann::json; - -#include -#include -#include -#include -#include "make_test_data_available.hpp" -#include "test_utils.hpp" - -// this test suite uses static variables with non-trivial destructors -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") - -namespace -{ -extern size_t calls; -size_t calls = 0; - -void check_utf8dump(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - static std::string json_string; - json_string.clear(); - - CAPTURE(byte1) - CAPTURE(byte2) - CAPTURE(byte3) - CAPTURE(byte4) - - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - json_string += std::string(1, static_cast(byte4)); - } - - CAPTURE(json_string) - - // store the string in a JSON value - static json j; - static json j2; - j = json_string; - j2 = "abc" + json_string + "xyz"; - - static std::string s_ignored; - static std::string s_ignored2; - static std::string s_ignored_ascii; - static std::string s_ignored2_ascii; - static std::string s_replaced; - static std::string s_replaced2; - static std::string s_replaced_ascii; - static std::string s_replaced2_ascii; - - // dumping with ignore/replace must not throw in any case - s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore); - s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore); - s_ignored2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::ignore); - s_replaced = j.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace); - s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace); - s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace); - - if (success_expected) - { - static std::string s_strict; - // strict mode must not throw if success is expected - s_strict = j.dump(); - // all dumps should agree on the string - CHECK(s_strict == s_ignored); - CHECK(s_strict == s_replaced); - } - else - { - // strict mode must throw if success is not expected - // dump() is nodiscard; the exception is thrown by dump() itself before it would return - CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&); - // ignore and replace must create different dumps - CHECK(s_ignored != s_replaced); - - // check that replace string contains a replacement character - CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos); - } - - // check that prefix and suffix are preserved - CHECK(s_ignored2.substr(1, 3) == "abc"); - CHECK(s_ignored2.substr(s_ignored2.size() - 4, 3) == "xyz"); - CHECK(s_ignored2_ascii.substr(1, 3) == "abc"); - CHECK(s_ignored2_ascii.substr(s_ignored2_ascii.size() - 4, 3) == "xyz"); - CHECK(s_replaced2.substr(1, 3) == "abc"); - CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz"); - CHECK(s_replaced2_ascii.substr(1, 3) == "abc"); - CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz"); -} - -void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4); - -// create and check a JSON string with up to four UTF-8 bytes -void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1) -{ - if (++calls % 100000 == 0) - { - std::cout << calls << " of 1246225 UTF-8 strings checked" << std::endl; // NOLINT(performance-avoid-endl) - } - - static std::string json_string; - json_string = "\""; - - CAPTURE(byte1) - json_string += std::string(1, static_cast(byte1)); - - if (byte2 != -1) - { - CAPTURE(byte2) - json_string += std::string(1, static_cast(byte2)); - } - - if (byte3 != -1) - { - CAPTURE(byte3) - json_string += std::string(1, static_cast(byte3)); - } - - if (byte4 != -1) - { - CAPTURE(byte4) - json_string += std::string(1, static_cast(byte4)); - } - - json_string += "\""; - - CAPTURE(json_string) - - json _; - if (success_expected) - { - CHECK_NOTHROW(_ = json::parse(json_string)); - } - else - { - CHECK_THROWS_AS(_ = json::parse(json_string), json::parse_error&); - } -} -} // namespace - -TEST_CASE("Unicode (5/5)" * doctest::skip()) -{ - SECTION("RFC 3629") - { - /* - RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as - follows: - - A UTF-8 string is a sequence of octets representing a sequence of UCS - characters. An octet sequence is valid UTF-8 only if it matches the - following syntax, which is derived from the rules for encoding UTF-8 - and is expressed in the ABNF of [RFC2234]. - - UTF8-octets = *( UTF8-char ) - UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 - UTF8-1 = %x00-7F - UTF8-2 = %xC2-DF UTF8-tail - UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - %xF4 %x80-8F 2( UTF8-tail ) - UTF8-tail = %x80-BF - */ - - SECTION("UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)") - { - SECTION("well-formed") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(true, byte1, byte2, byte3, byte4); - check_utf8dump(true, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: missing second byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - check_utf8string(false, byte1); - check_utf8dump(false, byte1); - } - } - - SECTION("ill-formed: missing third byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) - { - check_utf8string(false, byte1, byte2); - check_utf8dump(false, byte1, byte2); - } - } - } - - SECTION("ill-formed: missing fourth byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - check_utf8string(false, byte1, byte2, byte3); - check_utf8dump(false, byte1, byte2, byte3); - } - } - } - } - - SECTION("ill-formed: wrong second byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) - { - // skip correct second byte - if (0x80 <= byte2 && byte2 <= 0x8F) - { - continue; - } - - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong third byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) - { - for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) - { - // skip correct third byte - if (0x80 <= byte3 && byte3 <= 0xBF) - { - continue; - } - - for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4) - { - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - - SECTION("ill-formed: wrong fourth byte") - { - for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1) - { - for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2) - { - for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3) - { - for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) - { - // skip correct fourth byte - if (0x80 <= byte4 && byte4 <= 0xBF) - { - continue; - } - - check_utf8string(false, byte1, byte2, byte3, byte4); - check_utf8dump(false, byte1, byte2, byte3, byte4); - } - } - } - } - } - } - } -} - -DOCTEST_CLANG_SUPPRESS_WARNING_POP diff --git a/tools/generate_natvis/nlohmann_json.natvis.j2 b/tools/generate_natvis/nlohmann_json.natvis.j2 index c3eafa54b..bc9e56fd1 100644 --- a/tools/generate_natvis/nlohmann_json.natvis.j2 +++ b/tools/generate_natvis/nlohmann_json.natvis.j2 @@ -36,5 +36,31 @@ + +{% for default_base in ['json_default_base', 'detail::json_default_base'] %} + + null + {*(m_data.m_value.object)} + {*(m_data.m_value.array)} + {*(m_data.m_value.string)} + {m_data.m_value.boolean} + {m_data.m_value.number_integer} + {m_data.m_value.number_unsigned} + {m_data.m_value.number_float} + discarded + + + *(m_data.m_value.object),view(simple) + + + *(m_data.m_value.array),view(simple) + + + + +{% endfor %} {% endfor %}