diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..5b9e3fd5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,84 @@ +#AccessModifierOffset: 2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +#AlignConsecutiveBitFields: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: false +AlignEscapedNewlines: Right +#AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +#AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +#BitFieldColonSpacing: Both +BreakBeforeBraces: Custom # or Allman +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + #BeforeLambdaBody: false + #BeforeWhile: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakStringLiterals: false +ColumnLimit: 0 +CompactNamespaces: false +ConstructorInitializerIndentWidth: 2 +Cpp11BracedListStyle: true +PointerAlignment: Left +FixNamespaceComments: true +IncludeBlocks: Preserve +#IndentCaseBlocks: false +IndentCaseLabels: true +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ReflowComments: false +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: c++11 +TabWidth: 4 +UseTab: Never diff --git a/.clang-tidy b/.clang-tidy index feee8194..046d84f8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,23 +1,20 @@ -Checks: '-*, - bugprone-*, - cert-*, - clang-analyzer-*, - google-*, - -google-runtime-references, +Checks: '*, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-macro-usage, + -fuchsia-default-arguments-calls, + -fuchsia-default-arguments-declarations, + -fuchsia-overloaded-operator, -google-explicit-constructor, - hicpp-*, + -google-runtime-references, + -hicpp-avoid-goto, + -hicpp-explicit-conversions, -hicpp-no-array-decay, -hicpp-uppercase-literal-suffix, - -hicpp-explicit-conversions, - misc-*, - -misc-non-private-member-variables-in-classes, - llvm-*, -llvm-header-guard, - modernize-*, + -llvm-include-order, + -misc-non-private-member-variables-in-classes, -modernize-use-trailing-return-type, - performance-*, - portability-*, - readability-*, -readability-magic-numbers, -readability-uppercase-literal-suffix' diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 3485a689..a2df8dca 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -47,7 +47,7 @@ assignees: '' -- [ ] latest release version 3.7.3 +- [ ] latest release version 3.9.0 - [ ] other release - please state the version: ___ - [ ] the `develop` branch diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index f7effbaf..00000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: 'kind: enhancement/improvement' -assignees: '' - ---- - -#### Which feature do you want to see in the library? - - - -#### How would the feature be usable for other users? - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..0e966338 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/nlohmann/json/discussions + about: Ask questions and discuss with other community members diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 3f522cde..00000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: Question -about: Ask a question regarding the library. -title: '' -labels: 'kind: question' -assignees: '' - ---- - - - -#### What do you want to achieve? - - - -#### What have you tried? - - - - - -#### Can you provide a small code example? - - - -#### Which compiler and operating system are you using? - - - - -- Compiler: ___ -- Operating system: ___ - -#### Which version of the library did you use? - - - -- [ ] latest release version 3.7.3 -- [ ] other release - please state the version: ___ -- [ ] the `develop` branch diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..5ee44a04 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,54 @@ +name: "Code scanning - action" + +on: + push: + branches: [develop, ] + pull_request: + # The branches below must be a subset of the branches above + branches: [develop] + schedule: + - cron: '0 19 * * 1' + +jobs: + CodeQL-Build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 476b21df..5846cf75 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -3,8 +3,7 @@ name: Windows on: [push, pull_request] jobs: - build: - + msvc2019: runs-on: windows-latest steps: @@ -15,3 +14,55 @@ jobs: run: cmake --build build --parallel 10 - name: test run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure + + clang9: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + - name: install Clang + run: curl -fsSL -o LLVM9.exe https://releases.llvm.org/9.0.0/LLVM-9.0.0-win64.exe ; 7z x LLVM9.exe -y -o"C:/Program Files/LLVM" + - name: cmake + run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On + - 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 + + clang10: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + - name: install Clang + run: curl -fsSL -o LLVM10.exe https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe ; 7z x LLVM10.exe -y -o"C:/Program Files/LLVM" + - name: cmake + run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On + - 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 + + clang-cl-10-x64: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + - name: cmake + run: cmake -S . -B build -G "Visual Studio 16 2019" -A x64 -T ClangCL -DJSON_BuildTests=On + - 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 + + clang-cl-10-x86: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + - name: cmake + run: cmake -S . -B build -G "Visual Studio 16 2019" -A Win32 -T ClangCL -DJSON_BuildTests=On + - 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 diff --git a/.gitignore b/.gitignore index bec7f598..7e5a881e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ benchmarks/files/numbers/*.json .wsjcpp/* .idea -cmake-build-debug +/cmake-build-* test/test-* /.vs @@ -32,3 +32,4 @@ doc/mkdocs/docs/images doc/mkdocs/docs/examples doc/mkdocs/site doc/mkdocs/docs/__pycache__/ +doc/xml diff --git a/.travis.yml b/.travis.yml index 0fef3f44..bf749c1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,17 +10,6 @@ sudo: required group: edge -################### -# global settings # -################### - -env: - global: - # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created - # via the "travis encrypt" command using the project repo's public key - - secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA=" - - ################ # build matrix # ################ @@ -129,6 +118,9 @@ matrix: env: - SPECIAL=coverity - COMPILER=clang++-3.6 + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA=" # OSX / Clang @@ -150,6 +142,14 @@ matrix: - os: osx osx_image: xcode11.2 + - os: osx + osx_image: xcode12 + + - os: osx + osx_image: xcode12 + env: + - IMPLICIT_CONVERSIONS=OFF + # Linux / GCC - os: linux @@ -208,6 +208,16 @@ matrix: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-9', 'ninja-build'] + - os: linux + compiler: gcc + env: + - COMPILER=g++-9 + - IMPLICIT_CONVERSIONS=OFF + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-9', 'ninja-build'] + - os: linux compiler: gcc env: @@ -320,10 +330,12 @@ script: - if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi # by default, use the single-header version - if [[ "${MULTIPLE_HEADERS}" == "" ]]; then export MULTIPLE_HEADERS=OFF; fi + # by default, use implicit conversions + - if [[ "${IMPLICIT_CONVERSIONS}" == "" ]]; then export IMPLICIT_CONVERSIONS=ON; fi # compile and execute unit tests - mkdir -p build && cd build - - cmake .. ${CMAKE_OPTIONS} -DJSON_MultipleHeaders=${MULTIPLE_HEADERS} -DJSON_BuildTests=On -GNinja && cmake --build . --config Release + - cmake .. ${CMAKE_OPTIONS} -DJSON_MultipleHeaders=${MULTIPLE_HEADERS} -DJSON_ImplicitConversions=${IMPLICIT_CONVERSIONS} -DJSON_BuildTests=On -GNinja && cmake --build . --config Release - ctest -C Release --timeout 2700 -V -j - cd .. diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f163041..d5d0ae34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.8.0 LANGUAGES CXX) +project(nlohmann_json VERSION 3.9.0 LANGUAGES CXX) ## ## INCLUDE @@ -15,9 +15,16 @@ include(ExternalProject) ## ## OPTIONS ## + +if (POLICY CMP0077) + # Allow CMake 3.13+ to override options when using FetchContent / add_subdirectory. + cmake_policy(SET CMP0077 NEW) +endif () + option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON) option(JSON_Install "Install CMake targets during install step." ON) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF) +option(JSON_ImplicitConversions "Enable implicit conversions." ON) ## ## CONFIGURATION @@ -42,6 +49,10 @@ else() message(STATUS "Using the single-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}") endif() +if (NOT JSON_ImplicitConversions) + message(STATUS "Implicit conversions are disabled") +endif() + ## ## TARGET ## create target and add include path @@ -54,6 +65,12 @@ else() target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11) endif() +target_compile_definitions( + ${NLOHMANN_JSON_TARGET_NAME} + INTERFACE + JSON_USE_IMPLICIT_CONVERSIONS=$ +) + target_include_directories( ${NLOHMANN_JSON_TARGET_NAME} INTERFACE @@ -73,6 +90,12 @@ if (MSVC) ) endif() +# Install a pkg-config file, so other tools can find this. +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" +) + ## ## TESTS ## create and configure the unit test target @@ -133,4 +156,8 @@ endif() NAMESPACE ${PROJECT_NAME}:: DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} ) + install( + FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION lib/pkgconfig + ) endif() diff --git a/ChangeLog.md b/ChangeLog.md index 63ff3fb4..7a762275 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,13 +1,129 @@ # Changelog All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [v3.9.0](https://github.com/nlohmann/json/releases/tag/v3.9.0) (2020-07-27) + +[Full Changelog](https://github.com/nlohmann/json/compare/v3.8.0...v3.9.0) + +- Unknown Type Name clang error when using NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE [\#2313](https://github.com/nlohmann/json/issues/2313) +- Clang 10.0 / GCC 10.1 warnings on disabled exceptions [\#2304](https://github.com/nlohmann/json/issues/2304) +- Application stalls indefinitely with message byte size 10 [\#2293](https://github.com/nlohmann/json/issues/2293) +- linker error [\#2292](https://github.com/nlohmann/json/issues/2292) +- Add support for high-precision numbers in UBJSON encoding [\#2286](https://github.com/nlohmann/json/issues/2286) +- NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE fails if the length of the argument is 10 [\#2280](https://github.com/nlohmann/json/issues/2280) +- Custom types : MACRO expansion bug [\#2267](https://github.com/nlohmann/json/issues/2267) +- to/from\_json Failing To Convert String [\#2238](https://github.com/nlohmann/json/issues/2238) +- clang 9.0 report warning: unused type alias 'size\_type' \[-Wunused-local-typedef\] [\#2221](https://github.com/nlohmann/json/issues/2221) +- Enormous array created when working with map\ [\#2220](https://github.com/nlohmann/json/issues/2220) +- Can I disable sorting of json values [\#2219](https://github.com/nlohmann/json/issues/2219) +- Getting Qt types to work [\#2217](https://github.com/nlohmann/json/issues/2217) +- Convert to Qt QVariant [\#2216](https://github.com/nlohmann/json/issues/2216) +- How to custom serialize same data type of vector? [\#2215](https://github.com/nlohmann/json/issues/2215) +- json constructor does not support std::optional [\#2214](https://github.com/nlohmann/json/issues/2214) +- Failing to Parse Valid JSON [\#2209](https://github.com/nlohmann/json/issues/2209) +- \(De-\)Serialization of std::variant with namespaces [\#2208](https://github.com/nlohmann/json/issues/2208) +- Addint support for complex type [\#2207](https://github.com/nlohmann/json/issues/2207) +- array\_index possible out of range [\#2205](https://github.com/nlohmann/json/issues/2205) +- Object deserialized as array [\#2204](https://github.com/nlohmann/json/issues/2204) +- Sending to a function a reference to a sub-branch [\#2200](https://github.com/nlohmann/json/issues/2200) +- How to Serialize derived class to JSON object? [\#2199](https://github.com/nlohmann/json/issues/2199) +- JSON incorrectly serialized [\#2198](https://github.com/nlohmann/json/issues/2198) +- Exception Unhandled out\_of\_range error [\#2197](https://github.com/nlohmann/json/issues/2197) +- msgpack serialisation : float is treated as 64bit float, not 32bit float. [\#2196](https://github.com/nlohmann/json/issues/2196) +- Is it possible to use compile-time type guarantees for JSON structures? [\#2195](https://github.com/nlohmann/json/issues/2195) +- Question : performance against python dict [\#2194](https://github.com/nlohmann/json/issues/2194) +- vs2017 compile error [\#2192](https://github.com/nlohmann/json/issues/2192) +- Check if a key exists [\#2191](https://github.com/nlohmann/json/issues/2191) +- Failed to run tests due to missing test data on builders without Internet access [\#2190](https://github.com/nlohmann/json/issues/2190) +- 3.8.0: unit-cbor.cpp test failures [\#2189](https://github.com/nlohmann/json/issues/2189) +- 'nlohmann/json.hpp' file not found [\#2188](https://github.com/nlohmann/json/issues/2188) +- How to send json data over the wire? [\#2185](https://github.com/nlohmann/json/issues/2185) +- Ubuntu 16 not supporting nlohmann/json? [\#2184](https://github.com/nlohmann/json/issues/2184) +- .get\ causing emdash errors [\#2180](https://github.com/nlohmann/json/issues/2180) +- Object properties should not be re-sorted alphabetically [\#2179](https://github.com/nlohmann/json/issues/2179) +- Custom type registration : instrusive API [\#2175](https://github.com/nlohmann/json/issues/2175) +- Many version of the function "void to\_json\(json& j, const MyStruct& struct\)" [\#2171](https://github.com/nlohmann/json/issues/2171) +- How should strings be escaped? [\#2155](https://github.com/nlohmann/json/issues/2155) +- Adding a value to an existing json puts it at the beginning instead of the end [\#2149](https://github.com/nlohmann/json/issues/2149) +- The header file is big, can we use what we need. [\#2134](https://github.com/nlohmann/json/issues/2134) +- Changing the default format for unordered\_map \(or other set\) [\#2132](https://github.com/nlohmann/json/issues/2132) +- Getting size of deserialized bson document [\#2131](https://github.com/nlohmann/json/issues/2131) +- implicit conversion failure [\#2128](https://github.com/nlohmann/json/issues/2128) +- Error thrown when parsing in a subclass [\#2124](https://github.com/nlohmann/json/issues/2124) +- explicit conversion to string not considered for std::map keys in GCC8 [\#2096](https://github.com/nlohmann/json/issues/2096) +- Add support for JSONC [\#2061](https://github.com/nlohmann/json/issues/2061) +- Library provides template arg for string\_type but assumes std::string in some places [\#2059](https://github.com/nlohmann/json/issues/2059) +- incremental parsing with sax\_parser [\#2030](https://github.com/nlohmann/json/issues/2030) +- Question about flatten and unflatten [\#1989](https://github.com/nlohmann/json/issues/1989) +- CBOR parser doesn't skip tags [\#1968](https://github.com/nlohmann/json/issues/1968) +- Compilation failure using Clang on Windows [\#1898](https://github.com/nlohmann/json/issues/1898) +- Fail to build when including json.hpp as a system include [\#1818](https://github.com/nlohmann/json/issues/1818) +- Parsing string into json doesn't preserve the order correctly. [\#1817](https://github.com/nlohmann/json/issues/1817) +- \[C++17\] Allow std::optional to convert to nlohmann::json [\#1749](https://github.com/nlohmann/json/issues/1749) +- How can I save json object in file in order? [\#1717](https://github.com/nlohmann/json/issues/1717) +- Support for Comments [\#1513](https://github.com/nlohmann/json/issues/1513) +- clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119) +- dump\(\) without alphabetical order [\#1106](https://github.com/nlohmann/json/issues/1106) +- operator T\(\) considered harmful [\#958](https://github.com/nlohmann/json/issues/958) +- Order of the elements in JSON object [\#952](https://github.com/nlohmann/json/issues/952) +- How to prevent alphabetical sorting of data? [\#727](https://github.com/nlohmann/json/issues/727) +- Why is an object ordering values by Alphabetical Order? [\#660](https://github.com/nlohmann/json/issues/660) +- Feature request: Comments [\#597](https://github.com/nlohmann/json/issues/597) +- Head Elements Sorting [\#543](https://github.com/nlohmann/json/issues/543) +- Automatic ordered JSON [\#424](https://github.com/nlohmann/json/issues/424) +- Support for comments. [\#376](https://github.com/nlohmann/json/issues/376) +- Optional comment support. [\#363](https://github.com/nlohmann/json/issues/363) +- Strip comments / Minify [\#294](https://github.com/nlohmann/json/issues/294) +- maintaining order of keys during iteration [\#106](https://github.com/nlohmann/json/issues/106) + +- Update documentation [\#2312](https://github.com/nlohmann/json/pull/2312) ([nlohmann](https://github.com/nlohmann)) +- Fix bug in CBOR tag handling [\#2308](https://github.com/nlohmann/json/pull/2308) ([nlohmann](https://github.com/nlohmann)) +- added inline to NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE macro [\#2306](https://github.com/nlohmann/json/pull/2306) ([jwittbrodt](https://github.com/jwittbrodt)) +- fixes unused variable 'ex' for \#2304 [\#2305](https://github.com/nlohmann/json/pull/2305) ([AODQ](https://github.com/AODQ)) +- Cleanup [\#2303](https://github.com/nlohmann/json/pull/2303) ([nlohmann](https://github.com/nlohmann)) +- Add test with multiple translation units [\#2301](https://github.com/nlohmann/json/pull/2301) ([nlohmann](https://github.com/nlohmann)) +- Merge GitHub actions [\#2300](https://github.com/nlohmann/json/pull/2300) ([nlohmann](https://github.com/nlohmann)) +- Fix unused parameter [\#2299](https://github.com/nlohmann/json/pull/2299) ([nlohmann](https://github.com/nlohmann)) +- Add support for high-precision numbers in UBJSON encoding [\#2297](https://github.com/nlohmann/json/pull/2297) ([nlohmann](https://github.com/nlohmann)) +- fix eof for get\_binary and get\_string [\#2294](https://github.com/nlohmann/json/pull/2294) ([jprochazk](https://github.com/jprochazk)) +- Serialisation macros: increase upper bound on number of member variables [\#2287](https://github.com/nlohmann/json/pull/2287) ([pfeatherstone](https://github.com/pfeatherstone)) +- add inline specifier for detail::combine [\#2285](https://github.com/nlohmann/json/pull/2285) ([T0b1-iOS](https://github.com/T0b1-iOS)) +- Add static assertion for missing binary function in SAX interface [\#2282](https://github.com/nlohmann/json/pull/2282) ([nlohmann](https://github.com/nlohmann)) +- Add test for target\_include\_directories [\#2279](https://github.com/nlohmann/json/pull/2279) ([nlohmann](https://github.com/nlohmann)) +- Clean up maintainer Makefiles and fix some linter warnings [\#2274](https://github.com/nlohmann/json/pull/2274) ([nlohmann](https://github.com/nlohmann)) +- Add option to ignore CBOR tags [\#2273](https://github.com/nlohmann/json/pull/2273) ([nlohmann](https://github.com/nlohmann)) +- Hash function without allocation [\#2269](https://github.com/nlohmann/json/pull/2269) ([nlohmann](https://github.com/nlohmann)) +- Add ClangCL for MSVC [\#2268](https://github.com/nlohmann/json/pull/2268) ([t-b](https://github.com/t-b)) +- Makefile: Always use SED variable [\#2264](https://github.com/nlohmann/json/pull/2264) ([t-b](https://github.com/t-b)) +- Add Xcode 12 CI [\#2262](https://github.com/nlohmann/json/pull/2262) ([nlohmann](https://github.com/nlohmann)) +- Make library work with Clang on Windows [\#2259](https://github.com/nlohmann/json/pull/2259) ([nlohmann](https://github.com/nlohmann)) +- Add ordered\_json specialization with ordered object keys [\#2258](https://github.com/nlohmann/json/pull/2258) ([nlohmann](https://github.com/nlohmann)) +- Add pkg-config file [\#2253](https://github.com/nlohmann/json/pull/2253) ([ericonr](https://github.com/ericonr)) +- Fix regression from \#2181 [\#2251](https://github.com/nlohmann/json/pull/2251) ([nlohmann](https://github.com/nlohmann)) +- Tag binary values in cbor if set [\#2244](https://github.com/nlohmann/json/pull/2244) ([matthewbauer](https://github.com/matthewbauer)) +- Make assert configurable via JSON\_ASSERT [\#2242](https://github.com/nlohmann/json/pull/2242) ([nlohmann](https://github.com/nlohmann)) +- Add specialization of get\_to [\#2233](https://github.com/nlohmann/json/pull/2233) ([nlohmann](https://github.com/nlohmann)) +- Refine documentation of error\_handler parameter [\#2232](https://github.com/nlohmann/json/pull/2232) ([nlohmann](https://github.com/nlohmann)) +- Simplify conversion from/to custom types [\#2225](https://github.com/nlohmann/json/pull/2225) ([nlohmann](https://github.com/nlohmann)) +- Remove unused typedefs [\#2224](https://github.com/nlohmann/json/pull/2224) ([nlohmann](https://github.com/nlohmann)) +- Enable CMake policy CMP0077 [\#2222](https://github.com/nlohmann/json/pull/2222) ([alexreinking](https://github.com/alexreinking)) +- Add option to ignore comments in parse/accept functions [\#2212](https://github.com/nlohmann/json/pull/2212) ([nlohmann](https://github.com/nlohmann)) +- Fix Clang-Tidy warnings [\#2211](https://github.com/nlohmann/json/pull/2211) ([nlohmann](https://github.com/nlohmann)) +- Simple ordered\_json that works on all supported compilers [\#2206](https://github.com/nlohmann/json/pull/2206) ([gatopeich](https://github.com/gatopeich)) +- Use unsigned indizies for array index in json pointer [\#2203](https://github.com/nlohmann/json/pull/2203) ([t-b](https://github.com/t-b)) +- Add option to not rely on Internet connectivity during test stage [\#2202](https://github.com/nlohmann/json/pull/2202) ([nlohmann](https://github.com/nlohmann)) +- Serialize floating-point numbers with 32 bit when possible \(MessagePack\) [\#2201](https://github.com/nlohmann/json/pull/2201) ([nlohmann](https://github.com/nlohmann)) +- Fix consistency in function `int\_to\_string\(\)` [\#2193](https://github.com/nlohmann/json/pull/2193) ([dota17](https://github.com/dota17)) +- Fix issue\#1275 [\#2181](https://github.com/nlohmann/json/pull/2181) ([dota17](https://github.com/dota17)) +- C++20 support by removing swap specialization [\#2176](https://github.com/nlohmann/json/pull/2176) ([gracicot](https://github.com/gracicot)) +- Feat/explicit conversion operator [\#1559](https://github.com/nlohmann/json/pull/1559) ([theodelrieu](https://github.com/theodelrieu)) + ## [v3.8.0](https://github.com/nlohmann/json/releases/tag/v3.8.0) (2020-06-14) [Full Changelog](https://github.com/nlohmann/json/compare/v3.7.3...v3.8.0) - sorry delete this issue, i'm stupid [\#2187](https://github.com/nlohmann/json/issues/2187) - Append to a std::nlohmann::json type [\#2186](https://github.com/nlohmann/json/issues/2186) -- Object properties should not be re-sorted alphabetically [\#2179](https://github.com/nlohmann/json/issues/2179) - Some troubles to compile the last revision [\#2177](https://github.com/nlohmann/json/issues/2177) - ​\#​ Top level CMakeLists.txt​ ​project​\(FOO\) @@ -34,7 +150,6 @@ All notable changes to this project will be documented in this file. This projec - test-cbor fails [\#2154](https://github.com/nlohmann/json/issues/2154) - Accessing array inside array syntax? [\#2151](https://github.com/nlohmann/json/issues/2151) - Best way to catch errors when querying json [\#2150](https://github.com/nlohmann/json/issues/2150) -- Adding a value to an existing json puts it at the beginning instead of the end [\#2149](https://github.com/nlohmann/json/issues/2149) - JSON Data Mapping Key-Value from other Key-Value [\#2148](https://github.com/nlohmann/json/issues/2148) - Conflicts with std \ compiling with GCC 10 [\#2146](https://github.com/nlohmann/json/issues/2146) - Incorrect CMake FetchContent example [\#2142](https://github.com/nlohmann/json/issues/2142) @@ -64,7 +179,6 @@ All notable changes to this project will be documented in this file. This projec - Can't ad an object in another objet [\#2101](https://github.com/nlohmann/json/issues/2101) - Implicit conversion causes "cannot use operator\[\] with a string argument with string" [\#2098](https://github.com/nlohmann/json/issues/2098) - C++20: char8\_t [\#2097](https://github.com/nlohmann/json/issues/2097) -- UTF8 [\#2095](https://github.com/nlohmann/json/issues/2095) - Compilation issues when included in project [\#2094](https://github.com/nlohmann/json/issues/2094) - string value with null character causes infinite loop [\#2093](https://github.com/nlohmann/json/issues/2093) - corrupted size vs. prev\_size \(aborted\) [\#2092](https://github.com/nlohmann/json/issues/2092) @@ -91,7 +205,6 @@ All notable changes to this project will be documented in this file. This projec - Bug: returning reference to local temporary object [\#2064](https://github.com/nlohmann/json/issues/2064) - Allow to use non strict parsing [\#2063](https://github.com/nlohmann/json/issues/2063) - Crashing on json::at [\#2062](https://github.com/nlohmann/json/issues/2062) -- Add support for JSONC [\#2061](https://github.com/nlohmann/json/issues/2061) - How to convert a const std::vector\ message to a json, to be able to parse it and extract information from it? Can you point to any examples? [\#2058](https://github.com/nlohmann/json/issues/2058) - Nice library [\#2057](https://github.com/nlohmann/json/issues/2057) - json.hpp:15372:22: error: expected unqualified-id if \(not std::isfinite\(x\)\): Started getting this bug after updating my XCode [\#2056](https://github.com/nlohmann/json/issues/2056) @@ -197,7 +310,6 @@ All notable changes to this project will be documented in this file. This projec - typo in a comment [\#1903](https://github.com/nlohmann/json/issues/1903) - Watch JSON variables in Debug [\#1902](https://github.com/nlohmann/json/issues/1902) - does Json sdk cares about dfc dfd utf8 issue? [\#1901](https://github.com/nlohmann/json/issues/1901) -- Compilation failure using Clang on Windows [\#1898](https://github.com/nlohmann/json/issues/1898) - Allow multiple line string value in JSON [\#1897](https://github.com/nlohmann/json/issues/1897) - Writing map to json file [\#1896](https://github.com/nlohmann/json/issues/1896) - Small documentation mistake [\#1895](https://github.com/nlohmann/json/issues/1895) @@ -253,7 +365,6 @@ All notable changes to this project will be documented in this file. This projec - Serialize big data in json [\#1828](https://github.com/nlohmann/json/issues/1828) - Backslash '\' in value causes exception [\#1827](https://github.com/nlohmann/json/issues/1827) - from\_json for non default constructible class with dependency injection [\#1819](https://github.com/nlohmann/json/issues/1819) -- Fail to build when including json.hpp as a system include [\#1818](https://github.com/nlohmann/json/issues/1818) - Semi-frequent timeouts in `test-unicode\_all` with 3.6.1 \(aarch64\) [\#1816](https://github.com/nlohmann/json/issues/1816) - input\_adapter not user extensible [\#1813](https://github.com/nlohmann/json/issues/1813) - crash at json::destroy on android [\#1812](https://github.com/nlohmann/json/issues/1812) @@ -322,7 +433,6 @@ All notable changes to this project will be documented in this file. This projec - Fix issue\#1719 [\#2044](https://github.com/nlohmann/json/pull/2044) ([dota17](https://github.com/dota17)) - Add missing testcase about NaN in unit-constructor1.cpp [\#2043](https://github.com/nlohmann/json/pull/2043) ([dota17](https://github.com/dota17)) - Templatize basic\_json constructor from json\_ref [\#2034](https://github.com/nlohmann/json/pull/2034) ([ArtemSarmini](https://github.com/ArtemSarmini)) -- Replace deprecated std::is\_pod [\#2033](https://github.com/nlohmann/json/pull/2033) ([nlohmann](https://github.com/nlohmann)) - fix \#1982:json\_pointer.contains\(\) exception is incorrectly raised [\#2019](https://github.com/nlohmann/json/pull/2019) ([dota17](https://github.com/dota17)) - catch exceptions for json\_pointer : ..../+99 [\#1990](https://github.com/nlohmann/json/pull/1990) ([dota17](https://github.com/dota17)) - fix warnings in serializer.hpp for VS2019 [\#1969](https://github.com/nlohmann/json/pull/1969) ([dota17](https://github.com/dota17)) @@ -369,7 +479,6 @@ All notable changes to this project will be documented in this file. This projec - json class should have a get\_or member function [\#1823](https://github.com/nlohmann/json/issues/1823) - NLOHMANN\_JSON\_SERIALIZE\_ENUM macro capture's json objects by value [\#1822](https://github.com/nlohmann/json/issues/1822) - Parse fails when number literals start with zero [\#1820](https://github.com/nlohmann/json/issues/1820) -- Parsing string into json doesn't preserve the order correctly. [\#1817](https://github.com/nlohmann/json/issues/1817) - Weird behaviour of `contains` with `json\_pointer` [\#1815](https://github.com/nlohmann/json/issues/1815) - strange behaviour with json\_pointer and .contains\(\) [\#1811](https://github.com/nlohmann/json/issues/1811) - Can \#1695 be re-opened? [\#1808](https://github.com/nlohmann/json/issues/1808) @@ -426,7 +535,6 @@ All notable changes to this project will be documented in this file. This projec - CMake not correctly finding the configuration package for 3.7.0 [\#1721](https://github.com/nlohmann/json/issues/1721) - name typo in the "spack package management" section of README.md [\#1720](https://github.com/nlohmann/json/issues/1720) - How to add json to another json? [\#1718](https://github.com/nlohmann/json/issues/1718) -- How can I save json object in file in order? [\#1717](https://github.com/nlohmann/json/issues/1717) - json::parse\(\) ubsan regression with v3.7.0 [\#1716](https://github.com/nlohmann/json/issues/1716) - What I am doing wrong?!? [\#1714](https://github.com/nlohmann/json/issues/1714) - Potential memory leak detected by Valgrind [\#1713](https://github.com/nlohmann/json/issues/1713) @@ -633,8 +741,6 @@ All notable changes to this project will be documented in this file. This projec - Added to\_string and added basic tests [\#1585](https://github.com/nlohmann/json/pull/1585) ([Macr0Nerd](https://github.com/Macr0Nerd)) - Regression tests for MSVC [\#1570](https://github.com/nlohmann/json/pull/1570) ([nickaein](https://github.com/nickaein)) - Fix/1511 [\#1555](https://github.com/nlohmann/json/pull/1555) ([theodelrieu](https://github.com/theodelrieu)) -- Remove C++17 extension warning from clang; \#1535 [\#1551](https://github.com/nlohmann/json/pull/1551) ([heavywatal](https://github.com/heavywatal)) -- moved from Catch to doctest for unit tests [\#1439](https://github.com/nlohmann/json/pull/1439) ([onqtam](https://github.com/onqtam)) ## [v3.6.1](https://github.com/nlohmann/json/releases/tag/v3.6.1) (2019-03-20) @@ -658,7 +764,6 @@ All notable changes to this project will be documented in this file. This projec - how to precision to four decimal for double when use to\_json [\#1519](https://github.com/nlohmann/json/issues/1519) - error parse [\#1518](https://github.com/nlohmann/json/issues/1518) - Compile error: template argument deduction/substitution failed [\#1515](https://github.com/nlohmann/json/issues/1515) -- Support for Comments [\#1513](https://github.com/nlohmann/json/issues/1513) - std::complex type [\#1510](https://github.com/nlohmann/json/issues/1510) - CBOR byte string support [\#1509](https://github.com/nlohmann/json/issues/1509) - Compilation error getting a std::pair\<\> on latest VS 2017 compiler [\#1506](https://github.com/nlohmann/json/issues/1506) @@ -738,6 +843,7 @@ All notable changes to this project will be documented in this file. This projec - Implicit type conversion error on MSVC [\#1333](https://github.com/nlohmann/json/issues/1333) - NuGet Package [\#1132](https://github.com/nlohmann/json/issues/1132) +- Remove C++17 extension warning from clang; \#1535 [\#1551](https://github.com/nlohmann/json/pull/1551) ([heavywatal](https://github.com/heavywatal)) - Change macros to numeric\_limits [\#1514](https://github.com/nlohmann/json/pull/1514) ([naszta](https://github.com/naszta)) - fix GCC 7.1.1 - 7.2.1 on CentOS [\#1496](https://github.com/nlohmann/json/pull/1496) ([lieff](https://github.com/lieff)) - Update Buckaroo instructions in README.md [\#1495](https://github.com/nlohmann/json/pull/1495) ([njlr](https://github.com/njlr)) @@ -753,6 +859,7 @@ All notable changes to this project will be documented in this file. This projec - remove extra semicolon from readme [\#1451](https://github.com/nlohmann/json/pull/1451) ([Afforix](https://github.com/Afforix)) - attempt to fix \#1445, flush buffer in serializer::dump\_escaped in UTF8\_REJECT case. [\#1446](https://github.com/nlohmann/json/pull/1446) ([scinart](https://github.com/scinart)) - Use C++11 features supported by CMake 3.1. [\#1441](https://github.com/nlohmann/json/pull/1441) ([iwanders](https://github.com/iwanders)) +- moved from Catch to doctest for unit tests [\#1439](https://github.com/nlohmann/json/pull/1439) ([onqtam](https://github.com/onqtam)) - :rotating\_light: fixed unused variable warning [\#1435](https://github.com/nlohmann/json/pull/1435) ([pboettch](https://github.com/pboettch)) - allow push\_back\(\) and pop\_back\(\) calls on json\_pointer [\#1434](https://github.com/nlohmann/json/pull/1434) ([pboettch](https://github.com/pboettch)) - Add instructions about using nlohmann/json with the conda package manager [\#1430](https://github.com/nlohmann/json/pull/1430) ([nicoddemus](https://github.com/nicoddemus)) @@ -824,7 +931,6 @@ All notable changes to this project will be documented in this file. This projec - Comparisons between large unsigned and negative signed integers [\#1295](https://github.com/nlohmann/json/issues/1295) - CMake alias to `nlohmann::json` [\#1291](https://github.com/nlohmann/json/issues/1291) - Release zips without tests [\#1285](https://github.com/nlohmann/json/issues/1285) -- Suggestion to improve value\(\) accessors with respect to move semantics [\#1275](https://github.com/nlohmann/json/issues/1275) - separate object\_t::key\_type from basic\_json::key\_type, and use an allocator which returns object\_t::key\_type [\#1274](https://github.com/nlohmann/json/issues/1274) - Is there a nice way to associate external values with json elements? [\#1256](https://github.com/nlohmann/json/issues/1256) - Delete by json\_pointer [\#1248](https://github.com/nlohmann/json/issues/1248) @@ -1023,7 +1129,6 @@ All notable changes to this project will be documented in this file. This projec - can't not parse "\\“ string [\#1123](https://github.com/nlohmann/json/issues/1123) - if json file contain Internationalization chars , get exception [\#1122](https://github.com/nlohmann/json/issues/1122) - How to use a json::iterator dereferenced value in code? [\#1120](https://github.com/nlohmann/json/issues/1120) -- clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119) - Disable implicit conversions from json to std::initializer\_list\ for any T [\#1118](https://github.com/nlohmann/json/issues/1118) - Implicit conversions to complex types can lead to surprising and confusing errors [\#1116](https://github.com/nlohmann/json/issues/1116) - How can I write from\_json for a complex datatype that is not default constructible? [\#1115](https://github.com/nlohmann/json/issues/1115) @@ -1035,7 +1140,6 @@ All notable changes to this project will be documented in this file. This projec - JSON representation for floating point values has too many digits [\#1109](https://github.com/nlohmann/json/issues/1109) - Not working for classes containing "\_declspec\(dllimport\)" in their declaration [\#1108](https://github.com/nlohmann/json/issues/1108) - Get keys from json object [\#1107](https://github.com/nlohmann/json/issues/1107) -- dump\(\) without alphabetical order [\#1106](https://github.com/nlohmann/json/issues/1106) - Cannot deserialize types using std::ratio [\#1105](https://github.com/nlohmann/json/issues/1105) - i want to learn json [\#1104](https://github.com/nlohmann/json/issues/1104) - Type checking during compile [\#1103](https://github.com/nlohmann/json/issues/1103) @@ -1182,6 +1286,7 @@ All notable changes to this project will be documented in this file. This projec - Allowing for user-defined string type in lexer/parser [\#1009](https://github.com/nlohmann/json/pull/1009) ([nlohmann](https://github.com/nlohmann)) - dump to alternative string type, as defined in basic\_json template [\#1006](https://github.com/nlohmann/json/pull/1006) ([agrianius](https://github.com/agrianius)) +- Fix memory leak during parser callback [\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann)) - fixed misprinted condition detected by PVS Studio. [\#992](https://github.com/nlohmann/json/pull/992) ([bogemic](https://github.com/bogemic)) - Fix/basic json conversion [\#986](https://github.com/nlohmann/json/pull/986) ([theodelrieu](https://github.com/theodelrieu)) - Make integration section concise [\#981](https://github.com/nlohmann/json/pull/981) ([wla80](https://github.com/wla80)) @@ -1205,7 +1310,6 @@ All notable changes to this project will be documented in this file. This projec - \[Request\] Macro generating from\_json\(\) and to\_json\(\) [\#895](https://github.com/nlohmann/json/issues/895) - basic\_json::value throws exception instead of returning default value [\#871](https://github.com/nlohmann/json/issues/871) -- Fix memory leak during parser callback [\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann)) - Fix constraints on from\_json\(CompatibleArrayType\) [\#969](https://github.com/nlohmann/json/pull/969) ([theodelrieu](https://github.com/theodelrieu)) - Make coveralls watch the include folder [\#957](https://github.com/nlohmann/json/pull/957) ([theodelrieu](https://github.com/theodelrieu)) - Fix links in README.md [\#955](https://github.com/nlohmann/json/pull/955) ([patrikhuber](https://github.com/patrikhuber)) @@ -1219,7 +1323,6 @@ All notable changes to this project will be documented in this file. This projec [Full Changelog](https://github.com/nlohmann/json/compare/v3.0.1...3.1.0) -- Order of the elements in JSON object [\#952](https://github.com/nlohmann/json/issues/952) - I have a proposal [\#949](https://github.com/nlohmann/json/issues/949) - VERSION define\(s\) [\#948](https://github.com/nlohmann/json/issues/948) - v3.0.1 compile error in icc 16.0.4 [\#947](https://github.com/nlohmann/json/issues/947) @@ -1421,7 +1524,6 @@ All notable changes to this project will be documented in this file. This projec - Project's name is too generic and hard to search for [\#730](https://github.com/nlohmann/json/issues/730) - Visual Studio 2015 IntelliTrace problems [\#729](https://github.com/nlohmann/json/issues/729) - How to erase nested objects inside other objects? [\#728](https://github.com/nlohmann/json/issues/728) -- How to prevent alphabetical sorting of data? [\#727](https://github.com/nlohmann/json/issues/727) - Serialization for CBOR [\#726](https://github.com/nlohmann/json/issues/726) - Using json Object as value in a map [\#725](https://github.com/nlohmann/json/issues/725) - std::regex and nlohmann::json value [\#724](https://github.com/nlohmann/json/issues/724) @@ -1469,7 +1571,6 @@ All notable changes to this project will be documented in this file. This projec - could this json lib work on windows? [\#664](https://github.com/nlohmann/json/issues/664) - How does from\_json work? [\#662](https://github.com/nlohmann/json/issues/662) - insert\(or merge\) object should replace same key , not ignore [\#661](https://github.com/nlohmann/json/issues/661) -- Why is an object ordering values by Alphabetical Order? [\#660](https://github.com/nlohmann/json/issues/660) - Parse method doesn't handle newlines. [\#659](https://github.com/nlohmann/json/issues/659) - Compilation "note" on GCC 6 ARM [\#658](https://github.com/nlohmann/json/issues/658) - Adding additional push\_back/operator+= rvalue overloads for JSON object [\#657](https://github.com/nlohmann/json/issues/657) @@ -1519,7 +1620,6 @@ All notable changes to this project will be documented in this file. This projec - Use of the binary type in CBOR and Message Pack [\#601](https://github.com/nlohmann/json/issues/601) - Newbie issue: how does one convert a map in Json back to std::map? [\#600](https://github.com/nlohmann/json/issues/600) - Plugin system [\#599](https://github.com/nlohmann/json/issues/599) -- Feature request: Comments [\#597](https://github.com/nlohmann/json/issues/597) - Using custom types for scalars? [\#596](https://github.com/nlohmann/json/issues/596) - Issues with the arithmetic in iterator and reverse iterator [\#593](https://github.com/nlohmann/json/issues/593) - not enough examples [\#592](https://github.com/nlohmann/json/issues/592) @@ -1561,7 +1661,6 @@ All notable changes to this project will be documented in this file. This projec - Ambiguous compare operators with clang-5.0 [\#547](https://github.com/nlohmann/json/issues/547) - Using tsl::ordered\_map [\#546](https://github.com/nlohmann/json/issues/546) - Compiler support errors are inconvenient [\#544](https://github.com/nlohmann/json/issues/544) -- Head Elements Sorting [\#543](https://github.com/nlohmann/json/issues/543) - Duplicate symbols error happens while to\_json/from\_json method implemented inside entity definition header file [\#542](https://github.com/nlohmann/json/issues/542) - consider adding a bool json::is\_valid\(std::string const&\) non-member function [\#541](https://github.com/nlohmann/json/issues/541) - Help request [\#539](https://github.com/nlohmann/json/issues/539) @@ -1730,7 +1829,6 @@ All notable changes to this project will be documented in this file. This projec - Getting std::invalid\_argument: stream error when following example [\#429](https://github.com/nlohmann/json/issues/429) - Forward declare-only header? [\#427](https://github.com/nlohmann/json/issues/427) - Implicit conversion from array to object [\#425](https://github.com/nlohmann/json/issues/425) -- Automatic ordered JSON [\#424](https://github.com/nlohmann/json/issues/424) - error C4996: 'strerror' when reading file [\#422](https://github.com/nlohmann/json/issues/422) - Get an error - JSON pointer must be empty or begin with '/' [\#421](https://github.com/nlohmann/json/issues/421) - size parameter for parse\(\) [\#419](https://github.com/nlohmann/json/issues/419) @@ -1739,7 +1837,6 @@ All notable changes to this project will be documented in this file. This projec - comparing to 0 literal [\#414](https://github.com/nlohmann/json/issues/414) - Single char converted to ASCII code instead of string [\#413](https://github.com/nlohmann/json/issues/413) - How to know if a string was parsed as utf-8? [\#406](https://github.com/nlohmann/json/issues/406) -- Heap-buffer-overflow \(OSS-Fuzz issue 342\) [\#405](https://github.com/nlohmann/json/issues/405) - Overloaded += to add objects to an array makes no sense? [\#404](https://github.com/nlohmann/json/issues/404) - Finding a value in an array [\#399](https://github.com/nlohmann/json/issues/399) - add release information in static function [\#397](https://github.com/nlohmann/json/issues/397) @@ -1769,6 +1866,7 @@ All notable changes to this project will be documented in this file. This projec - Use-of-uninitialized-value \(OSS-Fuzz issue 347\) [\#409](https://github.com/nlohmann/json/issues/409) - Heap-buffer-overflow \(OSS-Fuzz issue 344\) [\#408](https://github.com/nlohmann/json/issues/408) - Heap-buffer-overflow \(OSS-Fuzz issue 343\) [\#407](https://github.com/nlohmann/json/issues/407) +- Heap-buffer-overflow \(OSS-Fuzz issue 342\) [\#405](https://github.com/nlohmann/json/issues/405) - strerror throwing error in compiler VS2015 [\#403](https://github.com/nlohmann/json/issues/403) - json::parse of std::string being underlined by Visual Studio [\#402](https://github.com/nlohmann/json/issues/402) - Explicitly getting string without .dump\(\) [\#401](https://github.com/nlohmann/json/issues/401) @@ -1800,7 +1898,6 @@ All notable changes to this project will be documented in this file. This projec - Allow for forward declaring nlohmann::json [\#381](https://github.com/nlohmann/json/issues/381) - Bug in overflow detection when parsing integers [\#380](https://github.com/nlohmann/json/issues/380) - A unique name to mention the library? [\#377](https://github.com/nlohmann/json/issues/377) -- Support for comments. [\#376](https://github.com/nlohmann/json/issues/376) - Non-unique keys in objects. [\#375](https://github.com/nlohmann/json/issues/375) - Request: binary serialization/deserialization [\#358](https://github.com/nlohmann/json/issues/358) @@ -1824,7 +1921,6 @@ All notable changes to this project will be documented in this file. This projec - json::parse on failed stream gets stuck [\#366](https://github.com/nlohmann/json/issues/366) - Performance improvements [\#365](https://github.com/nlohmann/json/issues/365) - 'to\_string' is not a member of 'std' [\#364](https://github.com/nlohmann/json/issues/364) -- Optional comment support. [\#363](https://github.com/nlohmann/json/issues/363) - Crash in dump\(\) from a static object [\#359](https://github.com/nlohmann/json/issues/359) - json::parse\(...\) vs json j; j.parse\(...\) [\#357](https://github.com/nlohmann/json/issues/357) - Hi, is there any method to dump json to string with the insert order rather than alphabets [\#356](https://github.com/nlohmann/json/issues/356) @@ -1902,7 +1998,6 @@ All notable changes to this project will be documented in this file. This projec [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.2...v2.0.3) - warning C4706: assignment within conditional expression [\#295](https://github.com/nlohmann/json/issues/295) -- Strip comments / Minify [\#294](https://github.com/nlohmann/json/issues/294) - Q: Is it possible to build json tree from already UTF8 encoded values? [\#293](https://github.com/nlohmann/json/issues/293) - Equality operator results in array when assigned object [\#292](https://github.com/nlohmann/json/issues/292) - Support for integers not from the range \[-\(2\*\*53\)+1, \(2\*\*53\)-1\] in parser [\#291](https://github.com/nlohmann/json/issues/291) @@ -2077,7 +2172,6 @@ All notable changes to this project will be documented in this file. This projec - error: unterminated raw string [\#109](https://github.com/nlohmann/json/issues/109) - vector\ copy constructor really weird [\#108](https://github.com/nlohmann/json/issues/108) - \[clang-3.6.2\] string/sstream with number to json issue [\#107](https://github.com/nlohmann/json/issues/107) -- maintaining order of keys during iteration [\#106](https://github.com/nlohmann/json/issues/106) - object field accessors [\#103](https://github.com/nlohmann/json/issues/103) - v8pp and json [\#95](https://github.com/nlohmann/json/issues/95) - Wishlist [\#65](https://github.com/nlohmann/json/issues/65) diff --git a/Makefile b/Makefile index 8579fb5d..98fa365a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ ########################################################################## # directory to recent compiler binaries -COMPILER_DIR=/Users/niels/Documents/projects/compilers/local/bin +COMPILER_DIR=/usr/local/opt/llvm/bin # find GNU sed to use `-i` parameter SED:=$(shell command -v gsed || which sed) @@ -30,7 +30,6 @@ AMALGAMATED_FILE=single_include/nlohmann/json.hpp all: @echo "amalgamate - amalgamate file single_include/nlohmann/json.hpp from the include/nlohmann sources" @echo "ChangeLog.md - generate ChangeLog file" - @echo "check - compile and execute test suite" @echo "check-amalgamation - check whether sources have been amalgamated" @echo "clean - remove built files" @echo "coverage - create coverage information with lcov" @@ -44,38 +43,24 @@ all: @echo "fuzz_testing_cbor - prepare fuzz testing of the CBOR parser" @echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser" @echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser" - @echo "json_unit - create single-file test executable" @echo "pedantic_clang - run Clang with maximal warning flags" @echo "pedantic_gcc - run GCC with maximal warning flags" @echo "pretty - beautify code with Artistic Style" @echo "run_benchmarks - build and run benchmarks" -########################################################################## -# unit tests -########################################################################## - -# build unit tests -json_unit: - @$(MAKE) json_unit -C test - -# run unit tests -check: - $(MAKE) check -C test - - ########################################################################## # coverage ########################################################################## coverage: - rm -fr build_coverage - mkdir build_coverage - cd build_coverage ; cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON - cd build_coverage ; ninja - cd build_coverage ; ctest -j10 - cd build_coverage ; ninja lcov_html - open build_coverage/test/html/index.html + rm -fr cmake-build-coverage + mkdir cmake-build-coverage + cd cmake-build-coverage ; cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON + cd cmake-build-coverage ; ninja + cd cmake-build-coverage ; ctest -j10 + cd cmake-build-coverage ; ninja lcov_html + open cmake-build-coverage/test/html/index.html ########################################################################## # documentation tests @@ -97,12 +82,13 @@ doctest: # -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM # -Wno-float-equal: not all comparisons in the tests can be replaced by Approx # -Wno-keyword-macro: unit-tests use "#define private public" +# -Wno-missing-prototypes: for NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE # -Wno-padded: padding is nothing to warn about # -Wno-range-loop-analysis: items tests "for(const auto i...)" # -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches # -Wno-weak-vtables: exception class is defined inline, but has virtual method pedantic_clang: - rm -fr build_pedantic + rm -fr cmake-build-pedantic CXXFLAGS=" \ -std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \ -Werror \ @@ -113,15 +99,16 @@ pedantic_clang: -Wno-exit-time-destructors \ -Wno-float-equal \ -Wno-keyword-macro \ + -Wno-missing-prototypes \ -Wno-padded \ -Wno-range-loop-analysis \ -Wno-switch-enum -Wno-covered-switch-default \ - -Wno-weak-vtables" cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On - cmake --build build_pedantic + -Wno-weak-vtables" cmake -S . -B cmake-build-pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On + cmake --build cmake-build-pedantic # calling GCC with most warnings pedantic_gcc: - rm -fr build_pedantic + rm -fr cmake-build-pedantic CXXFLAGS=" \ -std=c++11 \ -pedantic \ @@ -253,7 +240,7 @@ pedantic_gcc: -Wmismatched-tags \ -Wmissing-attributes \ -Wmissing-braces \ - -Wmissing-declarations \ + -Wno-missing-declarations \ -Wmissing-field-initializers \ -Wmissing-include-dirs \ -Wmissing-profile \ @@ -379,19 +366,19 @@ pedantic_gcc: -Wwrite-strings \ -Wzero-as-null-pointer-constant \ -Wzero-length-bounds \ - " cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On - cmake --build build_pedantic + " cmake -S . -B cmake-build-pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On + cmake --build cmake-build-pedantic ########################################################################## # benchmarks ########################################################################## run_benchmarks: - rm -fr build_benchmarks - mkdir build_benchmarks - cd build_benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=On - cd build_benchmarks ; ninja - cd build_benchmarks ; ./json_benchmarks + rm -fr cmake-build-benchmarks + mkdir cmake-build-benchmarks + cd cmake-build-benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=On + cd cmake-build-benchmarks ; ninja + cd cmake-build-benchmarks ; ./json_benchmarks ########################################################################## # fuzzing @@ -464,14 +451,14 @@ cppcheck: # call Clang Static Analyzer clang_analyze: - rm -fr clang_analyze_build - mkdir clang_analyze_build - cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On - cd clang_analyze_build ; \ + rm -fr cmake-build-clang-analyze + mkdir cmake-build-clang-analyze + cd cmake-build-clang-analyze ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On + cd cmake-build-clang-analyze ; \ $(COMPILER_DIR)/scan-build \ -enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \ --use-c++=$(COMPILER_DIR)/clang++ -analyze-headers -o report ninja - open clang_analyze_build/report/*/index.html + open cmake-build-clang-analyze/report/*/index.html # call cpplint # Note: some errors expected due to false positives @@ -482,22 +469,22 @@ cpplint: # call Clang-Tidy clang_tidy: - $(COMPILER_DIR)/clang-tidy $(AMALGAMATED_FILE) -- -Iinclude -std=c++11 + $(COMPILER_DIR)/clang-tidy $(SRCS) -- -Iinclude -std=c++11 # call PVS-Studio Analyzer pvs_studio: - rm -fr pvs_studio_build - mkdir pvs_studio_build - cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On - cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10 - cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs - open pvs_studio_build/pvs/index.html + rm -fr cmake-build-pvs-studio + mkdir cmake-build-pvs-studio + cd cmake-build-pvs-studio ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DJSON_MultipleHeaders=ON + cd cmake-build-pvs-studio ; pvs-studio-analyzer analyze -j 10 + cd cmake-build-pvs-studio ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs + open cmake-build-pvs-studio/pvs/index.html # call Infer static analyzer infer: - rm -fr infer_build - mkdir infer_build - cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4 + rm -fr cmake-build-infer + mkdir cmake-build-infer + cd cmake-build-infer ; infer compile -- cmake .. -DJSON_MultipleHeaders=ON ; infer run -- make -j 4 # call OCLint static analyzer oclint: @@ -506,11 +493,11 @@ oclint: # execute the test suite with Clang sanitizers (address and undefined behavior) clang_sanitize: - rm -fr clang_sanitize_build - mkdir clang_sanitize_build - cd clang_sanitize_build ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On -GNinja - cd clang_sanitize_build ; ninja - cd clang_sanitize_build ; ctest -j10 + rm -fr cmake-build-clang-sanitize + mkdir cmake-build-clang-sanitize + cd cmake-build-clang-sanitize ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On -GNinja + cd cmake-build-clang-sanitize ; ninja + cd cmake-build-clang-sanitize ; ctest -j10 ########################################################################## @@ -538,7 +525,11 @@ pretty: --preserve-date \ --suffix=none \ --formatted \ - $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp + $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp test/src/*.hpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp + +# call the Clang-Format on all source files +pretty_format: + for FILE in $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp test/src/*.hpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done # create single header file amalgamate: $(AMALGAMATED_FILE) @@ -560,7 +551,7 @@ check-amalgamation: check-single-includes: @for x in $(SRCS); do \ echo "Checking self-sufficiency of $$x..." ; \ - echo "#include <$$x>\nint main() {}\n" | sed 's|include/||' > single_include_test.cpp; \ + echo "#include <$$x>\nint main() {}\n" | $(SED) 's|include/||' > single_include_test.cpp; \ $(CXX) $(CXXFLAGS) -Iinclude -std=c++11 single_include_test.cpp -o single_include_test; \ rm -f single_include_test.cpp single_include_test; \ done @@ -570,17 +561,17 @@ check-single-includes: # CMake ########################################################################## -# grep "^option" CMakeLists.txt test/CMakeLists.txt | sed 's/(/ /' | awk '{print $2}' | xargs +# grep "^option" CMakeLists.txt test/CMakeLists.txt | $(SED) 's/(/ /' | awk '{print $2}' | xargs # check if all flags of our CMake files work check_cmake_flags_do: $(CMAKE_BINARY) --version - for flag in '' JSON_BuildTests JSON_Install JSON_MultipleHeaders JSON_Sanitizer JSON_Valgrind JSON_NoExceptions JSON_Coverage; do \ + for flag in JSON_BuildTests JSON_Install JSON_MultipleHeaders JSON_Sanitizer JSON_Valgrind JSON_NoExceptions JSON_Coverage; do \ rm -fr cmake_build; \ mkdir cmake_build; \ - echo "$(CMAKE_BINARY) .. -D$$flag=On" ; \ + echo "\n\n$(CMAKE_BINARY) .. -D$$flag=On\n" ; \ cd cmake_build ; \ - CXX=g++-8 $(CMAKE_BINARY) .. -D$$flag=On -DCMAKE_CXX_COMPILE_FEATURES="cxx_std_11;cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11" ; \ + $(CMAKE_BINARY) -Werror=dev .. -D$$flag=On -DCMAKE_CXX_COMPILE_FEATURES="cxx_std_11;cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11" ; \ test -f Makefile || exit 1 ; \ cd .. ; \ done; @@ -638,9 +629,8 @@ clean: rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html rm -fr benchmarks/files/numbers/*.json rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64 - rm -fr build_coverage build_benchmarks fuzz-testing clang_analyze_build pvs_studio_build infer_build clang_sanitize_build cmake_build + rm -fr cmake-build-coverage cmake-build-benchmarks fuzz-testing cmake-build-clang-analyze cmake-build-pvs-studio cmake-build-infer cmake-build-clang-sanitize cmake_build $(MAKE) clean -Cdoc - $(MAKE) clean -Ctest ########################################################################## # Thirdparty code @@ -649,6 +639,6 @@ clean: update_hedley: rm -f include/nlohmann/thirdparty/hedley/hedley.hpp include/nlohmann/thirdparty/hedley/hedley_undef.hpp curl https://raw.githubusercontent.com/nemequ/hedley/master/hedley.h -o include/nlohmann/thirdparty/hedley/hedley.hpp - gsed -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp - grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | gsed 's/ //g' | gsed 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp + $(SED) -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp + grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | $(SED) 's/ //g' | $(SED) 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp $(MAKE) amalgamate diff --git a/README.md b/README.md index d7492da3..07933a5b 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [Integration](#integration) - [CMake](#cmake) - [Package Managers](#package-managers) + - [Pkg-config](#pkg-config) - [Examples](#examples) - [JSON as first-class data type](#json-as-first-class-data-type) - [Serialization / Deserialization](#serialization--deserialization) @@ -230,6 +231,20 @@ Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. +### Pkg-config + +If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed: + +```sh +pkg-config nlohmann_json --cflags +``` + +Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`: + +```meson +json = dependency('nlohmann_json', required: true) +``` + ## Examples Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). @@ -468,7 +483,7 @@ MyIterator begin(MyContainer& tgt) { } MyIterator end(const MyContainer&) { - return {}; + return {}; } void foo() { @@ -497,6 +512,8 @@ bool number_float(number_float_t val, const string_t& s); // called when a string is parsed; value is passed and can be safely moved away bool string(string_t& val); +// called when a binary value is parsed; value is passed and can be safely moved away +bool binary(binary_t& val); // called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) bool start_object(std::size_t elements); @@ -746,7 +763,8 @@ j_document.merge_patch(j_patch); Supported types can be implicitly converted to JSON values. It is recommended to **NOT USE** implicit conversions **FROM** a JSON value. -You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958). +You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958). +You can switch off implicit conversions by defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` before including the `json.hpp` header. When using CMake, you can also achieve this by setting the option `JSON_ImplicitConversions` to `OFF`. ```cpp // strings @@ -869,6 +887,42 @@ Some important things: * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. +#### Simplify your life with macros + +If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. + +There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: + +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members. + +In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. + +##### Examples + +The `to_json`/`from_json` functions for the `person` struct above can be created with: + +```cpp +namespace ns { + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) +} +``` + +Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: + +```cpp +namespace ns { + class address { + private: + std::string street; + int housenumber; + int postcode; + + public: + NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) + }; +} +``` #### How do I convert third-party types? @@ -1139,6 +1193,7 @@ Though it's 2020 already, the support for C++11 is still a bit sparse. Currently - GCC 4.8 - 10.1 (and possibly later) - Clang 3.4 - 10.0 (and possibly later) +- Apple Clang 9.1 - 12.0 (and possibly later) - Intel C++ Compiler 17.0.2 (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) @@ -1174,6 +1229,7 @@ The following compilers are currently used in continuous integration at [Travis] | Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.2.1 | macOS 10.14.4 | Travis | | Apple Clang 11.0.0 (clang-1100.0.33.12); Xcode 11.2.1 | macOS 10.14.6 | Travis | | Apple Clang 11.0.3 (clang-1103.0.32.59); Xcode 11.4.1 | macOS 10.15.4 | GitHub Actions | +| Apple Clang 12.0.0 (clang-1200.0.22.7); Xcode 11.4.1 | macOS 10.15.5 | Travis | | Clang 3.5.0 (3.5.0-4ubuntu2~trusty2) | Ubuntu 14.04.5 LTS | Travis | | Clang 3.6.2 (3.6.2-svn240577-1~exp1) | Ubuntu 14.04.5 LTS | Travis | | Clang 3.7.1 (3.7.1-svn253571-1~exp1) | Ubuntu 14.04.5 LTS | Travis | @@ -1184,6 +1240,8 @@ The following compilers are currently used in continuous integration at [Travis] | Clang 6.0.1 (6.0.1-svn334776-1~exp1~20190309042707.121) | Ubuntu 14.04.5 LTS | Travis | | Clang 7.1.0 (7.1.0-svn353565-1~exp1~20190419134007.64) | Ubuntu 14.04.5 LTS | Travis | | Clang 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | Travis | +| Clang 9.0.0 (x86_64-pc-windows-msvc) | Windows-10.0.17763 | GitHub Actions | +| Clang 10.0.0 (x86_64-pc-windows-msvc) | Windows-10.0.17763 | GitHub Actions | | GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu8~14.04.2) | Ubuntu 14.04.5 LTS | Travis | | GCC 4.9.4 (Ubuntu 4.9.4-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis | | GCC 5.5.0 (Ubuntu 5.5.0-12ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis | @@ -1199,6 +1257,7 @@ The following compilers are currently used in continuous integration at [Travis] | MSVC 19.16.27035.0 (15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor | | MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) | Windows-10.0.17763 | AppVeyor | | MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) | Windows-10.0.17763 | GitHub Actions | +| MSVC 19.25.28614.0 (Build Engine version 16.5.0+d4cbfca49 for .NET Framework) with ClangCL 10.0.0 | Windows-10.0.17763 | GitHub Actions | ## License @@ -1452,6 +1511,17 @@ I deeply appreciate the help of the following people. - [XyFreak](https://github.com/XyFreak) fixed a compiler warning. - [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README. - [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input. +- [AODQ](https://github.com/AODQ) fixed a compiler warning. +- [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline. +- [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. +- [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values. +- [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation. +- [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes. +- [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`. +- [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config. +- [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. +- [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support. +- [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. @@ -1508,39 +1578,37 @@ The library supports **Unicode input** as follows: ### Comments in JSON -This library does not support comments. It does so for three reasons: +This library does not support comments by default. It does so for three reasons: 1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. 2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: - > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. + > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. 3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. -This library will not support comments in the future. If you wish to use comments, I see three options: - -1. Strip comments before using this library. -2. Use a different JSON library with comment support. -3. Use a format that natively supports comments (e.g., YAML or JSON5). +However, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. ### Order of object keys -By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). +By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". + +If you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). ### Memory Release -We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks. +We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks. -If you find that a parsing program with this library does not release memory, please consider the following case and it maybe unrelated to this library. +If you find that a parsing program with this library does not release memory, please consider the following case and it maybe unrelated to this library. **Your program is compiled with glibc.** There is a tunable threshold that glibc uses to decide whether to actually return memory to the system or whether to cache it for later reuse. If in your program you make lots of small allocations and those small allocations are not a contiguous block and are presumably below the threshold, then they will not get returned to the OS. Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924). ### Further notes -- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). +- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`. - As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. - **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. @@ -1557,4 +1625,6 @@ $ cmake --build . $ ctest --output-on-failure ``` -For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). +Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. + +In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure`. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. diff --git a/appveyor.yml b/appveyor.yml index 73788956..5836f88d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,7 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 14 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 @@ -14,6 +15,7 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 @@ -21,6 +23,7 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 16 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 @@ -28,6 +31,7 @@ environment: platform: x64 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 16 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -36,6 +40,7 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Ninja - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -44,6 +49,7 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Ninja - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -51,6 +57,7 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 14 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -59,6 +66,7 @@ environment: name: with_win_header CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 14 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 @@ -66,6 +74,7 @@ environment: platform: x86 CXX_FLAGS: "/permissive- /std:c++latest /utf-8" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 @@ -73,6 +82,15 @@ environment: platform: x86 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "-DJSON_ImplicitConversions=OFF" + GENERATOR: Visual Studio 16 2019 + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + configuration: Release + platform: x64 + CXX_FLAGS: "" + LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 16 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -80,6 +98,7 @@ environment: platform: x64 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 14 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 @@ -87,6 +106,7 @@ environment: platform: x64 CXX_FLAGS: "/permissive- /std:c++latest /Zc:__cplusplus /utf-8 /F4000000" LINKER_FLAGS: "/STACK:4000000" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 @@ -94,6 +114,7 @@ environment: platform: x64 CXX_FLAGS: "" LINKER_FLAGS: "" + CMAKE_OPTIONS: "" GENERATOR: Visual Studio 16 2019 init: @@ -112,7 +133,7 @@ before_build: # for with_win_header build, inject the inclusion of Windows.h to the single-header library - ps: if ($env:name -Eq "with_win_header") { $header_path = "single_include\nlohmann\json.hpp" } - ps: if ($env:name -Eq "with_win_header") { "#include `n" + (Get-Content $header_path | Out-String) | Set-Content $header_path } - - if "%GENERATOR%"=="Ninja" (cmake . -G "%GENERATOR%" -DCMAKE_BUILD_TYPE="%configuration%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On) else (cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On) + - if "%GENERATOR%"=="Ninja" (cmake . -G "%GENERATOR%" -DCMAKE_BUILD_TYPE="%configuration%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%") else (cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%") build_script: - cmake --build . --config "%configuration%" diff --git a/cmake/download_test_data.cmake b/cmake/download_test_data.cmake index fe95235f..a3f3f199 100644 --- a/cmake/download_test_data.cmake +++ b/cmake/download_test_data.cmake @@ -1,17 +1,22 @@ -find_package(Git) - set(JSON_TEST_DATA_URL https://github.com/nlohmann/json_test_data) -set(JSON_TEST_DATA_VERSION 2.0.0) +set(JSON_TEST_DATA_VERSION 3.0.0) -# target to download test data -add_custom_target(download_test_data - COMMAND test -d json_test_data || ${GIT_EXECUTABLE} clone -c advice.detachedHead=false --branch v${JSON_TEST_DATA_VERSION} ${JSON_TEST_DATA_URL}.git --quiet --depth 1 - COMMENT "Downloading test data from ${JSON_TEST_DATA_URL} (v${JSON_TEST_DATA_VERSION})" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} -) - -# create a header with the path to the downloaded test data -file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${CMAKE_BINARY_DIR}/json_test_data\"\n") +# if variable is set, use test data from given directory rather than downloading them +if(JSON_TestDataDirectory) + message(STATUS "Using test data in ${JSON_TestDataDirectory}.") + add_custom_target(download_test_data) + file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${JSON_TestDataDirectory}\"\n") +else() + find_package(Git) + # target to download test data + add_custom_target(download_test_data + COMMAND test -d json_test_data || ${GIT_EXECUTABLE} clone -c advice.detachedHead=false --branch v${JSON_TEST_DATA_VERSION} ${JSON_TEST_DATA_URL}.git --quiet --depth 1 + COMMENT "Downloading test data from ${JSON_TEST_DATA_URL} (v${JSON_TEST_DATA_VERSION})" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + # create a header with the path to the downloaded test data + file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${CMAKE_BINARY_DIR}/json_test_data\"\n") +endif() # determine the operating system (for debug and support purposes) find_program(UNAME_COMMAND uname) diff --git a/cmake/pkg-config.pc.in b/cmake/pkg-config.pc.in new file mode 100644 index 00000000..3541abf0 --- /dev/null +++ b/cmake/pkg-config.pc.in @@ -0,0 +1,4 @@ +Name: ${PROJECT_NAME} +Description: JSON for Modern C++ +Version: ${PROJECT_VERSION} +Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} diff --git a/doc/Doxyfile b/doc/Doxyfile index 56a41d13..e6207fb0 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 3.8.0 +PROJECT_NUMBER = 3.9.0 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . diff --git a/doc/Makefile b/doc/Makefile index 07e417c1..35e8b5aa 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -43,7 +43,7 @@ check_output: $(EXAMPLES:.cpp=.test) clean: - rm -fr me.nlohmann.json.docset html $(EXAMPLES:.cpp=) + rm -fr me.nlohmann.json.docset html xml $(EXAMPLES:.cpp=) ########################################################################## diff --git a/doc/avatars.png b/doc/avatars.png index d21ddc54..e3c29989 100644 Binary files a/doc/avatars.png and b/doc/avatars.png differ diff --git a/doc/examples/README.link b/doc/examples/README.link index 0589c59d..786b27be 100644 --- a/doc/examples/README.link +++ b/doc/examples/README.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/meta.output b/doc/examples/meta.output index aa47599b..ffadccbe 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -2,16 +2,16 @@ "compiler": { "c++": "201103", "family": "clang", - "version": "11.0.3 (clang-1103.0.32.62)" + "version": "12.0.0 (clang-1200.0.22.19)" }, - "copyright": "(C) 2013-2017 Niels Lohmann", + "copyright": "(C) 2013-2020 Niels Lohmann", "name": "JSON for Modern C++", "platform": "apple", "url": "https://github.com/nlohmann/json", "version": { "major": 3, - "minor": 8, + "minor": 9, "patch": 0, - "string": "3.8.0" + "string": "3.9.0" } } diff --git a/doc/index.md b/doc/index.md index fd5cf88d..e990e7a3 100644 --- a/doc/index.md +++ b/doc/index.md @@ -332,4 +332,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 3.8.0 +@version 3.9.0 diff --git a/doc/json.gif b/doc/json.gif index c9557b91..d3dfb91c 100644 Binary files a/doc/json.gif and b/doc/json.gif differ diff --git a/doc/mkdocs/docs/api/basic_json/dump.md b/doc/mkdocs/docs/api/basic_json/dump.md new file mode 100644 index 00000000..9ea6e356 --- /dev/null +++ b/doc/mkdocs/docs/api/basic_json/dump.md @@ -0,0 +1,74 @@ +# basic_json::dump + +```cpp +string_t dump(const int indent = -1, + const char indent_char = ' ', + const bool ensure_ascii = false, + const error_handler_t error_handler = error_handler_t::strict) const +``` + +Serialization function for JSON values. The function tries to mimic +Python's `json.dumps()` function, and currently supports its `indent` +and `ensure_ascii` parameters. + +## Parameters + +`indent` (in) +: If `indent` is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + +`indent_char` (in) +: The character to use for indentation if `indent` is + greater than `0`. The default is ` ` (space). + +`ensure_ascii` (in) +: If `ensure_ascii` is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + +`error_handler` (in) +: how to react on decoding errors; there are three + possible values: `strict` (throws and exception in case a decoding error + occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), + and `ignore` (ignore invalid UTF-8 sequences during serialization; all + bytes are copied to the output unchanged). + +## Return value + +string containing the serialization of the JSON value + +## Exception safety + +Strong guarantee: if an exception is thrown, there are no +changes to any JSON value. + +## Complexity + +Linear. + +## Notes + +Binary values are serialized as object containing two keys: + +- "bytes": an array of bytes as integers +- "subtype": the subtype as integer or `#!json null` if the binary has no subtype + +## Example + +??? example + + The following example shows the effect of different `indent`, + `indent_char`, and `ensure_ascii` parameters to the result of the + serialization. + + ```cpp + --8<-- "examples/dump.cpp" + ``` + + Output: + + ```json + --8<-- "examples/dump.output" + ``` diff --git a/doc/mkdocs/docs/api/basic_json/index.md b/doc/mkdocs/docs/api/basic_json/index.md new file mode 100644 index 00000000..496cd68b --- /dev/null +++ b/doc/mkdocs/docs/api/basic_json/index.md @@ -0,0 +1,253 @@ +# basic_json + +!!! note + + This page is under construction. + +Defined in header `` + +```cpp +template class ObjectType, + template class ArrayType, + class StringType, class BooleanType, class NumberIntegerType, + class NumberUnsignedType, class NumberFloatType, + template class AllocatorType, + template class JSONSerializer, + class BinaryType> +class basic_json +``` + +## Specializations + +- json +- ordered_json + +## Template parameters + +- ObjectType +- ArrayType +- StringType +- BooleanType +- NumberIntegerType +- NumberUnsignedType +- NumberFloatType +- AllocatorType +- JSONSerializer +- BinaryType + +## Iterator invalidation + +## Member types + +- value_t +- json_pointer +- json_serializer +- error_handler_t +- cbor_tag_handler_t +- initializer_list_t +- input_format_t +- json_sax_t + +### Exceptions + +- exception +- parse_error +- invalid_iterator +- type_error +- out_of_range +- other_error + +### Container types + +- value_type +- reference +- const_reference +- difference_type +- size_type +- allocator_type +- pointer +- const_pointer +- iterator +- const_iterator +- reverse_iterator +- const_reverse_iterator + +### JSON value data types + +- object_comparator_t +- object_t +- array_t +- string_t +- boolean_t +- number_integer_t +- number_unsigned_t +- number_float_t +- binary_t + +### Parser callback + +- parse_event_t +- parser_callback_t + +## Member functions + +- (constructor) +- (destructor) +- binary (static) - explicitly create a binary array +- array (static) - explicitly create an array +- object (static) - explicitly create an object +- operator= - copy assignment + +### Object inspection + +Functions to inspect the type of a JSON value. + +- type - return the type of the JSON value +- is_primitive - return whether type is primitive +- is_structured - return whether type is structured +- is_null - return whether value is null +- is_boolean - return whether value is a boolean +- is_number - return whether value is a number +- is_number_integer - return whether value is an integer number +- is_number_unsigned - return whether value is an unsigned integer number +- is_number_float - return whether value is a floating-point number +- is_object - return whether value is an object +- is_array - return whether value is an array +- is_string - return whether value is a string +- is_binary - return whether value is a binary array +- is_discarded - return whether value is discarded +- operator value_t - return the type of the JSON value + +### Value access + +Direct access to the stored value of a JSON value. + +- get - get a value +- get_to - get a value +- get_ptr - get a pointer value +- get_ref - get a reference value +- operator ValueType - get a value +- get_binary - get a binary value + +### Element access + +Access to the JSON value + +- at - access specified array element with bounds checking +- at - access specified object element with bounds checking +- operator[] - access specified array element +- operator[] - access specified object element +- value - access specified object element with default value +- front - access the first element +- back - access the last element +- erase - remove elements + +### Lookup + +- find - find an element in a JSON object +- count - returns the number of occurrences of a key in a JSON object +- contains - check the existence of an element in a JSON object + +### Iterators + +- begin - returns an iterator to the first element +- cbegin - returns a const iterator to the first element +- end - returns an iterator to one past the last element +- cend - returns a const iterator to one past the last element +- rbegin - returns an iterator to the reverse-beginning +- rend - returns an iterator to the reverse-end +- crbegin - returns a const iterator to the reverse-beginning +- crend - returns a const iterator to the reverse-end +- items - wrapper to access iterator member functions in range-based for + +### Capacity + +- empty - checks whether the container is empty +- size - returns the number of elements +- max_size - returns the maximum possible number of elements + +### Modifiers + +- clear - clears the contents +- push_back - add an object to an array +- operator+= - add an object to an array +- push_back - add an object to an object +- operator+= - add an object to an object +- emplace_back - add an object to an array +- emplace - add an object to an object if key does not exist +- insert - inserts element +- update - updates a JSON object from another object, overwriting existing keys +- swap - exchanges the values + +### Lexicographical comparison operators + +- operator== - comparison: equal +- operator!= - comparison: not equal +- operator< - comparison: less than +- operator<= - comparison: less than or equal +- operator> - comparison: greater than +- operator>= - comparison: greater than or equal + +### Serialization + +- [**dump**](dump.md) - serialization +- to_string - user-defined to_string function for JSON values + +### Deserialization + +- [**parse**](parse.md) - deserialize from a compatible input +- accept - check if the input is valid JSON +- sax_parse - generate SAX events + +### Convenience functions + +- type_name - return the type as string + +### JSON Pointer functions + +- at - access specified object element with bounds checking via JSON Pointer +- operator[] - access specified element via JSON Pointer +- value - access specified object element with default value via JSON Pointer +- flatten - return flattened JSON value +- unflatten - unflatten a previously flattened JSON value + +### JSON Patch functions + +- patch - applies a JSON patch +- diff (static) - creates a diff as a JSON patch + +### JSON Merge Patch functions + +- merge_patch - applies a JSON Merge Patch + +## Static functions + +- [**meta**](meta.md) - returns version information on the library +- get_allocator - returns the allocator associated with the container + +### Binary formats + +- to_cbor - create a CBOR serialization of a given JSON value +- to_msgpack - create a MessagePack serialization of a given JSON value +- to_ubjson - create a UBJSON serialization of a given JSON value +- to_bson - create a BSON serialization of a given JSON value +- from_cbor - create a JSON value from an input in CBOR format +- from_msgpack - create a JSON value from an input in MessagePack format +- from_ubjson - create a JSON value from an input in UBJSON format +- from_bson - create a JSON value from an input in BSON format + +## Non-member functions + +- operator<<(std::ostream&) - serialize to stream +- operator>>(std::istream&) - deserialize from stream + +## Literals + +- operator""_json +- operator""_json_pointer + +## Helper classes + +- std::hash +- std::less +- std::swap diff --git a/doc/mkdocs/docs/api/basic_json/meta.md b/doc/mkdocs/docs/api/basic_json/meta.md new file mode 100644 index 00000000..fd577545 --- /dev/null +++ b/doc/mkdocs/docs/api/basic_json/meta.md @@ -0,0 +1,45 @@ +# basic_json::meta + +```cpp +static basic_json meta(); +``` + +This function returns a JSON object with information about the library, +including the version number and information on the platform and compiler. + +## Return value + +JSON object holding version information + +key | description +----------- | --------------- +`compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). +`copyright` | The copyright line for the library as string. +`name` | The name of the library as string. +`platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. +`url` | The URL of the project as string. +`version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + +## Exception safety + +Strong guarantee: if an exception is thrown, there are no +changes to any JSON value. + +## Complexity + +Constant. + +## Example + +The following code shows an example output of the `meta()` +function. + +```cpp +--8<-- "examples/meta.cpp" +``` + +Output: + +```json +--8<-- "examples/meta.output" +``` diff --git a/doc/mkdocs/docs/api/basic_json/parse.md b/doc/mkdocs/docs/api/basic_json/parse.md new file mode 100644 index 00000000..f89df426 --- /dev/null +++ b/doc/mkdocs/docs/api/basic_json/parse.md @@ -0,0 +1,146 @@ +# basic_json::parse + +```cpp +// (1) +template +static basic_json parse(InputType&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + +// (2) +template +static basic_json parse(IteratorType first, + IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) +``` + +1. Deserialize from a compatible input. +2. Deserialize from a pair of character iterators + + The value_type of the iterator must be a integral type with size of 1, 2 or + 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. + +## Template parameters + +`InputType` +: A compatible input, for instance: + + - an `std::istream` object + - a `FILE` pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object `obj` for which `begin(obj)` and `end(obj)` produces a valid pair of + iterators. + +`IteratorType` +: Description + +## Parameters + +`i` (in) +: Input to parse from. + +`cb` (in) +: a parser callback function of type `parser_callback_t` + which is used to control the deserialization by filtering unwanted values + (optional) + +`allow_exceptions` (in) +: whether to throw exceptions in case of a parse error (optional, `#!cpp true` by default) + +`ignore_comments` (in) +: whether comments should be ignored and treated + like whitespace (`#!cpp true`) or yield a parse error (`#!cpp false`); (optional, `#!cpp false` by + default) + +`first` (in) +: iterator to start of character range + +`last` (in) +: iterator to end of character range + +## Return value + +Deserialized JSON value; in case of a parse error and `allow_exceptions` +set to `#!cpp false`, the return value will be `value_t::discarded`. + +## Exception safety + +## Complexity + +Linear in the length of the input. The parser is a predictive +LL(1) parser. The complexity can be higher if the parser callback function +`cb` or reading from (1) the input `i` or (2) the iterator range [`first`, `last`] has a super-linear complexity. + +## Notes + +(1) A UTF-8 byte order mark is silently ignored. + +## Examples + +??? example + + The example below demonstrates the `parse()` function reading + from an array. + + ```cpp + --8<-- "examples/parse__array__parser_callback_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/parse__array__parser_callback_t.output" + ``` + +??? example + + The example below demonstrates the `parse()` function with + and without callback function. + + ```cpp + --8<-- "examples/parse__string__parser_callback_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/parse__string__parser_callback_t.output" + ``` + +??? example + + The example below demonstrates the `parse()` function with + and without callback function. + + ```cpp + --8<-- "examples/parse__istream__parser_callback_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/parse__istream__parser_callback_t.output" + ``` + +??? example + + The example below demonstrates the `parse()` function reading + from a contiguous container. + + ```cpp + --8<-- "examples/parse__contiguouscontainer__parser_callback_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/parse__contiguouscontainer__parser_callback_t.output" + ``` + +## History + +(1) version 2.0.3 (contiguous containers); version 3.9.0 allowed to ignore comments. diff --git a/doc/mkdocs/docs/features/arbitrary_types.md b/doc/mkdocs/docs/features/arbitrary_types.md index 3d238317..23913bba 100644 --- a/doc/mkdocs/docs/features/arbitrary_types.md +++ b/doc/mkdocs/docs/features/arbitrary_types.md @@ -81,6 +81,47 @@ Some important things: * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. +## Simplify your life with macros + +If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. + +There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: + +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members. + +In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. + +!!! note + + At most 64 member variables can be passed to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` or `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. + +??? example + + The `to_json`/`from_json` functions for the `person` struct above can be created with: + + ```cpp + namespace ns { + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) + } + ``` + + Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: + + ```cpp + namespace ns { + class address { + private: + std::string street; + int housenumber; + int postcode; + + public: + NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) + }; + } + ``` + ## How do I convert third-party types? This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: diff --git a/doc/mkdocs/docs/features/binary_formats/cbor.md b/doc/mkdocs/docs/features/binary_formats/cbor.md index daea3a51..daa29be8 100644 --- a/doc/mkdocs/docs/features/binary_formats/cbor.md +++ b/doc/mkdocs/docs/features/binary_formats/cbor.md @@ -64,7 +64,6 @@ binary | *size*: 4294967296..18446744073709551615 | byte string (8 by If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the normal JSON serialization which serializes NaN or Infinity to `null`. - !!! info "Unused CBOR types" The following CBOR types are not used in the conversion: @@ -77,13 +76,16 @@ binary | *size*: 4294967296..18446744073709551615 | byte string (8 by - bignum (0xC2..0xC3) - decimal fraction (0xC4) - bigfloat (0xC5) - - tagged items (0xC6..0xD4, 0xD8..0xDB) - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) - half-precision floats (0xF9) - break (0xFF) +!!! info "Tagged items" + + Binary subtypes will be serialized as tagged items. See [binary values](../binary_values.md#cbor) for an example. + ??? example ```cpp @@ -150,7 +152,6 @@ Double-Precision Float | number_float | 0xFB - bignum (0xC2..0xC3) - decimal fraction (0xC4) - bigfloat (0xC5) - - tagged items (0xC6..0xD4, 0xD8..0xDB) - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) @@ -159,6 +160,10 @@ Double-Precision Float | number_float | 0xFB CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected. +!!! warning "Tagged items" + + Tagged items will throw a parse error by default. However, they can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`. + ??? example ```cpp diff --git a/doc/mkdocs/docs/features/binary_formats/messagepack.md b/doc/mkdocs/docs/features/binary_formats/messagepack.md index ed061056..3e041bb7 100644 --- a/doc/mkdocs/docs/features/binary_formats/messagepack.md +++ b/doc/mkdocs/docs/features/binary_formats/messagepack.md @@ -31,7 +31,8 @@ number_unsigned | 128..255 | uint 8 | 0xCC number_unsigned | 256..65535 | uint 16 | 0xCD number_unsigned | 65536..4294967295 | uint 32 | 0xCE number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF -number_float | *any value* | float 64 | 0xCB +number_float | *any value representable by a float* | float 32 | 0xCA +number_float | *any value NOT representable by a float* | float 64 | 0xCB string | *length*: 0..31 | fixstr | 0xA0..0xBF string | *length*: 32..255 | str 8 | 0xD9 string | *length*: 256..65535 | str 16 | 0xDA @@ -61,10 +62,6 @@ binary | *size*: 65536..4294967295 | bin 32 | 0xC6 - arrays with more than 4294967295 elements - objects with more than 4294967295 elements -!!! info "Unused MessagePack types" - - The following MessagePack types are not used in the conversion: float 32 (0xCA) - !!! info "NaN/infinity handling" If NaN or Infinity are stored inside a JSON number, they are serialized properly. function which serializes NaN or Infinity to `null`. diff --git a/doc/mkdocs/docs/features/binary_formats/ubjson.md b/doc/mkdocs/docs/features/binary_formats/ubjson.md index cb01cfde..050b4ec5 100644 --- a/doc/mkdocs/docs/features/binary_formats/ubjson.md +++ b/doc/mkdocs/docs/features/binary_formats/ubjson.md @@ -28,6 +28,7 @@ number_unsigned | 128..255 | uint8 | `U` number_unsigned | 256..32767 | int16 | `I` number_unsigned | 32768..2147483647 | int32 | `l` number_unsigned | 2147483648..9223372036854775807 | int64 | `L` +number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` number_float | *any value* | float64 | `D` string | *with shortest length indicator* | string | `S` array | *see notes on optimized format* | array | `[` @@ -44,7 +45,6 @@ object | *see notes on optimized format* | map | `{` The following values can **not** be converted to a UBJSON value: - strings with more than 9223372036854775807 bytes (theoretical) - - unsigned integer numbers above 9223372036854775807 !!! info "Unused UBJSON markers" diff --git a/doc/mkdocs/docs/features/binary_values.md b/doc/mkdocs/docs/features/binary_values.md index e268a5b5..4716aac7 100644 --- a/doc/mkdocs/docs/features/binary_values.md +++ b/doc/mkdocs/docs/features/binary_values.md @@ -158,14 +158,14 @@ JSON does not have a binary type, and this library does not introduce a new type ### CBOR -[CBOR](binary_formats/cbor.md) supports binary values, but no subtypes. Any binary value will be serialized as byte strings. The library will choose the smallest representation using the length of the byte array. +[CBOR](binary_formats/cbor.md) supports binary values, but no subtypes. Subtypes will be serialized as tags. Any binary value will be serialized as byte strings. The library will choose the smallest representation using the length of the byte array. ??? example Code: ```cpp - // create a binary value of subtype 42 (will be ignored by CBOR) + // create a binary value of subtype 42 json j; j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42); @@ -173,17 +173,18 @@ JSON does not have a binary type, and this library does not introduce a new type auto v = json::to_cbor(j); ``` - `v` is a `std::vector` with the following 13 elements: + `v` is a `std::vector` with the following 15 elements: ```c 0xA1 // map(1) 0x66 // text(6) 0x62 0x69 0x6E 0x61 0x72 0x79 // "binary" + 0xD8 0x2A // tag(42) 0x44 // bytes(4) 0xCA 0xFE 0xBA 0xBE // content ``` - Note the subtype (42) is **not** serialized, and deserializing `v` would yield the following value: + Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless `json::cbor_tag_handler_t::ignore` is passed to `json::from_cbor`. ```json { diff --git a/doc/mkdocs/docs/features/comments.md b/doc/mkdocs/docs/features/comments.md new file mode 100644 index 00000000..f82029ee --- /dev/null +++ b/doc/mkdocs/docs/features/comments.md @@ -0,0 +1,83 @@ +# Comments + +This library does not support comments *by default*. It does so for three reasons: + +1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. +2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: + + > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. + + > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. + +3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. + +However, you can pass set parameter `ignore_comments` to `#!c true` in the parse function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. + +!!! example + + Consider the following JSON with comments. + + ```json + { + // update in 2006: removed Pluto + "planets": ["Mercury", "Venus", "Earth", "Mars", + "Jupiter", "Uranus", "Neptune" /*, "Pluto" */] + } + ``` + + When calling `parse` without additional argument, a parse error exception is thrown. If `skip_comments` is set to `#! true`, the comments are skipped during parsing: + + ```cpp + #include + #include "json.hpp" + + using json = nlohmann::json; + + int main() + { + std::string s = R"( + { + // update in 2006: removed Pluto + "planets": ["Mercury", "Venus", "Earth", "Mars", + "Jupiter", "Uranus", "Neptune" /*, "Pluto" */] + } + )"; + + try + { + json j = json::parse(s); + } + catch (json::exception &e) + { + std::cout << e.what() << std::endl; + } + + json j = json::parse(s, + /* callback */ nullptr, + /* allow exceptions */ true, + /* skip_comments */ true); + std::cout << j.dump(2) << '\n'; + } + ``` + + Output: + + ``` + [json.exception.parse_error.101] parse error at line 3, column 9: + syntax error while parsing object key - invalid literal; + last read: ' { /'; expected string literal + ``` + + ```json + { + "planets": [ + "Mercury", + "Venus", + "Earth", + "Mars", + "Jupiter", + "Uranus", + "Neptune" + ] + } + ``` \ No newline at end of file diff --git a/doc/mkdocs/docs/features/element_access/checked_access.md b/doc/mkdocs/docs/features/element_access/checked_access.md new file mode 100644 index 00000000..095dff2d --- /dev/null +++ b/doc/mkdocs/docs/features/element_access/checked_access.md @@ -0,0 +1,77 @@ +# Checked access: at + +## Overview + +The `#!cpp at()` member function performs checked access; that is, it returns a reference to the desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) otherwise. + +??? example + + Consider the following JSON value: + + ```json + { + "name": "Mary Smith", + "age": 42, + "hobbies": ["hiking", "reading"] + } + ``` + + Assume the value is parsed to a `json` variable `j`. + + | expression | value | + | ---------- | ----- | + | `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` | + | `#!cpp j.at("name")` | `#!json "Mary Smith"` | + | `#!cpp j.at("age")` | `#!json 42` | + | `#!cpp j.at("hobbies")` | `#!json ["hiking", "reading"]` | + | `#!cpp j.at("hobbies").at(0)` | `#!json "hiking"` | + | `#!cpp j.at("hobbies").at(1)` | `#!json "reading"` | + +The return value is a reference, so it can be modify the original value. + +??? example + + ```cpp + j.at("name") = "John Smith"; + ``` + + This code produces the following JSON value: + + ```json + { + "name": "John Smith", + "age": 42, + "hobbies": ["hiking", "reading"] + } + ``` + +When accessing an invalid index (i.e., and index greater than or equal to the array size) or the passed object key is non-existing, an exception is thrown. + +??? example + + ```cpp + j.at("hobbies").at(3) = "cooking"; + ``` + + This code produces the following exception: + + ``` + [json.exception.out_of_range.401] array index 3 is out of range + ``` + +## Notes + + +!!! failure "Exceptions" + + - `at` can only be used with objects (with a string argument) or with arrays (with a numeric argument). For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error304) is thrown. + - [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) exceptions are thrown if the provided key is not found in an object or the provided index is invalid. + +## Summary + +| scenario | non-const value | const value | +| -------- | ------------- | ----------- | +| access to existing object key | reference to existing value is returned | const reference to existing value is returned | +| access to valid array index | reference to existing value is returned | const reference to existing value is returned | +| access to non-existing object key | `basic_json::out_of_range` exception is thrown | `basic_json::out_of_range` exception is thrown | +| access to invalid array index | `basic_json::out_of_range` exception is thrown | `basic_json::out_of_range` exception is thrown | diff --git a/doc/mkdocs/docs/features/element_access/default_value.md b/doc/mkdocs/docs/features/element_access/default_value.md new file mode 100644 index 00000000..02b4fea3 --- /dev/null +++ b/doc/mkdocs/docs/features/element_access/default_value.md @@ -0,0 +1,32 @@ +# Access with default value: value + +## Overview + +In many situations such as configuration files, missing values are not exceptional, but may be treated as if a default value was present. + +??? example + + Consider the following JSON value: + + ```json + { + "logOutput": "result.log", + "append": true + } + ``` + + Assume the value is parsed to a `json` variable `j`. + + | expression | value | + | ---------- | ----- | + | `#!cpp j` | `#!json {"logOutput": "result.log", "append": true}` | + | `#!cpp j.value("logOutput", "logfile.log")` | `#!json "result.log"` | + | `#!cpp j.value("append", true)` | `#!json true` | + | `#!cpp j.value("append", false)` | `#!json true` | + | `#!cpp j.value("logLevel", "verbose")` | `#!json "verbose"` | + +## Note + +!!! failure "Exceptions" + + - `value` can only be used with objects. For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error306) is thrown. diff --git a/doc/mkdocs/docs/features/element_access/index.md b/doc/mkdocs/docs/features/element_access/index.md new file mode 100644 index 00000000..1755fe8c --- /dev/null +++ b/doc/mkdocs/docs/features/element_access/index.md @@ -0,0 +1,9 @@ +# Overview + +There are many ways elements in a JSON value can be accessed: + +- unchecked access via [`operator[]`](unchecked_access.md) +- checked access via [`at`](checked_access.md) +- access with default value via [`value`](default_value.md) +- iterators +- JSON pointers diff --git a/doc/mkdocs/docs/features/element_access/unchecked_access.md b/doc/mkdocs/docs/features/element_access/unchecked_access.md new file mode 100644 index 00000000..f8667c81 --- /dev/null +++ b/doc/mkdocs/docs/features/element_access/unchecked_access.md @@ -0,0 +1,102 @@ +# Unchecked access: operator[] + +## Overview + +Elements in a JSON object and a JSON array can be accessed via `#!cpp operator[]` similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively. + +??? example + + Consider the following JSON value: + + ```json + { + "name": "Mary Smith", + "age": 42, + "hobbies": ["hiking", "reading"] + } + ``` + + Assume the value is parsed to a `json` variable `j`. + + | expression | value | + | ---------- | ----- | + | `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` | + | `#!cpp j["name"]` | `#!json "Mary Smith"` | + | `#!cpp j["age"]` | `#!json 42` | + | `#!cpp j["hobbies"]` | `#!json ["hiking", "reading"]` | + | `#!cpp j["hobbies"][0]` | `#!json "hiking"` | + | `#!cpp j["hobbies"][1]` | `#!json "reading"` | + +The return value is a reference, so it can be modify the original value. In case the passed object key is non-existing, a `#!json null` value is inserted which can be immediately be overwritten. + +??? example + + ```cpp + j["name"] = "John Smith"; + j["maidenName"] = "Jones"; + ``` + + This code produces the following JSON value: + + ```json + { + "name": "John Smith", + "maidenName": "Jones", + "age": 42, + "hobbies": ["hiking", "reading"] + } + ``` + +When accessing an invalid index (i.e., and index greater than or equal to the array size), the JSON array is resized such that the passed index is the new maximal index. Intermediate values are filled with `#!json null`. + +??? example + + ```cpp + j["hobbies"][0] = "running"; + j["hobbies"][3] = "cooking"; + ``` + + This code produces the following JSON value: + + ```json + { + "name": "John Smith", + "maidenName": "Jones", + "age": 42, + "hobbies": ["running", "reading", null, "cooking"] + } + ``` + +## Notes + +!!! info "Design rationale" + + The library behaves differently to `#!cpp std::vector` and `#!cpp std::map`: + + - `#!cpp std::vector::operator[]` never inserts a new element. + - `#!cpp std::map::operator[]` is not available for const values. + + The type `#!cpp json` wraps all JSON value types. It would be impossible to remove `operator[]` for const objects. At the same time, inserting elements for non-const objects is really convenient as it avoids awkward `insert` calls. To this end, we decided to have an inserting non-const behavior for both arrays and objects. + +!!! info + + The access is unchecked. In case the passed object key does not exist or the passed array index is invalid, no exception is thrown. + +!!! danger + + - It is **undefined behavior** to access a const object with a non-existing key. + - It is **undefined behavior** to access a const array with an invalid index. + - In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx). + +!!! failure "Exceptions" + + `operator[]` can only be used with objects (with a string argument) or with arrays (with a numeric argument). For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error305) is thrown. + +## Summary + +| scenario | non-const value | const value | +| -------- | ------------- | ----------- | +| access to existing object key | reference to existing value is returned | const reference to existing value is returned | +| access to valid array index | reference to existing value is returned | const reference to existing value is returned | +| access to non-existing object key | reference to newly inserted `#!json null` value is returned | **undefined behavior**; assertion in debug mode | +| access to invalid array index | reference to newly inserted `#!json null` value is returned; any index between previous maximal index and passed index are filled with `#!json null` | **undefined behavior**; assertion in debug mode | diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md new file mode 100644 index 00000000..696438d2 --- /dev/null +++ b/doc/mkdocs/docs/features/macros.md @@ -0,0 +1,79 @@ +# Supported Macros + +Some aspects of the library can be configured by defining preprocessor macros before including the `json.hpp` header. + +## `JSON_ASSERT(x)` + +The default value is `#!cpp assert(x)`. + +## `JSON_CATCH_USER(exception)` + +This macro overrides `#!cpp catch` calls inside the library. The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range` exceptions internally to rethrow them as [`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The macro is always followed by a scope. + +See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. + +## `JSON_NOEXCEPTION` + +Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. +When defining `JSON_NOEXCEPTION`, `#!cpp try` is replaced by `#!cpp if (true)`, +`#!cpp catch` is replaced by `#!cpp if (false)`, and `#!cpp throw` is replaced by `#!cpp std::abort()`. + +The same effect is achieved by setting the compiler flag `-fno-exceptions`. + +## `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK` + +When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used. + +## `JSON_THROW_USER(exception)` + +This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. + +See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. + +## `JSON_TRY_USER` + +This macro overrides `#!cpp try` calls inside the library. It has no arguments and is always followed by a scope. + +See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. + +## `JSON_USE_IMPLICIT_CONVERSIONS` + +When defined to `0`, implicit conversions are switched off. By default, implicit conversions are switched on. + +??? example + + This is an example for an implicit conversion: + + ```cpp + json j = "Hello, world!"; + std::string s = j; + ``` + + When `JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`, the code above does no longer compile. Instead, it must be written like this: + + ```cpp + json j = "Hello, world!"; + auto s = j.get(); + ``` + +## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)` + +This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object. + +The macro is to be defined inside of the class/struct to create code for. Unlike [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](#nlohmann_define_type_non_intrusivetype-member), it can access private members. +The first parameter is the name of the class/struct, and all remaining parameters name the members. + +See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. + +## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)` + +This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object. + +The macro is to be defined inside of the namespace of the class/struct to create code for. Private members cannot be accessed. Use [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](#nlohmann_define_type_intrusivetype-member) in these scenarios. +The first parameter is the name of the class/struct, and all remaining parameters name the members. + +See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. + +## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)` + +This macro simplifies the serialization/deserialization of enum types. See [Specializing enum conversion](enum_conversion.md) for more information. diff --git a/doc/mkdocs/docs/features/object_order.md b/doc/mkdocs/docs/features/object_order.md new file mode 100644 index 00000000..86bb253b --- /dev/null +++ b/doc/mkdocs/docs/features/object_order.md @@ -0,0 +1,67 @@ +# Object Order + +The [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". As such, an implementation does not need to preserve any specific order of object keys. + +The default type `nlohmann::json` uses a `std::map` to store JSON objects, and thus stores object keys **sorted alphabetically**. + +??? example + + ```cpp + #include + #include "json.hpp" + + using json = nlohmann::json; + + int main() + { + json j; + j["one"] = 1; + j["two"] = 2; + j["three"] = 3; + + std::cout << j.dump(2) << '\n'; + } + ``` + + Output: + + ```json + { + "one": 1, + "three": 3, + "two": 2 + } + ``` + +If you do want to preserve the **insertion order**, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). + +??? example + + ```cpp + #include + #include + + using ordered_json = nlohmann::ordered_json; + + int main() + { + ordered_json j; + j["one"] = 1; + j["two"] = 2; + j["three"] = 3; + + std::cout << j.dump(2) << '\n'; + } + ``` + + Output: + + ```json + { + "one": 1, + "two": 2, + "three": 3 + } + ``` + +Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). diff --git a/doc/mkdocs/docs/features/parsing/sax_interface.md b/doc/mkdocs/docs/features/parsing/sax_interface.md index ef83a532..73153482 100644 --- a/doc/mkdocs/docs/features/parsing/sax_interface.md +++ b/doc/mkdocs/docs/features/parsing/sax_interface.md @@ -14,6 +14,7 @@ interface json::sax_t { + {abstract} bool number_float(number_float_t val, const string_t& s) + {abstract} bool string(string_t& val) + + {abstract} bool binary(binary_t& val) + {abstract} bool start_object(std::size_t elements) + {abstract} bool end_object() @@ -41,6 +42,8 @@ bool number_float(number_float_t val, const string_t& s); // called when a string is parsed; value is passed and can be safely moved away bool string(string_t& val); +// called when a binary value is parsed; value is passed and can be safely moved away +bool binary(binary& val); // called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) bool start_object(std::size_t elements); diff --git a/doc/mkdocs/docs/home/exceptions.md b/doc/mkdocs/docs/home/exceptions.md index 92dfb43b..e1e1d13b 100644 --- a/doc/mkdocs/docs/home/exceptions.md +++ b/doc/mkdocs/docs/home/exceptions.md @@ -32,6 +32,24 @@ Exceptions are used widely within the library. They can, however, be switched of Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. +??? example + + The code below switches off exceptions and creates a log entry with a detailed error message in case of errors. + + ```cpp + #include + + #define JSON_TRY_USER if(true) + #define JSON_CATCH_USER(exception) if(false) + #define JSON_THROW_USER(exception) \ + {std::clog << "Error in " << __FILE__ << ":" << __LINE__ \ + << " (function " << __FUNCTION__ << ") - " \ + << (exception).what() << std::endl; \ + std::abort();} + + #include + ``` + ## Parse errors This exception is thrown by the library when a parse error occurs. Parse errors @@ -261,6 +279,16 @@ The parsing of the corresponding BSON record type is not implemented (yet). [json.exception.parse_error.114] parse error at byte 5: Unsupported BSON record type 0xFF ``` +### json.exception.parse_error.115 + +A UBJSON high-precision number could not be parsed. + +!!! failure "Example message" + + ``` + [json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A + ``` + ## Iterator errors This exception is thrown if iterators passed to a library function do not match @@ -747,6 +775,10 @@ UBJSON and BSON only support integer numbers up to 9223372036854775807. number overflow serializing '9223372036854775808' ``` +!!! note + + Since version 3.9.0, integer numbers beyond int64 are serialized as high-precision UBJSON numbers, and this exception does not further occur. + ### json.exception.out_of_range.408 The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. diff --git a/doc/mkdocs/docs/home/faq.md b/doc/mkdocs/docs/home/faq.md index a9b5af08..af63cfb6 100644 --- a/doc/mkdocs/docs/home/faq.md +++ b/doc/mkdocs/docs/home/faq.md @@ -2,31 +2,6 @@ ## Limitations -### Comments - -!!! question "Questions" - - - Why does the library not support comments? - - Can you add support for JSON5/JSONC/HOCON so that comments are supported? - -This library does not support comments. It does so for three reasons: - -1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. -2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: - - > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. - - > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. - -3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. - -This library will not support comments in the future. If you wish to use comments, I see three options: - -1. Strip comments before using this library. -2. Use a different JSON library with comment support. -3. Use a format that natively supports comments (e.g., YAML or JSON5). - - ### Relaxed parsing !!! question @@ -69,18 +44,6 @@ No, this is not possible. See for ## Serialization issues -### Order of object keys - -!!! question "Questions" - - - Why are object keys sorted? - - Why is the insertion order of object keys not preserved? - -By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". - -If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). - - ### Number precision !!! question diff --git a/doc/mkdocs/docs/home/license.md b/doc/mkdocs/docs/home/license.md index 9211eddd..f7d0aa82 100644 --- a/doc/mkdocs/docs/home/license.md +++ b/doc/mkdocs/docs/home/license.md @@ -4,7 +4,7 @@ The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): -Copyright © 2013-2019 [Niels Lohmann](http://nlohmann.me) +Copyright © 2013-2020 [Niels Lohmann](http://nlohmann.me) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/doc/mkdocs/docs/hooks.py b/doc/mkdocs/docs/hooks.py index a04a7c53..8fee8397 100644 --- a/doc/mkdocs/docs/hooks.py +++ b/doc/mkdocs/docs/hooks.py @@ -3,5 +3,8 @@ import os.path def copy_doxygen(*args, **kwargs): - shutil.copytree('../html', os.path.join(kwargs['config']['site_dir'], 'doxygen')) - print('Copy Doxygen complete') + doxygen_dir = os.path.join(kwargs['config']['site_dir'], 'doxygen') + if not os.path.isdir(doxygen_dir) or not os.listdir(doxygen_dir): + print('Copy Doxygen files...') + shutil.copytree('../html', doxygen_dir) + print('Copy Doxygen complete') diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml index 5d6e3b4e..2837e8ca 100644 --- a/doc/mkdocs/mkdocs.yml +++ b/doc/mkdocs/mkdocs.yml @@ -44,16 +44,24 @@ nav: - features/binary_formats/messagepack.md - features/binary_formats/ubjson.md - features/binary_values.md + - features/comments.md + - Element Access: + - features/element_access/index.md + - features/element_access/unchecked_access.md + - features/element_access/checked_access.md + - features/element_access/default_value.md - features/iterators.md - features/json_pointer.md - features/json_patch.md - features/merge_patch.md - - features/enum_conversion.md + - features/object_order.md - Parsing: - - features/parsing/index.md - - features/parsing/parse_exceptions.md - - features/parsing/parser_callbacks.md - - features/parsing/sax_interface.md + - features/parsing/index.md + - features/parsing/parse_exceptions.md + - features/parsing/parser_callbacks.md + - features/parsing/sax_interface.md + - features/enum_conversion.md + - features/macros.md - features/types.md - Integration: - integration/index.md @@ -61,6 +69,12 @@ nav: - integration/package_managers.md - Doxygen: - doxygen/index.html + - API: + - basic_json: + - api/basic_json/index.md + - api/basic_json/dump.md + - api/basic_json/meta.md + - api/basic_json/parse.md # Extras extra: @@ -79,6 +93,7 @@ extra: # Extensions markdown_extensions: - admonition + - def_list - codehilite: guess_lang: false - toc: diff --git a/include/nlohmann/adl_serializer.hpp b/include/nlohmann/adl_serializer.hpp index eeaa1425..4af1c4bb 100644 --- a/include/nlohmann/adl_serializer.hpp +++ b/include/nlohmann/adl_serializer.hpp @@ -37,7 +37,7 @@ struct adl_serializer @param[in,out] j JSON value to write to @param[in] val value to read from */ - template + template static auto to_json(BasicJsonType& j, ValueType&& val) noexcept( noexcept(::nlohmann::to_json(j, std::forward(val)))) -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) diff --git a/include/nlohmann/detail/boolean_operators.hpp b/include/nlohmann/detail/boolean_operators.hpp deleted file mode 100644 index 06335866..00000000 --- a/include/nlohmann/detail/boolean_operators.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// Header is removed in C++20. -// See for more information. - -#if __cplusplus <= 201703L - #include // and, not, or -#endif diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index e8731f22..438b84a2 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -12,7 +12,6 @@ #include // pair, declval #include // valarray -#include #include #include #include @@ -26,7 +25,7 @@ namespace detail template void from_json(const BasicJsonType& j, typename std::nullptr_t& n) { - if (JSON_HEDLEY_UNLIKELY(not j.is_null())) + if (JSON_HEDLEY_UNLIKELY(!j.is_null())) { JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); } @@ -34,10 +33,10 @@ void from_json(const BasicJsonType& j, typename std::nullptr_t& n) } // overloads for basic_json template parameters -template::value and - not std::is_same::value, - int> = 0> +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < std::is_arithmetic::value&& + !std::is_same::value, + int > = 0 > void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) { switch (static_cast(j)) @@ -66,7 +65,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) template void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) { - if (JSON_HEDLEY_UNLIKELY(not j.is_boolean())) + if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) { JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); } @@ -76,7 +75,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) template void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) { - if (JSON_HEDLEY_UNLIKELY(not j.is_string())) + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); } @@ -86,13 +85,13 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) template < typename BasicJsonType, typename ConstructibleStringType, enable_if_t < - is_constructible_string_type::value and - not std::is_same::value, + is_constructible_string_type::value&& + !std::is_same::value, int > = 0 > void from_json(const BasicJsonType& j, ConstructibleStringType& s) { - if (JSON_HEDLEY_UNLIKELY(not j.is_string())) + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); } @@ -129,10 +128,10 @@ void from_json(const BasicJsonType& j, EnumType& e) // forward_list doesn't have an insert method template::value, int> = 0> + enable_if_t::value, int> = 0> void from_json(const BasicJsonType& j, std::forward_list& l) { - if (JSON_HEDLEY_UNLIKELY(not j.is_array())) + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } @@ -146,18 +145,22 @@ void from_json(const BasicJsonType& j, std::forward_list& l) // valarray doesn't have an insert method template::value, int> = 0> + enable_if_t::value, int> = 0> void from_json(const BasicJsonType& j, std::valarray& l) { - if (JSON_HEDLEY_UNLIKELY(not j.is_array())) + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } l.resize(j.size()); - std::copy(j.begin(), j.end(), std::begin(l)); + std::transform(j.begin(), j.end(), std::begin(l), + [](const BasicJsonType & elem) + { + return elem.template get(); + }); } -template +template auto from_json(const BasicJsonType& j, T (&arr)[N]) -> decltype(j.template get(), void()) { @@ -173,7 +176,7 @@ void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_ arr = *j.template get_ptr(); } -template +template auto from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) -> decltype(j.template get(), void()) @@ -205,7 +208,7 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p arr = std::move(ret); } -template +template void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<0> /*unused*/) { @@ -223,20 +226,20 @@ void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, arr = std::move(ret); } -template ::value and - not is_constructible_object_type::value and - not is_constructible_string_type::value and - not std::is_same::value and - not is_basic_json::value, - int > = 0 > +template < typename BasicJsonType, typename ConstructibleArrayType, + enable_if_t < + is_constructible_array_type::value&& + !is_constructible_object_type::value&& + !is_constructible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), j.template get(), void()) { - if (JSON_HEDLEY_UNLIKELY(not j.is_array())) + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); @@ -245,10 +248,10 @@ void()) from_json_array_impl(j, arr, priority_tag<3> {}); } -template +template void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) { - if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) + if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) { JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); } @@ -260,7 +263,7 @@ template::value, int> = 0> void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) { - if (JSON_HEDLEY_UNLIKELY(not j.is_object())) + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); } @@ -282,14 +285,14 @@ void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) // (BooleanType, etc..); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? -template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value, - int> = 0> +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < + std::is_arithmetic::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value, + int > = 0 > void from_json(const BasicJsonType& j, ArithmeticType& val) { switch (static_cast(j)) @@ -338,19 +341,19 @@ void from_json(const BasicJsonType& j, std::tuple& t) from_json_tuple_impl(j, t, index_sequence_for {}); } -template ::value>> +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) { - if (JSON_HEDLEY_UNLIKELY(not j.is_array())) + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } m.clear(); for (const auto& p : j) { - if (JSON_HEDLEY_UNLIKELY(not p.is_array())) + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); } @@ -358,19 +361,19 @@ void from_json(const BasicJsonType& j, std::map& } } -template ::value>> +template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::unordered_map& m) { - if (JSON_HEDLEY_UNLIKELY(not j.is_array())) + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } m.clear(); for (const auto& p : j) { - if (JSON_HEDLEY_UNLIKELY(not p.is_array())) + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); } diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index 5851fd0a..c632ff2b 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -1,14 +1,12 @@ #pragma once #include // array -#include // assert #include // signbit, isfinite #include // intN_t, uintN_t #include // memcpy, memmove #include // numeric_limits #include // conditional -#include #include namespace nlohmann @@ -38,7 +36,7 @@ For a detailed description of the algorithm see: namespace dtoa_impl { -template +template Target reinterpret_bits(const Source source) { static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); @@ -63,8 +61,8 @@ struct diyfp // f * 2^e */ static diyfp sub(const diyfp& x, const diyfp& y) noexcept { - assert(x.e == y.e); - assert(x.f >= y.f); + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); return {x.f - y.f, x.e}; } @@ -140,7 +138,7 @@ struct diyfp // f * 2^e */ static diyfp normalize(diyfp x) noexcept { - assert(x.f != 0); + JSON_ASSERT(x.f != 0); while ((x.f >> 63u) == 0) { @@ -159,8 +157,8 @@ struct diyfp // f * 2^e { const int delta = x.e - target_exponent; - assert(delta >= 0); - assert(((x.f << delta) >> delta) == x.f); + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); return {x.f << delta, target_exponent}; } @@ -179,11 +177,11 @@ boundaries. @pre value must be finite and positive */ -template +template boundaries compute_boundaries(FloatType value) { - assert(std::isfinite(value)); - assert(value > 0); + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); // Convert the IEEE representation into a diyfp. // @@ -232,7 +230,7 @@ boundaries compute_boundaries(FloatType value) // -----------------+------+------+-------------+-------------+--- (B) // v- m- v m+ v+ - const bool lower_boundary_is_closer = F == 0 and E > 1; + const bool lower_boundary_is_closer = F == 0 && E > 1; const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); const diyfp m_minus = lower_boundary_is_closer ? diyfp(4 * v.f - 1, v.e - 2) // (B) @@ -463,18 +461,18 @@ inline cached_power get_cached_power_for_binary_exponent(int e) // k = ceil((kAlpha - e - 1) * 0.30102999566398114) // for |e| <= 1500, but doesn't require floating-point operations. // NB: log_10(2) ~= 78913 / 2^18 - assert(e >= -1500); - assert(e <= 1500); + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; - assert(index >= 0); - assert(static_cast(index) < kCachedPowers.size()); + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); const cached_power cached = kCachedPowers[static_cast(index)]; - assert(kAlpha <= cached.e + e + 64); - assert(kGamma >= cached.e + e + 64); + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); return cached; } @@ -542,10 +540,10 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, std::uint64_t rest, std::uint64_t ten_k) { - assert(len >= 1); - assert(dist <= delta); - assert(rest <= delta); - assert(ten_k > 0); + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); // <--------------------------- delta ----> // <---- dist ---------> @@ -567,10 +565,10 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d // integer arithmetic. while (rest < dist - and delta - rest >= ten_k - and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) { - assert(buf[len - 1] != '0'); + JSON_ASSERT(buf[len - 1] != '0'); buf[len - 1]--; rest += ten_k; } @@ -598,8 +596,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // Grisu2 generates the digits of M+ from left to right and stops as soon as // V is in [M-,M+]. - assert(M_plus.e >= kAlpha); - assert(M_plus.e <= kGamma); + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) @@ -620,7 +618,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] - assert(p1 > 0); + JSON_ASSERT(p1 > 0); std::uint32_t pow10; const int k = find_largest_pow10(p1, pow10); @@ -656,7 +654,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // - assert(d <= 9); + JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) @@ -743,7 +741,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // // and stop as soon as 10^-m * r * 2^e <= delta * 2^e - assert(p2 > delta); + JSON_ASSERT(p2 > delta); int m = 0; for (;;) @@ -754,7 +752,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e // - assert(p2 <= (std::numeric_limits::max)() / 10); + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); p2 *= 10; const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e @@ -763,7 +761,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e // - assert(d <= 9); + JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e @@ -824,8 +822,8 @@ JSON_HEDLEY_NON_NULL(1) inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus) { - assert(m_plus.e == m_minus.e); - assert(m_plus.e == v.e); + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); // --------(-----------------------+-----------------------)-------- (A) // m- v m+ @@ -879,15 +877,15 @@ v = buf * 10^decimal_exponent len is the length of the buffer (number of decimal digits) The buffer must be large enough, i.e. >= max_digits10. */ -template +template JSON_HEDLEY_NON_NULL(1) void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) { static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, "internal error: not enough precision"); - assert(std::isfinite(value)); - assert(value > 0); + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); // If the neighbors (and boundaries) of 'value' are always computed for double-precision // numbers, all float's can be recovered using strtod (and strtof). However, the resulting @@ -923,8 +921,8 @@ JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_RETURNS_NON_NULL inline char* append_exponent(char* buf, int e) { - assert(e > -1000); - assert(e < 1000); + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); if (e < 0) { @@ -976,8 +974,8 @@ JSON_HEDLEY_RETURNS_NON_NULL inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp) { - assert(min_exp < 0); - assert(max_exp > 0); + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); const int k = len; const int n = len + decimal_exponent; @@ -986,7 +984,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent, // k is the length of the buffer (number of decimal digits) // n is the position of the decimal point relative to the start of the buffer. - if (k <= n and n <= max_exp) + if (k <= n && n <= max_exp) { // digits[000] // len <= max_exp + 2 @@ -998,19 +996,19 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent, return buf + (static_cast(n) + 2); } - if (0 < n and n <= max_exp) + if (0 < n && n <= max_exp) { // dig.its // len <= max_digits10 + 1 - assert(k > n); + JSON_ASSERT(k > n); std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); buf[n] = '.'; return buf + (static_cast(k) + 1U); } - if (min_exp < n and n <= 0) + if (min_exp < n && n <= 0) { // 0.[000]digits // len <= 2 + (-min_exp - 1) + max_digits10 @@ -1055,13 +1053,13 @@ format. Returns an iterator pointing past-the-end of the decimal representation. @note The buffer must be large enough. @note The result is NOT null-terminated. */ -template +template JSON_HEDLEY_NON_NULL(1, 2) JSON_HEDLEY_RETURNS_NON_NULL char* to_chars(char* first, const char* last, FloatType value) { static_cast(last); // maybe unused - fix warning - assert(std::isfinite(value)); + JSON_ASSERT(std::isfinite(value)); // Use signbit(value) instead of (value < 0) since signbit works for -0. if (std::signbit(value)) @@ -1079,7 +1077,7 @@ char* to_chars(char* first, const char* last, FloatType value) return first; } - assert(last - first >= std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); // Compute v = buffer * 10^decimal_exponent. // The decimal digits are stored in the buffer, which needs to be interpreted @@ -1089,16 +1087,16 @@ char* to_chars(char* first, const char* last, FloatType value) int decimal_exponent = 0; dtoa_impl::grisu2(first, len, decimal_exponent, value); - assert(len <= std::numeric_limits::max_digits10); + JSON_ASSERT(len <= std::numeric_limits::max_digits10); // Format the buffer like printf("%.*g", prec, value) constexpr int kMinExp = -4; // Use digits10 here to increase compatibility with version 2. constexpr int kMaxExp = std::numeric_limits::digits10; - assert(last - first >= kMaxExp + 2); - assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); - assert(last - first >= std::numeric_limits::max_digits10 + 6); + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); } diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index cae779c5..b45004fd 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -9,7 +9,6 @@ #include // valarray #include // vector -#include #include #include #include @@ -56,9 +55,9 @@ struct external_constructor j.assert_invariant(); } - template::value, - int> = 0> + template < typename BasicJsonType, typename CompatibleStringType, + enable_if_t < !std::is_same::value, + int > = 0 > static void construct(BasicJsonType& j, const CompatibleStringType& str) { j.m_type = value_t::string; @@ -144,9 +143,9 @@ struct external_constructor j.assert_invariant(); } - template::value, - int> = 0> + template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < !std::is_same::value, + int > = 0 > static void construct(BasicJsonType& j, const CompatibleArrayType& arr) { using std::begin; @@ -203,8 +202,8 @@ struct external_constructor j.assert_invariant(); } - template::value, int> = 0> + template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < !std::is_same::value, int > = 0 > static void construct(BasicJsonType& j, const CompatibleObjectType& obj) { using std::begin; @@ -275,20 +274,20 @@ void to_json(BasicJsonType& j, const std::vector& e) external_constructor::construct(j, e); } -template ::value and - not is_compatible_object_type::value and - not is_compatible_string_type::value and - not std::is_same::value and - not is_basic_json::value, - int> = 0> +template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < is_compatible_array_type::value&& + !is_compatible_object_type::value&& + !is_compatible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor::construct(j, arr); } -template +template void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) { external_constructor::construct(j, bin); @@ -307,8 +306,8 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) external_constructor::construct(j, std::move(arr)); } -template::value and not is_basic_json::value, int> = 0> +template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > void to_json(BasicJsonType& j, const CompatibleObjectType& obj) { external_constructor::construct(j, obj); @@ -322,9 +321,9 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) template < typename BasicJsonType, typename T, std::size_t N, - enable_if_t::value, - int> = 0 > + enable_if_t < !std::is_constructible::value, + int > = 0 > void to_json(BasicJsonType& j, const T(&arr)[N]) { external_constructor::construct(j, arr); @@ -337,8 +336,8 @@ void to_json(BasicJsonType& j, const std::pair& p) } // for https://github.com/nlohmann/json/pull/1134 -template < typename BasicJsonType, typename T, - enable_if_t>::value, int> = 0> +template>::value, int> = 0> void to_json(BasicJsonType& j, const T& b) { j = { {b.key(), b.value()} }; diff --git a/include/nlohmann/detail/exceptions.hpp b/include/nlohmann/detail/exceptions.hpp index ed836188..dd92897d 100644 --- a/include/nlohmann/detail/exceptions.hpp +++ b/include/nlohmann/detail/exceptions.hpp @@ -97,6 +97,7 @@ json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vect json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). +json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also @@ -285,7 +286,7 @@ json.exception.out_of_range.403 | key 'foo' not found | The provided key was not json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. -json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | diff --git a/include/nlohmann/detail/hash.hpp b/include/nlohmann/detail/hash.hpp new file mode 100644 index 00000000..4094cc94 --- /dev/null +++ b/include/nlohmann/detail/hash.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include // size_t, uint8_t +#include // hash + +namespace nlohmann +{ +namespace detail +{ + +// boost::hash_combine +inline std::size_t combine(std::size_t seed, std::size_t h) noexcept +{ + seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); + return seed; +} + +/*! +@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. + +@tparam BasicJsonType basic_json specialization +@param j JSON value to hash +@return hash value of j +*/ +template +std::size_t hash(const BasicJsonType& j) +{ + 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()); + switch (j.type()) + { + case BasicJsonType::value_t::null: + case BasicJsonType::value_t::discarded: + { + return combine(type, 0); + } + + case BasicJsonType::value_t::object: + { + auto seed = combine(type, j.size()); + for (const auto& element : j.items()) + { + const auto h = std::hash {}(element.key()); + seed = combine(seed, h); + seed = combine(seed, hash(element.value())); + } + return seed; + } + + case BasicJsonType::value_t::array: + { + auto seed = combine(type, j.size()); + for (const auto& element : j) + { + seed = combine(seed, hash(element)); + } + return seed; + } + + case BasicJsonType::value_t::string: + { + const auto h = std::hash {}(j.template get_ref()); + return combine(type, h); + } + + case BasicJsonType::value_t::boolean: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_integer: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::number_unsigned: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::number_float: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::binary: + { + auto seed = combine(type, j.get_binary().size()); + const auto h = std::hash {}(j.get_binary().has_subtype()); + seed = combine(seed, h); + seed = combine(seed, j.get_binary().subtype()); + for (const auto byte : j.get_binary()) + { + seed = combine(seed, std::hash {}(byte)); + } + return seed; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } +} + +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 93667e8f..4c94d1cc 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2,7 +2,6 @@ #include // generate_n #include // array -#include // assert #include // ldexp #include // size_t #include // uint8_t, uint16_t, uint32_t, uint64_t @@ -16,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +25,13 @@ namespace nlohmann namespace detail { +/// how to treat CBOR tags +enum class cbor_tag_handler_t +{ + error, ///< throw a parse_error exception in case of a tag + ignore ///< ignore tags +}; + /*! @brief determine system byte order @@ -79,13 +86,15 @@ class binary_reader @param[in] format the binary format to parse @param[in] sax_ a SAX event processor @param[in] strict whether to expect the input to be consumed completed + @param[in] tag_handler how to treat CBOR tags @return */ JSON_HEDLEY_NON_NULL(3) bool sax_parse(const input_format_t format, json_sax_t* sax_, - const bool strict = true) + const bool strict = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { sax = sax_; bool result = false; @@ -97,7 +106,7 @@ class binary_reader break; case input_format_t::cbor: - result = parse_cbor_internal(); + result = parse_cbor_internal(true, tag_handler); break; case input_format_t::msgpack: @@ -109,11 +118,11 @@ class binary_reader break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } // strict mode: next byte must be EOF - if (result and strict) + if (result && strict) { if (format == input_format_t::ubjson) { @@ -145,15 +154,15 @@ class binary_reader */ bool parse_bson_internal() { - std::int32_t document_size; + std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/false))) + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) { return false; } @@ -174,7 +183,7 @@ class binary_reader while (true) { get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) { return false; } @@ -184,8 +193,6 @@ class binary_reader } *out++ = static_cast(current); } - - return true; } /*! @@ -208,7 +215,7 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"))); } - return get_string(input_format_t::bson, len - static_cast(1), result) and get() != std::char_traits::eof(); + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); } /*! @@ -230,7 +237,7 @@ class binary_reader } // All BSON binary values have a subtype - std::uint8_t subtype; + std::uint8_t subtype{}; get_number(input_format_t::bson, subtype); result.set_subtype(subtype); @@ -254,15 +261,15 @@ class binary_reader { case 0x01: // double { - double number; - return get_number(input_format_t::bson, number) and sax->number_float(static_cast(number), ""); + double number{}; + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); } case 0x02: // string { - std::int32_t len; + std::int32_t len{}; string_t value; - return get_number(input_format_t::bson, len) and get_bson_string(len, value) and sax->string(value); + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); } case 0x03: // object @@ -277,9 +284,9 @@ class binary_reader case 0x05: // binary { - std::int32_t len; + std::int32_t len{}; binary_t value; - return get_number(input_format_t::bson, len) and get_bson_binary(len, value) and sax->binary(value); + return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); } case 0x08: // boolean @@ -294,14 +301,14 @@ class binary_reader case 0x10: // int32 { - std::int32_t value; - return get_number(input_format_t::bson, value) and sax->number_integer(value); + std::int32_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); } case 0x12: // int64 { - std::int64_t value; - return get_number(input_format_t::bson, value) and sax->number_integer(value); + std::int64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); } default: // anything else not supported (yet) @@ -331,23 +338,23 @@ class binary_reader while (auto element_type = get()) { - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) { return false; } const std::size_t element_type_parse_position = chars_read; - if (JSON_HEDLEY_UNLIKELY(not get_bson_cstr(key))) + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) { return false; } - if (not is_array and not sax->key(key)) + if (!is_array && !sax->key(key)) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position))) + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) { return false; } @@ -365,15 +372,15 @@ class binary_reader */ bool parse_bson_array() { - std::int32_t document_size; + std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/true))) + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) { return false; } @@ -387,12 +394,14 @@ class binary_reader /*! @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated @return whether a valid CBOR value was passed to the SAX parser */ - bool parse_cbor_internal(const bool get_char = true) + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) { switch (get_char ? get() : current) { @@ -429,26 +438,26 @@ class binary_reader case 0x18: // Unsigned integer (one-byte uint8_t follows) { - std::uint8_t number; - return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } case 0x19: // Unsigned integer (two-byte uint16_t follows) { - std::uint16_t number; - return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } case 0x1A: // Unsigned integer (four-byte uint32_t follows) { - std::uint32_t number; - return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } case 0x1B: // Unsigned integer (eight-byte uint64_t follows) { - std::uint64_t number; - return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } // Negative integer -1-0x00..-1-0x17 (-1..-24) @@ -480,26 +489,26 @@ class binary_reader case 0x38: // Negative integer (one-byte uint8_t follows) { - std::uint8_t number; - return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); } case 0x39: // Negative integer -1-n (two-byte uint16_t follows) { - std::uint16_t number; - return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); } case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) { - std::uint32_t number; - return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); } case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) { - std::uint64_t number; - return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - static_cast(number)); } @@ -535,7 +544,7 @@ class binary_reader case 0x5F: // Binary data (indefinite length) { binary_t b; - return get_cbor_binary(b) and sax->binary(b); + return get_cbor_binary(b) && sax->binary(b); } // UTF-8 string (0x00..0x17 bytes follow) @@ -570,7 +579,7 @@ class binary_reader case 0x7F: // UTF-8 string (indefinite length) { string_t s; - return get_cbor_string(s) and sax->string(s); + return get_cbor_string(s) && sax->string(s); } // array (0x00..0x17 data items follow) @@ -598,34 +607,34 @@ class binary_reader case 0x95: case 0x96: case 0x97: - return get_cbor_array(static_cast(static_cast(current) & 0x1Fu)); + return get_cbor_array(static_cast(static_cast(current) & 0x1Fu), tag_handler); case 0x98: // array (one-byte uint8_t for n follows) { - std::uint8_t len; - return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x99: // array (two-byte uint16_t for n follow) { - std::uint16_t len; - return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x9A: // array (four-byte uint32_t for n follow) { - std::uint32_t len; - return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x9B: // array (eight-byte uint64_t for n follow) { - std::uint64_t len; - return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x9F: // array (indefinite length) - return get_cbor_array(std::size_t(-1)); + return get_cbor_array(std::size_t(-1), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -652,34 +661,101 @@ class binary_reader case 0xB5: case 0xB6: case 0xB7: - return get_cbor_object(static_cast(static_cast(current) & 0x1Fu)); + return get_cbor_object(static_cast(static_cast(current) & 0x1Fu), tag_handler); case 0xB8: // map (one-byte uint8_t for n follows) { - std::uint8_t len; - return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xB9: // map (two-byte uint16_t for n follow) { - std::uint16_t len; - return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xBA: // map (four-byte uint32_t for n follow) { - std::uint32_t len; - return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xBB: // map (eight-byte uint64_t for n follow) { - std::uint64_t len; - return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xBF: // map (indefinite length) - return get_cbor_object(std::size_t(-1)); + return get_cbor_object(std::size_t(-1), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + 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, "invalid byte: 0x" + last_token, "value"))); + } + + case cbor_tag_handler_t::ignore: + { + switch (current) + { + case 0xD8: + { + std::uint8_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xD9: + { + std::uint16_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xDA: + { + std::uint32_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xDB: + { + std::uint64_t len{}; + get_number(input_format_t::cbor, len); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } case 0xF4: // false return sax->boolean(false); @@ -693,12 +769,12 @@ class binary_reader case 0xF9: // Half-Precision Float (two-byte IEEE 754) { const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) { return false; } const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) { return false; } @@ -719,8 +795,8 @@ class binary_reader { const int exp = (half >> 10u) & 0x1Fu; const unsigned int mant = half & 0x3FFu; - assert(0 <= exp and exp <= 32); - assert(mant <= 1024); + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); switch (exp) { case 0: @@ -740,14 +816,14 @@ class binary_reader case 0xFA: // Single-Precision Float (four-byte IEEE 754) { - float number; - return get_number(input_format_t::cbor, number) and sax->number_float(static_cast(number), ""); + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); } case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { - double number; - return get_number(input_format_t::cbor, number) and sax->number_float(static_cast(number), ""); + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); } default: // anything else (0xFF is handled inside the other types) @@ -771,7 +847,7 @@ class binary_reader */ bool get_cbor_string(string_t& result) { - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) { return false; } @@ -809,26 +885,26 @@ class binary_reader case 0x78: // UTF-8 string (one-byte uint8_t for n follows) { - std::uint8_t len; - return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, 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) and get_string(input_format_t::cbor, len, result); + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, 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) and get_string(input_format_t::cbor, len, result); + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, 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) and get_string(input_format_t::cbor, len, result); + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); } case 0x7F: // UTF-8 string (indefinite length) @@ -836,7 +912,7 @@ class binary_reader while (get() != 0xFF) { string_t chunk; - if (not get_cbor_string(chunk)) + if (!get_cbor_string(chunk)) { return false; } @@ -866,7 +942,7 @@ class binary_reader */ bool get_cbor_binary(binary_t& result) { - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "binary"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) { return false; } @@ -904,29 +980,29 @@ class binary_reader case 0x58: // Binary data (one-byte uint8_t for n follows) { - std::uint8_t len; - return get_number(input_format_t::cbor, len) and + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, 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) and + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, 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) and + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, 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) and + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, len, result); } @@ -935,7 +1011,7 @@ class binary_reader while (get() != 0xFF) { binary_t chunk; - if (not get_cbor_binary(chunk)) + if (!get_cbor_binary(chunk)) { return false; } @@ -955,11 +1031,13 @@ class binary_reader /*! @param[in] len the length of the array or std::size_t(-1) for an array of indefinite size + @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed */ - bool get_cbor_array(const std::size_t len) + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) { - if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) { return false; } @@ -968,7 +1046,7 @@ class binary_reader { for (std::size_t i = 0; i < len; ++i) { - if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) { return false; } @@ -978,7 +1056,7 @@ class binary_reader { while (get() != 0xFF) { - if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal(false))) + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) { return false; } @@ -991,11 +1069,13 @@ class binary_reader /*! @param[in] len the length of the object or std::size_t(-1) for an object of indefinite size + @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed */ - bool get_cbor_object(const std::size_t len) + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) { - if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) { return false; } @@ -1006,12 +1086,12 @@ class binary_reader for (std::size_t i = 0; i < len; ++i) { get(); - if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key))) + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) { return false; } @@ -1022,12 +1102,12 @@ class binary_reader { while (get() != 0xFF) { - if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key))) + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) { return false; } @@ -1260,7 +1340,7 @@ class binary_reader case 0xDB: // str 32 { string_t s; - return get_msgpack_string(s) and sax->string(s); + return get_msgpack_string(s) && sax->string(s); } case 0xC0: // nil @@ -1285,91 +1365,91 @@ class binary_reader case 0xD8: // fixext 16 { binary_t b; - return get_msgpack_binary(b) and sax->binary(b); + return get_msgpack_binary(b) && sax->binary(b); } case 0xCA: // float 32 { - float number; - return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast(number), ""); + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); } case 0xCB: // float 64 { - double number; - return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast(number), ""); + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); } case 0xCC: // uint 8 { - std::uint8_t number; - return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xCD: // uint 16 { - std::uint16_t number; - return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xCE: // uint 32 { - std::uint32_t number; - return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xCF: // uint 64 { - std::uint64_t number; - return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xD0: // int 8 { - std::int8_t number; - return get_number(input_format_t::msgpack, number) and sax->number_integer(number); + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xD1: // int 16 { - std::int16_t number; - return get_number(input_format_t::msgpack, number) and sax->number_integer(number); + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xD2: // int 32 { - std::int32_t number; - return get_number(input_format_t::msgpack, number) and sax->number_integer(number); + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xD3: // int 64 { - std::int64_t number; - return get_number(input_format_t::msgpack, number) and sax->number_integer(number); + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xDC: // array 16 { - std::uint16_t len; - return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast(len)); + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); } case 0xDD: // array 32 { - std::uint32_t len; - return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast(len)); + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); } case 0xDE: // map 16 { - std::uint16_t len; - return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast(len)); + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); } case 0xDF: // map 32 { - std::uint32_t len; - return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast(len)); + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); } // negative fixint @@ -1427,7 +1507,7 @@ class binary_reader */ bool get_msgpack_string(string_t& result) { - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) { return false; } @@ -1473,20 +1553,20 @@ class binary_reader case 0xD9: // str 8 { - std::uint8_t len; - return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); } case 0xDA: // str 16 { - std::uint16_t len; - return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); } case 0xDB: // str 32 { - std::uint32_t len; - return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); } default: @@ -1520,92 +1600,92 @@ class binary_reader { case 0xC4: // bin 8 { - std::uint8_t len; - return get_number(input_format_t::msgpack, len) and + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_binary(input_format_t::msgpack, len, result); } case 0xC5: // bin 16 { - std::uint16_t len; - return get_number(input_format_t::msgpack, len) and + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_binary(input_format_t::msgpack, len, result); } case 0xC6: // bin 32 { - std::uint32_t len; - return get_number(input_format_t::msgpack, len) and + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_binary(input_format_t::msgpack, len, result); } case 0xC7: // ext 8 { - std::uint8_t len; - std::int8_t subtype; - return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, len, result) and + 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) && assign_and_return_true(subtype); } case 0xC8: // ext 16 { - std::uint16_t len; - std::int8_t subtype; - return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, len, result) and + 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) && assign_and_return_true(subtype); } case 0xC9: // ext 32 { - std::uint32_t len; - std::int8_t subtype; - return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, len, result) and + 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) && assign_and_return_true(subtype); } case 0xD4: // fixext 1 { - std::int8_t subtype; - return get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, 1, result) and + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && assign_and_return_true(subtype); } case 0xD5: // fixext 2 { - std::int8_t subtype; - return get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, 2, result) and + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && assign_and_return_true(subtype); } case 0xD6: // fixext 4 { - std::int8_t subtype; - return get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, 4, result) and + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && assign_and_return_true(subtype); } case 0xD7: // fixext 8 { - std::int8_t subtype; - return get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, 8, result) and + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && assign_and_return_true(subtype); } case 0xD8: // fixext 16 { - std::int8_t subtype; - return get_number(input_format_t::msgpack, subtype) and - get_binary(input_format_t::msgpack, 16, result) and + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && assign_and_return_true(subtype); } @@ -1620,14 +1700,14 @@ class binary_reader */ bool get_msgpack_array(const std::size_t len) { - if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) { return false; } for (std::size_t i = 0; i < len; ++i) { - if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) { return false; } @@ -1642,7 +1722,7 @@ class binary_reader */ bool get_msgpack_object(const std::size_t len) { - if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) { return false; } @@ -1651,12 +1731,12 @@ class binary_reader for (std::size_t i = 0; i < len; ++i) { get(); - if (JSON_HEDLEY_UNLIKELY(not get_msgpack_string(key) or not sax->key(key))) + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) { return false; } @@ -1703,7 +1783,7 @@ class binary_reader get(); // TODO(niels): may we ignore N here? } - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) { return false; } @@ -1712,32 +1792,32 @@ class binary_reader { case 'U': { - std::uint8_t len; - return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); + std::uint8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'i': { - std::int8_t len; - return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); + std::int8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'I': { - std::int16_t len; - return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); + std::int16_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'l': { - std::int32_t len; - return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); + std::int32_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'L': { - std::int64_t len; - return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); + std::int64_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } default: @@ -1756,8 +1836,8 @@ class binary_reader { case 'U': { - std::uint8_t number; - if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number))) + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } @@ -1767,8 +1847,8 @@ class binary_reader case 'i': { - std::int8_t number; - if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number))) + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } @@ -1778,8 +1858,8 @@ class binary_reader case 'I': { - std::int16_t number; - if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number))) + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } @@ -1789,8 +1869,8 @@ class binary_reader case 'l': { - std::int32_t number; - if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number))) + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } @@ -1800,8 +1880,8 @@ class binary_reader case 'L': { - std::int64_t number; - if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number))) + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } @@ -1837,7 +1917,7 @@ class binary_reader if (current == '$') { result.second = get(); // must not ignore 'N', because 'N' maybe the type - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type"))) { return false; } @@ -1845,7 +1925,7 @@ class binary_reader get_ignore_noop(); if (JSON_HEDLEY_UNLIKELY(current != '#')) { - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) { return false; } @@ -1885,50 +1965,55 @@ class binary_reader case 'U': { - std::uint8_t number; - return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number); + std::uint8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number); } case 'i': { - std::int8_t number; - return get_number(input_format_t::ubjson, number) and sax->number_integer(number); + std::int8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'I': { - std::int16_t number; - return get_number(input_format_t::ubjson, number) and sax->number_integer(number); + std::int16_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'l': { - std::int32_t number; - return get_number(input_format_t::ubjson, number) and sax->number_integer(number); + std::int32_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'L': { - std::int64_t number; - return get_number(input_format_t::ubjson, number) and sax->number_integer(number); + std::int64_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'd': { - float number; - return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast(number), ""); + float number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); } case 'D': { - double number; - return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast(number), ""); + double number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); } case 'C': // char { get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char"))) { return false; } @@ -1944,7 +2029,7 @@ class binary_reader case 'S': // string { string_t s; - return get_ubjson_string(s) and sax->string(s); + return get_ubjson_string(s) && sax->string(s); } case '[': // array @@ -1967,14 +2052,14 @@ class binary_reader bool get_ubjson_array() { std::pair size_and_type; - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) { return false; } if (size_and_type.first != string_t::npos) { - if (JSON_HEDLEY_UNLIKELY(not sax->start_array(size_and_type.first))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) { return false; } @@ -1985,7 +2070,7 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) { return false; } @@ -1996,7 +2081,7 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) { return false; } @@ -2005,14 +2090,14 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) { return false; } while (current != ']') { - if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal(false))) + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) { return false; } @@ -2029,7 +2114,7 @@ class binary_reader bool get_ubjson_object() { std::pair size_and_type; - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) { return false; } @@ -2037,7 +2122,7 @@ class binary_reader string_t key; if (size_and_type.first != string_t::npos) { - if (JSON_HEDLEY_UNLIKELY(not sax->start_object(size_and_type.first))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) { return false; } @@ -2046,11 +2131,11 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) { return false; } @@ -2061,11 +2146,11 @@ class binary_reader { for (std::size_t i = 0; i < size_and_type.first; ++i) { - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) { return false; } @@ -2075,18 +2160,18 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) { return false; } while (current != '}') { - if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key))) + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) { return false; } - if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal())) + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) { return false; } @@ -2101,6 +2186,55 @@ class binary_reader // Note, no reader for UBJSON binary types is implemented because they do // not exist + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + auto res = get_ubjson_size_value(size); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + auto number_ia = detail::input_adapter(std::forward(number_vector)); + auto number_lexer = detail::lexer(std::move(number_ia), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + 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_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); + } + } + /////////////////////// // Utility functions // /////////////////////// @@ -2155,7 +2289,7 @@ class binary_reader for (std::size_t i = 0; i < sizeof(NumberType); ++i) { get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "number"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) { return false; } @@ -2196,15 +2330,16 @@ class binary_reader string_t& result) { bool success = true; - std::generate_n(std::back_inserter(result), len, [this, &success, &format]() + for (NumberType i = 0; i < len; i++) { get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "string"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) { success = false; + break; } - return std::char_traits::to_char_type(current); - }); + result.push_back(static_cast(current)); + }; return success; } @@ -2228,15 +2363,16 @@ class binary_reader binary_t& result) { bool success = true; - std::generate_n(std::back_inserter(result), len, [this, &success, &format]() + for (NumberType i = 0; i < len; i++) { get(); - if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "binary"))) + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) { success = false; + break; } - return static_cast(current); - }); + result.push_back(static_cast(current)); + } return success; } @@ -2297,7 +2433,7 @@ class binary_reader break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } return error_msg + " " + context + ": " + detail; diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index ed9db0f6..63921ca5 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -1,7 +1,6 @@ #pragma once #include // array -#include // assert #include // size_t #include //FILE * #include // strlen @@ -37,7 +36,7 @@ class file_input_adapter using char_type = char; JSON_HEDLEY_NON_NULL(2) - explicit file_input_adapter(std::FILE* f) noexcept + explicit file_input_adapter(std::FILE* f) noexcept : m_file(f) {} @@ -76,7 +75,7 @@ class input_stream_adapter { // clear stream flags; we use underlying streambuf I/O, do not // maintain ifstream flags, except eof - if (is) + if (is != nullptr) { is->clear(is->rdstate() & std::ios::eofbit); } @@ -91,7 +90,7 @@ class input_stream_adapter input_stream_adapter& operator=(input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&& rhs) = delete; - input_stream_adapter(input_stream_adapter&& rhs) : is(rhs.is), sb(rhs.sb) + input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb) { rhs.is = nullptr; rhs.sb = nullptr; @@ -251,7 +250,7 @@ struct wide_string_input_helper utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); utf8_bytes_filled = 2; } - else if (0xD800 > wc or wc >= 0xE000) + else if (0xD800 > wc || wc >= 0xE000) { utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); @@ -260,7 +259,7 @@ struct wide_string_input_helper } else { - if (JSON_HEDLEY_UNLIKELY(not input.empty())) + if (JSON_HEDLEY_UNLIKELY(!input.empty())) { const auto wc2 = static_cast(input.get_character()); const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); @@ -297,13 +296,13 @@ class wide_string_input_adapter { fill_buffer(); - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); } // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); return utf8_bytes[utf8_bytes_index++]; } @@ -403,15 +402,15 @@ using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval::value and - not std::is_array::value and - std::is_integral::type>::value and + std::is_pointer::value&& + !std::is_array::value&& + std::is_integral::type>::value&& sizeof(typename std::remove_pointer::type) == 1, int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { auto length = std::strlen(reinterpret_cast(b)); - auto ptr = reinterpret_cast(b); + const auto* ptr = reinterpret_cast(b); return input_adapter(ptr, ptr + length); } @@ -427,12 +426,12 @@ auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) class span_input_adapter { public: - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> + template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > span_input_adapter(CharT b, std::size_t l) : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 66b08bff..223acd60 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -1,6 +1,5 @@ #pragma once -#include // assert #include #include // string #include // move @@ -218,7 +217,7 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); @@ -244,7 +243,7 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); @@ -259,30 +258,15 @@ class json_sax_dom_parser return true; } + template bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const detail::exception& ex) + const Exception& ex) { errored = true; + static_cast(ex); if (allow_exceptions) { - // determine the proper exception type from the id - switch ((ex.id / 100) % 100) - { - case 1: - JSON_THROW(*static_cast(&ex)); - case 4: - JSON_THROW(*static_cast(&ex)); - // LCOV_EXCL_START - case 2: - JSON_THROW(*static_cast(&ex)); - case 3: - JSON_THROW(*static_cast(&ex)); - case 5: - JSON_THROW(*static_cast(&ex)); - default: - assert(false); - // LCOV_EXCL_STOP - } + JSON_THROW(ex); } return false; } @@ -309,7 +293,7 @@ class json_sax_dom_parser return &root; } - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); if (ref_stack.back()->is_array()) { @@ -317,8 +301,8 @@ class json_sax_dom_parser return &(ref_stack.back()->m_value.array->back()); } - assert(ref_stack.back()->is_object()); - assert(object_element); + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); *object_element = BasicJsonType(std::forward(v)); return object_element; } @@ -414,7 +398,7 @@ class json_sax_dom_callback_parser ref_stack.push_back(val.second); // check object limit - if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); } @@ -431,7 +415,7 @@ class json_sax_dom_callback_parser key_keep_stack.push_back(keep); // add discarded value at given key and store the reference for later - if (keep and ref_stack.back()) + if (keep && ref_stack.back()) { object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); } @@ -441,18 +425,18 @@ class json_sax_dom_callback_parser bool end_object() { - if (ref_stack.back() and not callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + if (ref_stack.back() && !callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) { // discard object *ref_stack.back() = discarded; } - assert(not ref_stack.empty()); - assert(not keep_stack.empty()); + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); - if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_structured()) + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) { // remove discarded value for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) @@ -477,7 +461,7 @@ class json_sax_dom_callback_parser ref_stack.push_back(val.second); // check array limit - if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); } @@ -492,20 +476,20 @@ class json_sax_dom_callback_parser if (ref_stack.back()) { keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); - if (not keep) + if (!keep) { // discard array *ref_stack.back() = discarded; } } - assert(not ref_stack.empty()); - assert(not keep_stack.empty()); + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); // remove discarded value - if (not keep and not ref_stack.empty() and ref_stack.back()->is_array()) + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) { ref_stack.back()->m_value.array->pop_back(); } @@ -513,30 +497,15 @@ class json_sax_dom_callback_parser return true; } + template bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const detail::exception& ex) + const Exception& ex) { errored = true; + static_cast(ex); if (allow_exceptions) { - // determine the proper exception type from the id - switch ((ex.id / 100) % 100) - { - case 1: - JSON_THROW(*static_cast(&ex)); - case 4: - JSON_THROW(*static_cast(&ex)); - // LCOV_EXCL_START - case 2: - JSON_THROW(*static_cast(&ex)); - case 3: - JSON_THROW(*static_cast(&ex)); - case 5: - JSON_THROW(*static_cast(&ex)); - default: - assert(false); - // LCOV_EXCL_STOP - } + JSON_THROW(ex); } return false; } @@ -565,11 +534,11 @@ class json_sax_dom_callback_parser template std::pair handle_value(Value&& v, const bool skip_callback = false) { - assert(not keep_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); // do not handle this value if we know it would be added to a discarded // container - if (not keep_stack.back()) + if (!keep_stack.back()) { return {false, nullptr}; } @@ -578,10 +547,10 @@ class json_sax_dom_callback_parser auto value = BasicJsonType(std::forward(v)); // check callback - const bool keep = skip_callback or callback(static_cast(ref_stack.size()), parse_event_t::value, value); + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); // do not handle this value if we just learnt it shall be discarded - if (not keep) + if (!keep) { return {false, nullptr}; } @@ -594,13 +563,13 @@ class json_sax_dom_callback_parser // skip this value if we already decided to skip the parent // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (not ref_stack.back()) + if (!ref_stack.back()) { return {false, nullptr}; } // we now only expect arrays and objects - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); // array if (ref_stack.back()->is_array()) @@ -610,18 +579,18 @@ class json_sax_dom_callback_parser } // object - assert(ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_object()); // check if we should store an element for the current key - assert(not key_keep_stack.empty()); + JSON_ASSERT(!key_keep_stack.empty()); const bool store_element = key_keep_stack.back(); key_keep_stack.pop_back(); - if (not store_element) + if (!store_element) { return {false, nullptr}; } - assert(object_element); + JSON_ASSERT(object_element); *object_element = std::move(value); return {true, object_element}; } diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 0ff0c736..60eb3526 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -112,8 +112,11 @@ class lexer : public lexer_base public: using token_type = typename lexer_base::token_type; - explicit lexer(InputAdapterType&& adapter) - : ia(std::move(adapter)), decimal_point_char(static_cast(get_decimal_point())) {} + explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) + : ia(std::move(adapter)) + , ignore_comments(ignore_comments_) + , decimal_point_char(static_cast(get_decimal_point())) + {} // delete because of pointer members lexer(const lexer&) = delete; @@ -131,8 +134,8 @@ class lexer : public lexer_base JSON_HEDLEY_PURE static char get_decimal_point() noexcept { - const auto loc = localeconv(); - assert(loc != nullptr); + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); } @@ -158,7 +161,7 @@ class lexer : public lexer_base int get_codepoint() { // this function only makes sense after reading `\u` - assert(current == 'u'); + JSON_ASSERT(current == 'u'); int codepoint = 0; const auto factors = { 12u, 8u, 4u, 0u }; @@ -166,15 +169,15 @@ class lexer : public lexer_base { get(); - if (current >= '0' and current <= '9') + if (current >= '0' && current <= '9') { codepoint += static_cast((static_cast(current) - 0x30u) << factor); } - else if (current >= 'A' and current <= 'F') + else if (current >= 'A' && current <= 'F') { codepoint += static_cast((static_cast(current) - 0x37u) << factor); } - else if (current >= 'a' and current <= 'f') + else if (current >= 'a' && current <= 'f') { codepoint += static_cast((static_cast(current) - 0x57u) << factor); } @@ -184,7 +187,7 @@ class lexer : public lexer_base } } - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); return codepoint; } @@ -205,13 +208,13 @@ class lexer : public lexer_base */ bool next_byte_in_range(std::initializer_list ranges) { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); add(current); for (auto range = ranges.begin(); range != ranges.end(); ++range) { get(); - if (JSON_HEDLEY_LIKELY(*range <= current and current <= *(++range))) + if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) { add(current); } @@ -246,7 +249,7 @@ class lexer : public lexer_base reset(); // we entered the function by reading an open quote - assert(current == '\"'); + JSON_ASSERT(current == '\"'); while (true) { @@ -317,10 +320,10 @@ class lexer : public lexer_base } // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) { // expect next \uxxxx entry - if (JSON_HEDLEY_LIKELY(get() == '\\' and get() == 'u')) + if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) { const int codepoint2 = get_codepoint(); @@ -331,7 +334,7 @@ class lexer : public lexer_base } // check if codepoint2 is a low surrogate - if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) { // overwrite codepoint codepoint = static_cast( @@ -358,7 +361,7 @@ class lexer : public lexer_base } else { - if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) { error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; return token_type::parse_error; @@ -366,7 +369,7 @@ class lexer : public lexer_base } // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); // translate codepoint into bytes if (codepoint < 0x80) @@ -733,7 +736,7 @@ class lexer : public lexer_base case 0xDE: case 0xDF: { - if (JSON_HEDLEY_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) { return token_type::parse_error; } @@ -743,7 +746,7 @@ class lexer : public lexer_base // U+0800..U+0FFF: bytes E0 A0..BF 80..BF case 0xE0: { - if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -767,7 +770,7 @@ class lexer : public lexer_base case 0xEE: case 0xEF: { - if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -777,7 +780,7 @@ class lexer : public lexer_base // U+D000..U+D7FF: bytes ED 80..9F 80..BF case 0xED: { - if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -787,7 +790,7 @@ class lexer : public lexer_base // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF case 0xF0: { - if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -799,7 +802,7 @@ class lexer : public lexer_base case 0xF2: case 0xF3: { - if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -809,7 +812,7 @@ class lexer : public lexer_base // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF case 0xF4: { - if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -826,6 +829,77 @@ class lexer : public lexer_base } } + /*! + * @brief scan a comment + * @return whether comment could be scanned successfully + */ + bool scan_comment() + { + switch (get()) + { + // single-line comments skip input until a newline or EOF is read + case '/': + { + while (true) + { + switch (get()) + { + case '\n': + case '\r': + case std::char_traits::eof(): + case '\0': + return true; + + default: + break; + } + } + } + + // multi-line comments skip input until */ is read + case '*': + { + while (true) + { + switch (get()) + { + case std::char_traits::eof(): + case '\0': + { + error_message = "invalid comment; missing closing '*/'"; + return false; + } + + case '*': + { + switch (get()) + { + case '/': + return true; + + default: + { + unget(); + break; + } + } + } + + default: + break; + } + } + } + + // unexpected character after reading '/' + default: + { + error_message = "invalid comment; expecting '/' or '*' after '/'"; + return false; + } + } + } + JSON_HEDLEY_NON_NULL(2) static void strtof(float& f, const char* str, char** endptr) noexcept { @@ -924,7 +998,7 @@ class lexer : public lexer_base // all other characters are rejected outside scan_number() default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } scan_number_minus: @@ -1171,7 +1245,7 @@ scan_number_done: const auto x = std::strtoull(token_buffer.data(), &endptr, 10); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -1187,7 +1261,7 @@ scan_number_done: const auto x = std::strtoll(token_buffer.data(), &endptr, 10); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -1204,7 +1278,7 @@ scan_number_done: strtof(value_float, token_buffer.data(), &endptr); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); return token_type::value_float; } @@ -1218,7 +1292,7 @@ scan_number_done: token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type return_type) { - assert(std::char_traits::to_char_type(current) == literal_text[0]); + JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); for (std::size_t i = 1; i < length; ++i) { if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) @@ -1310,7 +1384,7 @@ scan_number_done: if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) { - assert(not token_string.empty()); + JSON_ASSERT(!token_string.empty()); token_string.pop_back(); } } @@ -1406,7 +1480,7 @@ scan_number_done: if (get() == 0xEF) { // check if we completely parse the BOM - return get() == 0xBB and get() == 0xBF; + return get() == 0xBB && get() == 0xBF; } // the first character is not the beginning of the BOM; unget it to @@ -1415,21 +1489,38 @@ scan_number_done: return true; } + void skip_whitespace() + { + do + { + get(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); + } + token_type scan() { // initially, skip the BOM - if (position.chars_read_total == 0 and not skip_bom()) + if (position.chars_read_total == 0 && !skip_bom()) { error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; return token_type::parse_error; } // read next character and ignore whitespace - do + skip_whitespace(); + + // ignore comments + if (ignore_comments && current == '/') { - get(); + if (!scan_comment()) + { + return token_type::parse_error; + } + + // skip following whitespace + skip_whitespace(); } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); switch (current) { @@ -1499,6 +1590,9 @@ scan_number_done: /// input adapter InputAdapterType ia; + /// whether comments should be ignored (true) or signaled as errors (false) + const bool ignore_comments = false; + /// the current character char_int_type current = std::char_traits::eof(); diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 0546b88c..ffe483aa 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -1,6 +1,5 @@ #pragma once -#include // assert #include // isfinite #include // uint8_t #include // function @@ -63,8 +62,11 @@ class parser /// a parser reading from an input adapter explicit parser(InputAdapterType&& adapter, const parser_callback_t cb = nullptr, - const bool allow_exceptions_ = true) - : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_) + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(cb) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) { // read first token get_token(); @@ -89,7 +91,7 @@ class parser result.assert_invariant(); // in strict mode, input must be completely read - if (strict and (get_token() != token_type::end_of_input)) + if (strict && (get_token() != token_type::end_of_input)) { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -118,7 +120,7 @@ class parser result.assert_invariant(); // in strict mode, input must be completely read - if (strict and (get_token() != token_type::end_of_input)) + if (strict && (get_token() != token_type::end_of_input)) { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -147,7 +149,7 @@ class parser return sax_parse(&sax_acceptor, strict); } - template + template JSON_HEDLEY_NON_NULL(2) bool sax_parse(SAX* sax, const bool strict = true) { @@ -155,7 +157,7 @@ class parser const bool result = sax_parse_internal(sax); // strict mode: next byte must be EOF - if (result and strict and (get_token() != token_type::end_of_input)) + if (result && strict && (get_token() != token_type::end_of_input)) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), @@ -167,7 +169,7 @@ class parser } private: - template + template JSON_HEDLEY_NON_NULL(2) bool sax_parse_internal(SAX* sax) { @@ -179,14 +181,14 @@ class parser while (true) { - if (not skip_to_state_evaluation) + if (!skip_to_state_evaluation) { // invariant: get_token() was called before each iteration switch (last_token) { case token_type::begin_object: { - if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) { return false; } @@ -194,7 +196,7 @@ class parser // closing } -> we are done if (get_token() == token_type::end_object) { - if (JSON_HEDLEY_UNLIKELY(not sax->end_object())) + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) { return false; } @@ -209,7 +211,7 @@ class parser parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"))); } - if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string()))) + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) { return false; } @@ -233,7 +235,7 @@ class parser case token_type::begin_array: { - if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) { return false; } @@ -241,7 +243,7 @@ class parser // closing ] -> we are done if (get_token() == token_type::end_array) { - if (JSON_HEDLEY_UNLIKELY(not sax->end_array())) + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) { return false; } @@ -259,14 +261,14 @@ class parser { const auto res = m_lexer.get_number_float(); - if (JSON_HEDLEY_UNLIKELY(not std::isfinite(res))) + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); } - if (JSON_HEDLEY_UNLIKELY(not sax->number_float(res, m_lexer.get_string()))) + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) { return false; } @@ -276,7 +278,7 @@ class parser case token_type::literal_false: { - if (JSON_HEDLEY_UNLIKELY(not sax->boolean(false))) + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) { return false; } @@ -285,7 +287,7 @@ class parser case token_type::literal_null: { - if (JSON_HEDLEY_UNLIKELY(not sax->null())) + if (JSON_HEDLEY_UNLIKELY(!sax->null())) { return false; } @@ -294,7 +296,7 @@ class parser case token_type::literal_true: { - if (JSON_HEDLEY_UNLIKELY(not sax->boolean(true))) + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) { return false; } @@ -303,7 +305,7 @@ class parser case token_type::value_integer: { - if (JSON_HEDLEY_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer()))) + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) { return false; } @@ -312,7 +314,7 @@ class parser case token_type::value_string: { - if (JSON_HEDLEY_UNLIKELY(not sax->string(m_lexer.get_string()))) + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) { return false; } @@ -321,7 +323,7 @@ class parser case token_type::value_unsigned: { - if (JSON_HEDLEY_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned()))) + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) { return false; } @@ -371,7 +373,7 @@ class parser // closing ] if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) { - if (JSON_HEDLEY_UNLIKELY(not sax->end_array())) + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) { return false; } @@ -380,7 +382,7 @@ class parser // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. - assert(not states.empty()); + JSON_ASSERT(!states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; @@ -405,7 +407,7 @@ class parser exception_message(token_type::value_string, "object key"))); } - if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string()))) + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) { return false; } @@ -427,7 +429,7 @@ class parser // closing } if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) { - if (JSON_HEDLEY_UNLIKELY(not sax->end_object())) + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) { return false; } @@ -436,7 +438,7 @@ class parser // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. - assert(not states.empty()); + JSON_ASSERT(!states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; @@ -460,7 +462,7 @@ class parser { std::string error_msg = "syntax error "; - if (not context.empty()) + if (!context.empty()) { error_msg += "while parsing " + context + " "; } diff --git a/include/nlohmann/detail/iterators/internal_iterator.hpp b/include/nlohmann/detail/iterators/internal_iterator.hpp index 742df483..2c81f723 100644 --- a/include/nlohmann/detail/iterators/internal_iterator.hpp +++ b/include/nlohmann/detail/iterators/internal_iterator.hpp @@ -18,8 +18,6 @@ template struct internal_iterator typename BasicJsonType::object_t::iterator object_iterator {}; /// iterator for JSON arrays typename BasicJsonType::array_t::iterator array_iterator {}; - /// iterator for JSON binary arrays - typename BasicJsonType::binary_t::container_type::iterator binary_iterator {}; /// generic iterator for all other types primitive_iterator_t primitive_iterator {}; }; diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 0b79202a..e9a394d4 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -3,7 +3,6 @@ #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include // conditional, is_const, remove_const -#include #include #include #include @@ -85,7 +84,7 @@ class iter_impl */ explicit iter_impl(pointer object) noexcept : m_object(object) { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -171,7 +170,7 @@ class iter_impl */ void set_begin() noexcept { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -208,7 +207,7 @@ class iter_impl */ void set_end() noexcept { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -239,19 +238,19 @@ class iter_impl */ reference operator*() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { - assert(m_it.object_iterator != m_object->m_value.object->end()); + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case value_t::array: { - assert(m_it.array_iterator != m_object->m_value.array->end()); + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } @@ -276,19 +275,19 @@ class iter_impl */ pointer operator->() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { - assert(m_it.object_iterator != m_object->m_value.object->end()); + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case value_t::array: { - assert(m_it.array_iterator != m_object->m_value.array->end()); + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } @@ -321,7 +320,7 @@ class iter_impl */ iter_impl& operator++() { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -364,7 +363,7 @@ class iter_impl */ iter_impl& operator--() { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -402,7 +401,7 @@ class iter_impl JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -423,7 +422,7 @@ class iter_impl */ bool operator!=(const iter_impl& other) const { - return not operator==(other); + return !operator==(other); } /*! @@ -438,7 +437,7 @@ class iter_impl JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -459,7 +458,7 @@ class iter_impl */ bool operator<=(const iter_impl& other) const { - return not other.operator < (*this); + return !other.operator < (*this); } /*! @@ -468,7 +467,7 @@ class iter_impl */ bool operator>(const iter_impl& other) const { - return not operator<=(other); + return !operator<=(other); } /*! @@ -477,7 +476,7 @@ class iter_impl */ bool operator>=(const iter_impl& other) const { - return not operator<(other); + return !operator<(other); } /*! @@ -486,7 +485,7 @@ class iter_impl */ iter_impl& operator+=(difference_type i) { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -557,7 +556,7 @@ class iter_impl */ difference_type operator-(const iter_impl& other) const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -578,7 +577,7 @@ class iter_impl */ reference operator[](difference_type n) const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -609,7 +608,7 @@ class iter_impl */ const typename object_t::key_type& key() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); if (JSON_HEDLEY_LIKELY(m_object->is_object())) { diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp index c61d9629..74b4eb34 100644 --- a/include/nlohmann/detail/iterators/iteration_proxy.hpp +++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -15,9 +15,11 @@ namespace detail template void int_to_string( string_type& target, std::size_t value ) { - target = std::to_string(value); + // For ADL + using std::to_string; + target = to_string(value); } -template class iteration_proxy_value +template class iteration_proxy_value { public: using difference_type = std::ptrdiff_t; @@ -72,7 +74,7 @@ template class iteration_proxy_value /// return key of the iterator const string_type& key() const { - assert(anchor.m_object != nullptr); + JSON_ASSERT(anchor.m_object != nullptr); switch (anchor.m_object->type()) { @@ -131,7 +133,7 @@ template class iteration_proxy // Structured Bindings Support // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 -template = 0> +template = 0> auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) { return i.key(); @@ -139,7 +141,7 @@ auto get(const nlohmann::detail::iteration_proxy_value& i) -> decl // Structured Bindings Support // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 -template = 0> +template = 0> auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) { return i.value(); @@ -158,11 +160,11 @@ namespace std #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmismatched-tags" #endif -template +template class tuple_size<::nlohmann::detail::iteration_proxy_value> : public std::integral_constant {}; -template +template class tuple_element> { public: diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp index 4cced80c..da563618 100644 --- a/include/nlohmann/detail/iterators/iterator_traits.hpp +++ b/include/nlohmann/detail/iterators/iterator_traits.hpp @@ -9,10 +9,10 @@ namespace nlohmann { namespace detail { -template +template struct iterator_types {}; -template +template struct iterator_types < It, void_t +template struct iterator_traits { }; -template +template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> : iterator_types { }; -template +template struct iterator_traits::value>> { using iterator_category = std::random_access_iterator_tag; diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 421c5ec8..78bc3a3a 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -1,8 +1,8 @@ #pragma once #include // all_of -#include // assert #include // isdigit +#include // max #include // accumulate #include // string #include // move @@ -325,12 +325,17 @@ class json_pointer @return integer representation of @a s + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type */ - static int array_index(const std::string& s) + static typename BasicJsonType::size_type array_index(const std::string& s) { + using size_type = typename BasicJsonType::size_type; + // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0')) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) { JSON_THROW(detail::parse_error::create(106, 0, "array index '" + s + @@ -338,16 +343,16 @@ class json_pointer } // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9'))) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) { JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); } std::size_t processed_chars = 0; - int res = 0; + unsigned long long res = 0; JSON_TRY { - res = std::stoi(s, &processed_chars); + res = std::stoull(s, &processed_chars); } JSON_CATCH(std::out_of_range&) { @@ -360,7 +365,14 @@ class json_pointer JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); } - return res; + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) + { + JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE + } + + return static_cast(res); } json_pointer top() const @@ -385,7 +397,6 @@ class json_pointer */ BasicJsonType& get_and_create(BasicJsonType& j) const { - using size_type = typename BasicJsonType::size_type; auto result = &j; // in case no reference tokens exist, return a reference to the JSON value @@ -419,7 +430,7 @@ class json_pointer case detail::value_t::array: { // create an entry in the array - result = &result->operator[](static_cast(array_index(reference_token))); + result = &result->operator[](array_index(reference_token)); break; } @@ -458,7 +469,6 @@ class json_pointer */ BasicJsonType& get_unchecked(BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { // convert null values to arrays or objects before continuing @@ -473,7 +483,7 @@ class json_pointer }); // change value to array for numbers or "-" or to object otherwise - *ptr = (nums or reference_token == "-") + *ptr = (nums || reference_token == "-") ? detail::value_t::array : detail::value_t::object; } @@ -497,8 +507,7 @@ class json_pointer else { // convert array index to number; unchecked access - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); + ptr = &ptr->operator[](array_index(reference_token)); } break; } @@ -519,7 +528,6 @@ class json_pointer */ BasicJsonType& get_checked(BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -542,7 +550,7 @@ class json_pointer } // note: at performs range check - ptr = &ptr->at(static_cast(array_index(reference_token))); + ptr = &ptr->at(array_index(reference_token)); break; } @@ -569,7 +577,6 @@ class json_pointer */ const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -592,8 +599,7 @@ class json_pointer } // use unchecked array access - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); + ptr = &ptr->operator[](array_index(reference_token)); break; } @@ -613,7 +619,6 @@ class json_pointer */ const BasicJsonType& get_checked(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -636,7 +641,7 @@ class json_pointer } // note: at performs range check - ptr = &ptr->at(static_cast(array_index(reference_token))); + ptr = &ptr->at(array_index(reference_token)); break; } @@ -654,14 +659,13 @@ class json_pointer */ bool contains(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { - if (not ptr->contains(reference_token)) + if (!ptr->contains(reference_token)) { // we did not find the key in the object return false; @@ -678,21 +682,21 @@ class json_pointer // "-" always fails the range check return false; } - if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 and not ("0" <= reference_token and reference_token <= "9"))) + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) { // invalid char return false; } if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) { - if (JSON_HEDLEY_UNLIKELY(not ('1' <= reference_token[0] and reference_token[0] <= '9'))) + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) { // first char should be between '1' and '9' return false; } for (std::size_t i = 1; i < reference_token.size(); i++) { - if (JSON_HEDLEY_UNLIKELY(not ('0' <= reference_token[i] and reference_token[i] <= '9'))) + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) { // other char should be between '0' and '9' return false; @@ -700,7 +704,7 @@ class json_pointer } } - const auto idx = static_cast(array_index(reference_token)); + const auto idx = array_index(reference_token); if (idx >= ptr->size()) { // index out of range @@ -776,11 +780,11 @@ class json_pointer pos != std::string::npos; pos = reference_token.find_first_of('~', pos + 1)) { - assert(reference_token[pos] == '~'); + JSON_ASSERT(reference_token[pos] == '~'); // ~ must be followed by 0 or 1 - if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or - (reference_token[pos + 1] != '0' and + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && reference_token[pos + 1] != '1'))) { JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); @@ -811,7 +815,7 @@ class json_pointer static void replace_substring(std::string& s, const std::string& f, const std::string& t) { - assert(not f.empty()); + JSON_ASSERT(!f.empty()); for (auto pos = s.find(f); // find first occurrence of f pos != std::string::npos; // make sure f was found s.replace(pos, f.size(), t), // replace with t, and @@ -906,7 +910,7 @@ class json_pointer static BasicJsonType unflatten(const BasicJsonType& value) { - if (JSON_HEDLEY_UNLIKELY(not value.is_object())) + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) { JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); } @@ -916,7 +920,7 @@ class json_pointer // iterate the JSON object values for (const auto& element : *value.m_value.object) { - if (JSON_HEDLEY_UNLIKELY(not element.second.is_primitive())) + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) { JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); } @@ -962,7 +966,7 @@ class json_pointer friend bool operator!=(json_pointer const& lhs, json_pointer const& rhs) noexcept { - return not (lhs == rhs); + return !(lhs == rhs); } /// the reference tokens diff --git a/include/nlohmann/detail/json_ref.hpp b/include/nlohmann/detail/json_ref.hpp index c8dec733..c9bf6cb2 100644 --- a/include/nlohmann/detail/json_ref.hpp +++ b/include/nlohmann/detail/json_ref.hpp @@ -16,23 +16,30 @@ class json_ref using value_type = BasicJsonType; json_ref(value_type&& value) - : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) + : owned_value(std::move(value)) + , value_ref(&owned_value) + , is_rvalue(true) {} json_ref(const value_type& value) - : value_ref(const_cast(&value)), is_rvalue(false) + : value_ref(const_cast(&value)) + , is_rvalue(false) {} json_ref(std::initializer_list init) - : owned_value(init), value_ref(&owned_value), is_rvalue(true) + : owned_value(init) + , value_ref(&owned_value) + , is_rvalue(true) {} template < class... Args, enable_if_t::value, int> = 0 > json_ref(Args && ... args) - : owned_value(std::forward(args)...), value_ref(&owned_value), - is_rvalue(true) {} + : owned_value(std::forward(args)...) + , value_ref(&owned_value) + , is_rvalue(true) + {} // class should be movable only json_ref(json_ref&&) = default; @@ -63,7 +70,7 @@ class json_ref private: mutable value_type owned_value = nullptr; value_type* value_ref = nullptr; - const bool is_rvalue; + const bool is_rvalue = true; }; } // namespace detail } // namespace nlohmann diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 25e6b76e..8c9f6329 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -20,7 +20,11 @@ #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) @@ -73,6 +77,12 @@ #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM @@ -120,3 +130,167 @@ basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 80b293e7..eb706511 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -9,6 +9,7 @@ #endif // clean up +#undef JSON_ASSERT #undef JSON_INTERNAL_CATCH #undef JSON_CATCH #undef JSON_THROW @@ -17,5 +18,6 @@ #undef JSON_HAS_CPP_17 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT #include diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index 11f88acc..dd929ee1 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -3,8 +3,6 @@ #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include - namespace nlohmann { namespace detail diff --git a/include/nlohmann/detail/meta/detected.hpp b/include/nlohmann/detail/meta/detected.hpp index e5ca5eb2..7b5a0035 100644 --- a/include/nlohmann/detail/meta/detected.hpp +++ b/include/nlohmann/detail/meta/detected.hpp @@ -19,39 +19,39 @@ struct nonesuch void operator=(nonesuch&&) = delete; }; -template class Op, - class... Args> +template class Op, + class... Args> struct detector { using value_t = std::false_type; using type = Default; }; -template class Op, class... Args> +template class Op, class... Args> struct detector>, Op, Args...> { using value_t = std::true_type; using type = Op; }; -template