Merge branch 'release/3.9.0'

This commit is contained in:
Niels Lohmann 2020-07-27 15:54:24 +02:00
commit 36e5ecf66d
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
147 changed files with 8984 additions and 5201 deletions

84
.clang-format Normal file
View file

@ -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

View file

@ -1,23 +1,20 @@
Checks: '-*, Checks: '*,
bugprone-*, -cppcoreguidelines-avoid-goto,
cert-*, -cppcoreguidelines-avoid-magic-numbers,
clang-analyzer-*, -cppcoreguidelines-macro-usage,
google-*, -fuchsia-default-arguments-calls,
-google-runtime-references, -fuchsia-default-arguments-declarations,
-fuchsia-overloaded-operator,
-google-explicit-constructor, -google-explicit-constructor,
hicpp-*, -google-runtime-references,
-hicpp-avoid-goto,
-hicpp-explicit-conversions,
-hicpp-no-array-decay, -hicpp-no-array-decay,
-hicpp-uppercase-literal-suffix, -hicpp-uppercase-literal-suffix,
-hicpp-explicit-conversions,
misc-*,
-misc-non-private-member-variables-in-classes,
llvm-*,
-llvm-header-guard, -llvm-header-guard,
modernize-*, -llvm-include-order,
-misc-non-private-member-variables-in-classes,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
performance-*,
portability-*,
readability-*,
-readability-magic-numbers, -readability-magic-numbers,
-readability-uppercase-literal-suffix' -readability-uppercase-literal-suffix'

View file

@ -47,7 +47,7 @@ assignees: ''
<!-- Please add an `x` to the respective line. --> <!-- Please add an `x` to the respective line. -->
- [ ] latest release version 3.7.3 - [ ] latest release version 3.9.0
- [ ] other release - please state the version: ___ - [ ] other release - please state the version: ___
- [ ] the `develop` branch - [ ] the `develop` branch

View file

@ -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?
<!-- Describe the feature in as much detail as possible. -->
#### How would the feature be usable for other users?
<!-- Include sample usage where appropriate. -->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -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

View file

@ -1,40 +0,0 @@
---
name: Question
about: Ask a question regarding the library.
title: ''
labels: 'kind: question'
assignees: ''
---
<!-- Provide a concise summary of the issue in the title above. -->
#### What do you want to achieve?
<!-- Please describe the feature as detailed as possible. -->
#### What have you tried?
<!-- There are thousands of issues to search: https://github.com/nlohmann/json/issues?q=is%3Aissue+ -->
<!-- There is a full documentation of the API: https://nlohmann.github.io/json/ -->
<!-- There is a detailed README file: https://github.com/nlohmann/json/blob/develop/README.md -->
#### Can you provide a small code example?
<!-- Please understand that we cannot analyze and debug large code bases. -->
#### Which compiler and operating system are you using?
<!-- Include as many relevant details about the environment you experienced the bug in. -->
<!-- Make sure you use a supported compiler, see https://github.com/nlohmann/json#supported-compilers. -->
- Compiler: ___
- Operating system: ___
#### Which version of the library did you use?
<!-- Please add an `x` to the respective line. -->
- [ ] latest release version 3.7.3
- [ ] other release - please state the version: ___
- [ ] the `develop` branch

54
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -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

View file

@ -3,8 +3,7 @@ name: Windows
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: msvc2019:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
@ -15,3 +14,55 @@ jobs:
run: cmake --build build --parallel 10 run: cmake --build build --parallel 10
- name: test - name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure run: cd build ; ctest -j 10 -C Debug --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

3
.gitignore vendored
View file

@ -22,7 +22,7 @@ benchmarks/files/numbers/*.json
.wsjcpp/* .wsjcpp/*
.idea .idea
cmake-build-debug /cmake-build-*
test/test-* test/test-*
/.vs /.vs
@ -32,3 +32,4 @@ doc/mkdocs/docs/images
doc/mkdocs/docs/examples doc/mkdocs/docs/examples
doc/mkdocs/site doc/mkdocs/site
doc/mkdocs/docs/__pycache__/ doc/mkdocs/docs/__pycache__/
doc/xml

View file

@ -10,17 +10,6 @@ sudo: required
group: edge 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 # # build matrix #
################ ################
@ -129,6 +118,9 @@ matrix:
env: env:
- SPECIAL=coverity - SPECIAL=coverity
- COMPILER=clang++-3.6 - 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 # OSX / Clang
@ -150,6 +142,14 @@ matrix:
- os: osx - os: osx
osx_image: xcode11.2 osx_image: xcode11.2
- os: osx
osx_image: xcode12
- os: osx
osx_image: xcode12
env:
- IMPLICIT_CONVERSIONS=OFF
# Linux / GCC # Linux / GCC
- os: linux - os: linux
@ -208,6 +208,16 @@ matrix:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-9', 'ninja-build'] 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 - os: linux
compiler: gcc compiler: gcc
env: env:
@ -320,10 +330,12 @@ script:
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi - if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi
# by default, use the single-header version # by default, use the single-header version
- if [[ "${MULTIPLE_HEADERS}" == "" ]]; then export MULTIPLE_HEADERS=OFF; fi - 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 # compile and execute unit tests
- mkdir -p build && cd build - 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 - ctest -C Release --timeout 2700 -V -j
- cd .. - cd ..

View file

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1)
## PROJECT ## PROJECT
## name and version ## name and version
## ##
project(nlohmann_json VERSION 3.8.0 LANGUAGES CXX) project(nlohmann_json VERSION 3.9.0 LANGUAGES CXX)
## ##
## INCLUDE ## INCLUDE
@ -15,9 +15,16 @@ include(ExternalProject)
## ##
## OPTIONS ## 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_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON)
option(JSON_Install "Install CMake targets during install step." ON) option(JSON_Install "Install CMake targets during install step." ON)
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
## ##
## CONFIGURATION ## CONFIGURATION
@ -42,6 +49,10 @@ else()
message(STATUS "Using the single-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}") message(STATUS "Using the single-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}")
endif() endif()
if (NOT JSON_ImplicitConversions)
message(STATUS "Implicit conversions are disabled")
endif()
## ##
## TARGET ## TARGET
## create target and add include path ## create target and add include path
@ -54,6 +65,12 @@ else()
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11) target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
endif() endif()
target_compile_definitions(
${NLOHMANN_JSON_TARGET_NAME}
INTERFACE
JSON_USE_IMPLICIT_CONVERSIONS=$<BOOL:${JSON_ImplicitConversions}>
)
target_include_directories( target_include_directories(
${NLOHMANN_JSON_TARGET_NAME} ${NLOHMANN_JSON_TARGET_NAME}
INTERFACE INTERFACE
@ -73,6 +90,12 @@ if (MSVC)
) )
endif() 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 ## TESTS
## create and configure the unit test target ## create and configure the unit test target
@ -133,4 +156,8 @@ endif()
NAMESPACE ${PROJECT_NAME}:: NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
) )
install(
FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION lib/pkgconfig
)
endif() endif()

View file

@ -1,13 +1,129 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). 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\<int,T\> [\#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\<std::string\> 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) ## [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) [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) - 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) - 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) - Some troubles to compile the last revision [\#2177](https://github.com/nlohmann/json/issues/2177)
- \# Top level CMakeLists.txt - \# Top level CMakeLists.txt
project\(FOO\) 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) - test-cbor fails [\#2154](https://github.com/nlohmann/json/issues/2154)
- Accessing array inside array syntax? [\#2151](https://github.com/nlohmann/json/issues/2151) - 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) - 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) - JSON Data Mapping Key-Value from other Key-Value [\#2148](https://github.com/nlohmann/json/issues/2148)
- Conflicts with std \<any\> compiling with GCC 10 [\#2146](https://github.com/nlohmann/json/issues/2146) - Conflicts with std \<any\> compiling with GCC 10 [\#2146](https://github.com/nlohmann/json/issues/2146)
- Incorrect CMake FetchContent example [\#2142](https://github.com/nlohmann/json/issues/2142) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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\<char8\_t\> 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) - How to convert a const std::vector\<char8\_t\> 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) - 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) - 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) - 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) - 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) - 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) - 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) - Writing map to json file [\#1896](https://github.com/nlohmann/json/issues/1896)
- Small documentation mistake [\#1895](https://github.com/nlohmann/json/issues/1895) - 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) - 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) - 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) - 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) - 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) - 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) - 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)) - 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)) - 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)) - 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)) - 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)) - 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)) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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 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) - 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) - 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) - 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)) - 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)) - 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)) - 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) ## [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) - 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) - 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) - 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) - std::complex type [\#1510](https://github.com/nlohmann/json/issues/1510)
- CBOR byte string support [\#1509](https://github.com/nlohmann/json/issues/1509) - 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) - 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) - Implicit type conversion error on MSVC [\#1333](https://github.com/nlohmann/json/issues/1333)
- NuGet Package [\#1132](https://github.com/nlohmann/json/issues/1132) - 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)) - 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)) - 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)) - 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)) - 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)) - 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)) - 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)) - :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)) - 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)) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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\<T\> for any T [\#1118](https://github.com/nlohmann/json/issues/1118) - Disable implicit conversions from json to std::initializer\_list\<T\> 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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)) - 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)) - 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)) - 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)) - 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)) - 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) - \[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) - 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)) - 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)) - 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)) - 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) [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) - I have a proposal [\#949](https://github.com/nlohmann/json/issues/949)
- VERSION define\(s\) [\#948](https://github.com/nlohmann/json/issues/948) - 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) - 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) - 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) - 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 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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 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 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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) - '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) - 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) - 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) - 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) [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) - 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) - 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) - 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) - 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) - error: unterminated raw string [\#109](https://github.com/nlohmann/json/issues/109)
- vector\<json\> copy constructor really weird [\#108](https://github.com/nlohmann/json/issues/108) - vector\<json\> 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) - \[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) - object field accessors [\#103](https://github.com/nlohmann/json/issues/103)
- v8pp and json [\#95](https://github.com/nlohmann/json/issues/95) - v8pp and json [\#95](https://github.com/nlohmann/json/issues/95)
- Wishlist [\#65](https://github.com/nlohmann/json/issues/65) - Wishlist [\#65](https://github.com/nlohmann/json/issues/65)

120
Makefile
View file

@ -5,7 +5,7 @@
########################################################################## ##########################################################################
# directory to recent compiler binaries # 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 # find GNU sed to use `-i` parameter
SED:=$(shell command -v gsed || which sed) SED:=$(shell command -v gsed || which sed)
@ -30,7 +30,6 @@ AMALGAMATED_FILE=single_include/nlohmann/json.hpp
all: all:
@echo "amalgamate - amalgamate file single_include/nlohmann/json.hpp from the include/nlohmann sources" @echo "amalgamate - amalgamate file single_include/nlohmann/json.hpp from the include/nlohmann sources"
@echo "ChangeLog.md - generate ChangeLog file" @echo "ChangeLog.md - generate ChangeLog file"
@echo "check - compile and execute test suite"
@echo "check-amalgamation - check whether sources have been amalgamated" @echo "check-amalgamation - check whether sources have been amalgamated"
@echo "clean - remove built files" @echo "clean - remove built files"
@echo "coverage - create coverage information with lcov" @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_cbor - prepare fuzz testing of the CBOR parser"
@echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser" @echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser"
@echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON 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_clang - run Clang with maximal warning flags"
@echo "pedantic_gcc - run GCC with maximal warning flags" @echo "pedantic_gcc - run GCC with maximal warning flags"
@echo "pretty - beautify code with Artistic Style" @echo "pretty - beautify code with Artistic Style"
@echo "run_benchmarks - build and run benchmarks" @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
########################################################################## ##########################################################################
coverage: coverage:
rm -fr build_coverage rm -fr cmake-build-coverage
mkdir build_coverage mkdir cmake-build-coverage
cd build_coverage ; cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON cd cmake-build-coverage ; cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
cd build_coverage ; ninja cd cmake-build-coverage ; ninja
cd build_coverage ; ctest -j10 cd cmake-build-coverage ; ctest -j10
cd build_coverage ; ninja lcov_html cd cmake-build-coverage ; ninja lcov_html
open build_coverage/test/html/index.html open cmake-build-coverage/test/html/index.html
########################################################################## ##########################################################################
# documentation tests # documentation tests
@ -97,12 +82,13 @@ doctest:
# -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM # -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-float-equal: not all comparisons in the tests can be replaced by Approx
# -Wno-keyword-macro: unit-tests use "#define private public" # -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-padded: padding is nothing to warn about
# -Wno-range-loop-analysis: items tests "for(const auto i...)" # -Wno-range-loop-analysis: items tests "for(const auto i...)"
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches # -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
# -Wno-weak-vtables: exception class is defined inline, but has virtual method # -Wno-weak-vtables: exception class is defined inline, but has virtual method
pedantic_clang: pedantic_clang:
rm -fr build_pedantic rm -fr cmake-build-pedantic
CXXFLAGS=" \ CXXFLAGS=" \
-std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \ -std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \
-Werror \ -Werror \
@ -113,15 +99,16 @@ pedantic_clang:
-Wno-exit-time-destructors \ -Wno-exit-time-destructors \
-Wno-float-equal \ -Wno-float-equal \
-Wno-keyword-macro \ -Wno-keyword-macro \
-Wno-missing-prototypes \
-Wno-padded \ -Wno-padded \
-Wno-range-loop-analysis \ -Wno-range-loop-analysis \
-Wno-switch-enum -Wno-covered-switch-default \ -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 -Wno-weak-vtables" cmake -S . -B cmake-build-pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On
cmake --build build_pedantic cmake --build cmake-build-pedantic
# calling GCC with most warnings # calling GCC with most warnings
pedantic_gcc: pedantic_gcc:
rm -fr build_pedantic rm -fr cmake-build-pedantic
CXXFLAGS=" \ CXXFLAGS=" \
-std=c++11 \ -std=c++11 \
-pedantic \ -pedantic \
@ -253,7 +240,7 @@ pedantic_gcc:
-Wmismatched-tags \ -Wmismatched-tags \
-Wmissing-attributes \ -Wmissing-attributes \
-Wmissing-braces \ -Wmissing-braces \
-Wmissing-declarations \ -Wno-missing-declarations \
-Wmissing-field-initializers \ -Wmissing-field-initializers \
-Wmissing-include-dirs \ -Wmissing-include-dirs \
-Wmissing-profile \ -Wmissing-profile \
@ -379,19 +366,19 @@ pedantic_gcc:
-Wwrite-strings \ -Wwrite-strings \
-Wzero-as-null-pointer-constant \ -Wzero-as-null-pointer-constant \
-Wzero-length-bounds \ -Wzero-length-bounds \
" cmake -S . -B build_pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On " cmake -S . -B cmake-build-pedantic -GNinja -DCMAKE_BUILD_TYPE=Debug -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On
cmake --build build_pedantic cmake --build cmake-build-pedantic
########################################################################## ##########################################################################
# benchmarks # benchmarks
########################################################################## ##########################################################################
run_benchmarks: run_benchmarks:
rm -fr build_benchmarks rm -fr cmake-build-benchmarks
mkdir build_benchmarks mkdir cmake-build-benchmarks
cd build_benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=On cd cmake-build-benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=On
cd build_benchmarks ; ninja cd cmake-build-benchmarks ; ninja
cd build_benchmarks ; ./json_benchmarks cd cmake-build-benchmarks ; ./json_benchmarks
########################################################################## ##########################################################################
# fuzzing # fuzzing
@ -464,14 +451,14 @@ cppcheck:
# call Clang Static Analyzer <https://clang-analyzer.llvm.org> # call Clang Static Analyzer <https://clang-analyzer.llvm.org>
clang_analyze: clang_analyze:
rm -fr clang_analyze_build rm -fr cmake-build-clang-analyze
mkdir clang_analyze_build mkdir cmake-build-clang-analyze
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On cd cmake-build-clang-analyze ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On
cd clang_analyze_build ; \ cd cmake-build-clang-analyze ; \
$(COMPILER_DIR)/scan-build \ $(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 \ -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 --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 <https://github.com/cpplint/cpplint> # call cpplint <https://github.com/cpplint/cpplint>
# Note: some errors expected due to false positives # Note: some errors expected due to false positives
@ -482,22 +469,22 @@ cpplint:
# call Clang-Tidy <https://clang.llvm.org/extra/clang-tidy/> # call Clang-Tidy <https://clang.llvm.org/extra/clang-tidy/>
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 <https://www.viva64.com/en/pvs-studio/> # call PVS-Studio Analyzer <https://www.viva64.com/en/pvs-studio/>
pvs_studio: pvs_studio:
rm -fr pvs_studio_build rm -fr cmake-build-pvs-studio
mkdir pvs_studio_build mkdir cmake-build-pvs-studio
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On cd cmake-build-pvs-studio ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DJSON_MultipleHeaders=ON
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10 cd cmake-build-pvs-studio ; 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 cd cmake-build-pvs-studio ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open pvs_studio_build/pvs/index.html open cmake-build-pvs-studio/pvs/index.html
# call Infer <https://fbinfer.com> static analyzer # call Infer <https://fbinfer.com> static analyzer
infer: infer:
rm -fr infer_build rm -fr cmake-build-infer
mkdir infer_build mkdir cmake-build-infer
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4 cd cmake-build-infer ; infer compile -- cmake .. -DJSON_MultipleHeaders=ON ; infer run -- make -j 4
# call OCLint <http://oclint.org> static analyzer # call OCLint <http://oclint.org> static analyzer
oclint: oclint:
@ -506,11 +493,11 @@ oclint:
# execute the test suite with Clang sanitizers (address and undefined behavior) # execute the test suite with Clang sanitizers (address and undefined behavior)
clang_sanitize: clang_sanitize:
rm -fr clang_sanitize_build rm -fr cmake-build-clang-sanitize
mkdir clang_sanitize_build mkdir cmake-build-clang-sanitize
cd clang_sanitize_build ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On -GNinja cd cmake-build-clang-sanitize ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -DJSON_BuildTests=On -GNinja
cd clang_sanitize_build ; ninja cd cmake-build-clang-sanitize ; ninja
cd clang_sanitize_build ; ctest -j10 cd cmake-build-clang-sanitize ; ctest -j10
########################################################################## ##########################################################################
@ -538,7 +525,11 @@ pretty:
--preserve-date \ --preserve-date \
--suffix=none \ --suffix=none \
--formatted \ --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 # create single header file
amalgamate: $(AMALGAMATED_FILE) amalgamate: $(AMALGAMATED_FILE)
@ -560,7 +551,7 @@ check-amalgamation:
check-single-includes: check-single-includes:
@for x in $(SRCS); do \ @for x in $(SRCS); do \
echo "Checking self-sufficiency of $$x..." ; \ 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; \ $(CXX) $(CXXFLAGS) -Iinclude -std=c++11 single_include_test.cpp -o single_include_test; \
rm -f single_include_test.cpp single_include_test; \ rm -f single_include_test.cpp single_include_test; \
done done
@ -570,17 +561,17 @@ check-single-includes:
# CMake # 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 if all flags of our CMake files work
check_cmake_flags_do: check_cmake_flags_do:
$(CMAKE_BINARY) --version $(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; \ rm -fr cmake_build; \
mkdir cmake_build; \ mkdir cmake_build; \
echo "$(CMAKE_BINARY) .. -D$$flag=On" ; \ echo "\n\n$(CMAKE_BINARY) .. -D$$flag=On\n" ; \
cd cmake_build ; \ 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 ; \ test -f Makefile || exit 1 ; \
cd .. ; \ cd .. ; \
done; done;
@ -638,9 +629,8 @@ clean:
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html
rm -fr benchmarks/files/numbers/*.json rm -fr benchmarks/files/numbers/*.json
rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64 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 -Cdoc
$(MAKE) clean -Ctest
########################################################################## ##########################################################################
# Thirdparty code # Thirdparty code
@ -649,6 +639,6 @@ clean:
update_hedley: update_hedley:
rm -f include/nlohmann/thirdparty/hedley/hedley.hpp include/nlohmann/thirdparty/hedley/hedley_undef.hpp 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 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 $(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 | gsed 's/ //g' | gsed 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.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 $(MAKE) amalgamate

View file

@ -27,6 +27,7 @@
- [Integration](#integration) - [Integration](#integration)
- [CMake](#cmake) - [CMake](#cmake)
- [Package Managers](#package-managers) - [Package Managers](#package-managers)
- [Pkg-config](#pkg-config)
- [Examples](#examples) - [Examples](#examples)
- [JSON as first-class data type](#json-as-first-class-data-type) - [JSON as first-class data type](#json-as-first-class-data-type)
- [Serialization / Deserialization](#serialization--deserialization) - [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. 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 ## 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)). 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)).
@ -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 // called when a string is parsed; value is passed and can be safely moved away
bool string(string_t& val); 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) // 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); bool start_object(std::size_t elements);
@ -747,6 +764,7 @@ Supported types can be implicitly converted to JSON values.
It is recommended to **NOT USE** implicit conversions **FROM** a JSON value. 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 ```cpp
// strings // 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. * 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. * 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? #### 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) - GCC 4.8 - 10.1 (and possibly later)
- Clang 3.4 - 10.0 (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) - 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++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) - Microsoft Visual C++ 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 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.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 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.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.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 | | 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 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.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 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.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 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 | | 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.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 | 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) | 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 ## License
@ -1452,6 +1511,17 @@ I deeply appreciate the help of the following people.
- [XyFreak](https://github.com/XyFreak) fixed a compiler warning. - [XyFreak](https://github.com/XyFreak) fixed a compiler warning.
- [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README. - [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README.
- [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input. - [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. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
@ -1508,7 +1578,7 @@ The library supports **Unicode input** as follows:
### Comments in JSON ### 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. 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: 2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012:
@ -1519,15 +1589,13 @@ This library does not support comments. It does so for three reasons:
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. 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: 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.
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).
### Order of object keys ### 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 ### Memory Release
@ -1540,7 +1608,7 @@ Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924).
### Further notes ### 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. - 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. - 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. - **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 $ 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.

View file

@ -7,6 +7,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
@ -14,6 +15,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
@ -21,6 +23,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 16 2019 GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
@ -28,6 +31,7 @@ environment:
platform: x64 platform: x64
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 16 2019 GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
@ -36,6 +40,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Ninja GENERATOR: Ninja
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
@ -44,6 +49,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Ninja GENERATOR: Ninja
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
@ -51,6 +57,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
@ -59,6 +66,7 @@ environment:
name: with_win_header name: with_win_header
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
@ -66,6 +74,7 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "/permissive- /std:c++latest /utf-8" CXX_FLAGS: "/permissive- /std:c++latest /utf-8"
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
@ -73,6 +82,15 @@ environment:
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_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 GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
@ -80,6 +98,7 @@ environment:
platform: x64 platform: x64
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 14 2015 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
@ -87,6 +106,7 @@ environment:
platform: x64 platform: x64
CXX_FLAGS: "/permissive- /std:c++latest /Zc:__cplusplus /utf-8 /F4000000" CXX_FLAGS: "/permissive- /std:c++latest /Zc:__cplusplus /utf-8 /F4000000"
LINKER_FLAGS: "/STACK:4000000" LINKER_FLAGS: "/STACK:4000000"
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
@ -94,6 +114,7 @@ environment:
platform: x64 platform: x64
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
CMAKE_OPTIONS: ""
GENERATOR: Visual Studio 16 2019 GENERATOR: Visual Studio 16 2019
init: init:
@ -112,7 +133,7 @@ before_build:
# for with_win_header build, inject the inclusion of Windows.h to the single-header library # 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") { $header_path = "single_include\nlohmann\json.hpp" }
- ps: if ($env:name -Eq "with_win_header") { "#include <Windows.h>`n" + (Get-Content $header_path | Out-String) | Set-Content $header_path } - ps: if ($env:name -Eq "with_win_header") { "#include <Windows.h>`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: build_script:
- cmake --build . --config "%configuration%" - cmake --build . --config "%configuration%"

View file

@ -1,17 +1,22 @@
find_package(Git)
set(JSON_TEST_DATA_URL https://github.com/nlohmann/json_test_data) 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)
# 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 # target to download test data
add_custom_target(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 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})" COMMENT "Downloading test data from ${JSON_TEST_DATA_URL} (v${JSON_TEST_DATA_VERSION})"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
) )
# create a header with the path to the downloaded test data # 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") 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) # determine the operating system (for debug and support purposes)
find_program(UNAME_COMMAND uname) find_program(UNAME_COMMAND uname)

4
cmake/pkg-config.pc.in Normal file
View file

@ -0,0 +1,4 @@
Name: ${PROJECT_NAME}
Description: JSON for Modern C++
Version: ${PROJECT_VERSION}
Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}

View file

@ -5,7 +5,7 @@
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "JSON for Modern C++" PROJECT_NAME = "JSON for Modern C++"
PROJECT_NUMBER = 3.8.0 PROJECT_NUMBER = 3.9.0
PROJECT_BRIEF = PROJECT_BRIEF =
PROJECT_LOGO = PROJECT_LOGO =
OUTPUT_DIRECTORY = . OUTPUT_DIRECTORY = .

View file

@ -43,7 +43,7 @@ check_output: $(EXAMPLES:.cpp=.test)
clean: clean:
rm -fr me.nlohmann.json.docset html $(EXAMPLES:.cpp=) rm -fr me.nlohmann.json.docset html xml $(EXAMPLES:.cpp=)
########################################################################## ##########################################################################

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -1 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/EezQxM0Nzi8tTUEe"><b>online</b></a> <a target="_blank" href="https://wandbox.org/permlink/shE8T6phAQiEzAad"><b>online</b></a>

View file

@ -2,16 +2,16 @@
"compiler": { "compiler": {
"c++": "201103", "c++": "201103",
"family": "clang", "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++", "name": "JSON for Modern C++",
"platform": "apple", "platform": "apple",
"url": "https://github.com/nlohmann/json", "url": "https://github.com/nlohmann/json",
"version": { "version": {
"major": 3, "major": 3,
"minor": 8, "minor": 9,
"patch": 0, "patch": 0,
"string": "3.8.0" "string": "3.9.0"
} }
} }

View file

@ -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) @author [Niels Lohmann](http://nlohmann.me)
@see https://github.com/nlohmann/json to download the source code @see https://github.com/nlohmann/json to download the source code
@version 3.8.0 @version 3.9.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -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"
```

View file

@ -0,0 +1,253 @@
# basic_json
!!! note
This page is under construction.
Defined in header `<json.hpp>`
```cpp
template<template<typename, typename, typename...> class ObjectType,
template<typename, typename...> class ArrayType,
class StringType, class BooleanType, class NumberIntegerType,
class NumberUnsignedType, class NumberFloatType,
template<typename> class AllocatorType,
template<typename, typename = void> 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<nlohmann::json\>
- std::less<nlohmann::value_t\>
- std::swap<nlohmann::json\>

View file

@ -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"
```

View file

@ -0,0 +1,146 @@
# basic_json::parse
```cpp
// (1)
template<typename InputType>
static basic_json parse(InputType&& i,
const parser_callback_t cb = nullptr,
const bool allow_exceptions = true,
const bool ignore_comments = false)
// (2)
template<typename IteratorType>
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.

View file

@ -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. * 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? ## How do I convert third-party types?
This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:

View file

@ -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`. 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" !!! info "Unused CBOR types"
The following CBOR types are not used in the conversion: 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) - bignum (0xC2..0xC3)
- decimal fraction (0xC4) - decimal fraction (0xC4)
- bigfloat (0xC5) - bigfloat (0xC5)
- tagged items (0xC6..0xD4, 0xD8..0xDB)
- expected conversions (0xD5..0xD7) - expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8) - simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7) - undefined (0xF7)
- half-precision floats (0xF9) - half-precision floats (0xF9)
- break (0xFF) - break (0xFF)
!!! info "Tagged items"
Binary subtypes will be serialized as tagged items. See [binary values](../binary_values.md#cbor) for an example.
??? example ??? example
```cpp ```cpp
@ -150,7 +152,6 @@ Double-Precision Float | number_float | 0xFB
- bignum (0xC2..0xC3) - bignum (0xC2..0xC3)
- decimal fraction (0xC4) - decimal fraction (0xC4)
- bigfloat (0xC5) - bigfloat (0xC5)
- tagged items (0xC6..0xD4, 0xD8..0xDB)
- expected conversions (0xD5..0xD7) - expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8) - simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7) - 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. 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 ??? example
```cpp ```cpp

View file

@ -31,7 +31,8 @@ number_unsigned | 128..255 | uint 8 | 0xCC
number_unsigned | 256..65535 | uint 16 | 0xCD number_unsigned | 256..65535 | uint 16 | 0xCD
number_unsigned | 65536..4294967295 | uint 32 | 0xCE number_unsigned | 65536..4294967295 | uint 32 | 0xCE
number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF 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*: 0..31 | fixstr | 0xA0..0xBF
string | *length*: 32..255 | str 8 | 0xD9 string | *length*: 32..255 | str 8 | 0xD9
string | *length*: 256..65535 | str 16 | 0xDA string | *length*: 256..65535 | str 16 | 0xDA
@ -61,10 +62,6 @@ binary | *size*: 65536..4294967295 | bin 32 | 0xC6
- arrays with more than 4294967295 elements - arrays with more than 4294967295 elements
- objects 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" !!! 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`. If NaN or Infinity are stored inside a JSON number, they are serialized properly. function which serializes NaN or Infinity to `null`.

View file

@ -28,6 +28,7 @@ number_unsigned | 128..255 | uint8 | `U`
number_unsigned | 256..32767 | int16 | `I` number_unsigned | 256..32767 | int16 | `I`
number_unsigned | 32768..2147483647 | int32 | `l` number_unsigned | 32768..2147483647 | int32 | `l`
number_unsigned | 2147483648..9223372036854775807 | int64 | `L` number_unsigned | 2147483648..9223372036854775807 | int64 | `L`
number_unsigned | 2147483649..18446744073709551615 | high-precision | `H`
number_float | *any value* | float64 | `D` number_float | *any value* | float64 | `D`
string | *with shortest length indicator* | string | `S` string | *with shortest length indicator* | string | `S`
array | *see notes on optimized format* | array | `[` 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: The following values can **not** be converted to a UBJSON value:
- strings with more than 9223372036854775807 bytes (theoretical) - strings with more than 9223372036854775807 bytes (theoretical)
- unsigned integer numbers above 9223372036854775807
!!! info "Unused UBJSON markers" !!! info "Unused UBJSON markers"

View file

@ -158,14 +158,14 @@ JSON does not have a binary type, and this library does not introduce a new type
### CBOR ### 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 ??? example
Code: Code:
```cpp ```cpp
// create a binary value of subtype 42 (will be ignored by CBOR) // create a binary value of subtype 42
json j; json j;
j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42); 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); auto v = json::to_cbor(j);
``` ```
`v` is a `std::vector<std::uint8t>` with the following 13 elements: `v` is a `std::vector<std::uint8t>` with the following 15 elements:
```c ```c
0xA1 // map(1) 0xA1 // map(1)
0x66 // text(6) 0x66 // text(6)
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary" 0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
0xD8 0x2A // tag(42)
0x44 // bytes(4) 0x44 // bytes(4)
0xCA 0xFE 0xBA 0xBE // content 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 ```json
{ {

View file

@ -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 <iostream>
#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: '<U+000A> {<U+000A> /'; expected string literal
```
```json
{
"planets": [
"Mercury",
"Venus",
"Earth",
"Mars",
"Jupiter",
"Uranus",
"Neptune"
]
}
```

View file

@ -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 |

View file

@ -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.

View file

@ -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

View file

@ -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 |

View file

@ -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<std::string>();
```
## `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.

View file

@ -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 <iostream>
#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 <iostream>
#include <nlohmann/json.hpp>
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)).

View file

@ -14,6 +14,7 @@ interface json::sax_t {
+ {abstract} bool number_float(number_float_t val, const string_t& s) + {abstract} bool number_float(number_float_t val, const string_t& s)
+ {abstract} bool string(string_t& val) + {abstract} bool string(string_t& val)
+ {abstract} bool binary(binary_t& val)
+ {abstract} bool start_object(std::size_t elements) + {abstract} bool start_object(std::size_t elements)
+ {abstract} bool end_object() + {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 // called when a string is parsed; value is passed and can be safely moved away
bool string(string_t& val); 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) // 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); bool start_object(std::size_t elements);

View file

@ -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. 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 <iostream>
#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 <nlohmann/json.hpp>
```
## Parse errors ## Parse errors
This exception is thrown by the library when a parse error occurs. 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.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 ## Iterator errors
This exception is thrown if iterators passed to a library function do not match 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' 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 ### json.exception.out_of_range.408
The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. The size (following `#`) of an UBJSON array or object exceeds the maximal capacity.

View file

@ -2,31 +2,6 @@
## Limitations ## 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 ### Relaxed parsing
!!! question !!! question
@ -69,18 +44,6 @@ No, this is not possible. See <https://github.com/nlohmann/json/issues/932> for
## Serialization issues ## 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 ### Number precision
!!! question !!! question

View file

@ -4,7 +4,7 @@
The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): The class is licensed under the [MIT License](http://opensource.org/licenses/MIT):
Copyright &copy; 2013-2019 [Niels Lohmann](http://nlohmann.me) Copyright &copy; 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: 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:

View file

@ -3,5 +3,8 @@ import os.path
def copy_doxygen(*args, **kwargs): def copy_doxygen(*args, **kwargs):
shutil.copytree('../html', os.path.join(kwargs['config']['site_dir'], 'doxygen')) 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') print('Copy Doxygen complete')

View file

@ -44,16 +44,24 @@ nav:
- features/binary_formats/messagepack.md - features/binary_formats/messagepack.md
- features/binary_formats/ubjson.md - features/binary_formats/ubjson.md
- features/binary_values.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/iterators.md
- features/json_pointer.md - features/json_pointer.md
- features/json_patch.md - features/json_patch.md
- features/merge_patch.md - features/merge_patch.md
- features/enum_conversion.md - features/object_order.md
- Parsing: - Parsing:
- features/parsing/index.md - features/parsing/index.md
- features/parsing/parse_exceptions.md - features/parsing/parse_exceptions.md
- features/parsing/parser_callbacks.md - features/parsing/parser_callbacks.md
- features/parsing/sax_interface.md - features/parsing/sax_interface.md
- features/enum_conversion.md
- features/macros.md
- features/types.md - features/types.md
- Integration: - Integration:
- integration/index.md - integration/index.md
@ -61,6 +69,12 @@ nav:
- integration/package_managers.md - integration/package_managers.md
- Doxygen: - Doxygen:
- doxygen/index.html - 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 # Extras
extra: extra:
@ -79,6 +93,7 @@ extra:
# Extensions # Extensions
markdown_extensions: markdown_extensions:
- admonition - admonition
- def_list
- codehilite: - codehilite:
guess_lang: false guess_lang: false
- toc: - toc:

View file

@ -1,8 +0,0 @@
#pragma once
// Header <ciso646> is removed in C++20.
// See <https://github.com/nlohmann/json/issues/2089> for more information.
#if __cplusplus <= 201703L
#include <ciso646> // and, not, or
#endif

View file

@ -12,7 +12,6 @@
#include <utility> // pair, declval #include <utility> // pair, declval
#include <valarray> // valarray #include <valarray> // valarray
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
@ -26,7 +25,7 @@ namespace detail
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename std::nullptr_t& n) 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()))); JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
} }
@ -35,8 +34,8 @@ void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
// overloads for basic_json template parameters // overloads for basic_json template parameters
template < typename BasicJsonType, typename ArithmeticType, template < typename BasicJsonType, typename ArithmeticType,
enable_if_t<std::is_arithmetic<ArithmeticType>::value and enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 > int > = 0 >
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{ {
@ -66,7 +65,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) 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()))); 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<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) 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()))); 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 < template <
typename BasicJsonType, typename ConstructibleStringType, typename BasicJsonType, typename ConstructibleStringType,
enable_if_t < enable_if_t <
is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&
not std::is_same<typename BasicJsonType::string_t, !std::is_same<typename BasicJsonType::string_t,
ConstructibleStringType>::value, ConstructibleStringType>::value,
int > = 0 > int > = 0 >
void from_json(const BasicJsonType& j, ConstructibleStringType& s) 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()))); 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 // forward_list doesn't have an insert method
template<typename BasicJsonType, typename T, typename Allocator, template<typename BasicJsonType, typename T, typename Allocator,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& 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()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
@ -146,15 +145,19 @@ void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
// valarray doesn't have an insert method // valarray doesn't have an insert method
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType& j, std::valarray<T>& l) void from_json(const BasicJsonType& j, std::valarray<T>& 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()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
l.resize(j.size()); 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<T>();
});
} }
template<typename BasicJsonType, typename T, std::size_t N> template<typename BasicJsonType, typename T, std::size_t N>
@ -225,18 +228,18 @@ void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
template < typename BasicJsonType, typename ConstructibleArrayType, template < typename BasicJsonType, typename ConstructibleArrayType,
enable_if_t < enable_if_t <
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
not std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value and !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
not is_basic_json<ConstructibleArrayType>::value, !is_basic_json<ConstructibleArrayType>::value,
int > = 0 > int > = 0 >
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
j.template get<typename ConstructibleArrayType::value_type>(), j.template get<typename ConstructibleArrayType::value_type>(),
void()) 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 " + JSON_THROW(type_error::create(302, "type must be array, but is " +
std::string(j.type_name()))); std::string(j.type_name())));
@ -248,7 +251,7 @@ void())
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) 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()))); JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name())));
} }
@ -260,7 +263,7 @@ template<typename BasicJsonType, typename ConstructibleObjectType,
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0> enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) 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()))); JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
} }
@ -284,11 +287,11 @@ void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
// an arithmetic type? // an arithmetic type?
template < typename BasicJsonType, typename ArithmeticType, template < typename BasicJsonType, typename ArithmeticType,
enable_if_t < enable_if_t <
std::is_arithmetic<ArithmeticType>::value and std::is_arithmetic<ArithmeticType>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 > int > = 0 >
void from_json(const BasicJsonType& j, ArithmeticType& val) void from_json(const BasicJsonType& j, ArithmeticType& val)
{ {
@ -339,18 +342,18 @@ void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
} }
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
typename = enable_if_t<not std::is_constructible< typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >> typename BasicJsonType::string_t, Key >::value >>
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m) void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& 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()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
m.clear(); m.clear();
for (const auto& p : j) 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()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
} }
@ -359,18 +362,18 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>&
} }
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
typename = enable_if_t<not std::is_constructible< typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >> typename BasicJsonType::string_t, Key >::value >>
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m) void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& 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()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
m.clear(); m.clear();
for (const auto& p : j) 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()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
} }

View file

@ -1,14 +1,12 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cassert> // assert
#include <cmath> // signbit, isfinite #include <cmath> // signbit, isfinite
#include <cstdint> // intN_t, uintN_t #include <cstdint> // intN_t, uintN_t
#include <cstring> // memcpy, memmove #include <cstring> // memcpy, memmove
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <type_traits> // conditional #include <type_traits> // conditional
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
@ -63,8 +61,8 @@ struct diyfp // f * 2^e
*/ */
static diyfp sub(const diyfp& x, const diyfp& y) noexcept static diyfp sub(const diyfp& x, const diyfp& y) noexcept
{ {
assert(x.e == y.e); JSON_ASSERT(x.e == y.e);
assert(x.f >= y.f); JSON_ASSERT(x.f >= y.f);
return {x.f - y.f, x.e}; return {x.f - y.f, x.e};
} }
@ -140,7 +138,7 @@ struct diyfp // f * 2^e
*/ */
static diyfp normalize(diyfp x) noexcept static diyfp normalize(diyfp x) noexcept
{ {
assert(x.f != 0); JSON_ASSERT(x.f != 0);
while ((x.f >> 63u) == 0) while ((x.f >> 63u) == 0)
{ {
@ -159,8 +157,8 @@ struct diyfp // f * 2^e
{ {
const int delta = x.e - target_exponent; const int delta = x.e - target_exponent;
assert(delta >= 0); JSON_ASSERT(delta >= 0);
assert(((x.f << delta) >> delta) == x.f); JSON_ASSERT(((x.f << delta) >> delta) == x.f);
return {x.f << delta, target_exponent}; return {x.f << delta, target_exponent};
} }
@ -182,8 +180,8 @@ boundaries.
template<typename FloatType> template<typename FloatType>
boundaries compute_boundaries(FloatType value) boundaries compute_boundaries(FloatType value)
{ {
assert(std::isfinite(value)); JSON_ASSERT(std::isfinite(value));
assert(value > 0); JSON_ASSERT(value > 0);
// Convert the IEEE representation into a diyfp. // Convert the IEEE representation into a diyfp.
// //
@ -232,7 +230,7 @@ boundaries compute_boundaries(FloatType value)
// -----------------+------+------+-------------+-------------+--- (B) // -----------------+------+------+-------------+-------------+--- (B)
// v- m- v m+ v+ // 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_plus = diyfp(2 * v.f + 1, v.e - 1);
const diyfp m_minus = lower_boundary_is_closer const diyfp m_minus = lower_boundary_is_closer
? diyfp(4 * v.f - 1, v.e - 2) // (B) ? 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) // k = ceil((kAlpha - e - 1) * 0.30102999566398114)
// for |e| <= 1500, but doesn't require floating-point operations. // for |e| <= 1500, but doesn't require floating-point operations.
// NB: log_10(2) ~= 78913 / 2^18 // NB: log_10(2) ~= 78913 / 2^18
assert(e >= -1500); JSON_ASSERT(e >= -1500);
assert(e <= 1500); JSON_ASSERT(e <= 1500);
const int f = kAlpha - e - 1; const int f = kAlpha - e - 1;
const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0); const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
assert(index >= 0); JSON_ASSERT(index >= 0);
assert(static_cast<std::size_t>(index) < kCachedPowers.size()); JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)]; const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
assert(kAlpha <= cached.e + e + 64); JSON_ASSERT(kAlpha <= cached.e + e + 64);
assert(kGamma >= cached.e + e + 64); JSON_ASSERT(kGamma >= cached.e + e + 64);
return cached; 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, 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) std::uint64_t rest, std::uint64_t ten_k)
{ {
assert(len >= 1); JSON_ASSERT(len >= 1);
assert(dist <= delta); JSON_ASSERT(dist <= delta);
assert(rest <= delta); JSON_ASSERT(rest <= delta);
assert(ten_k > 0); JSON_ASSERT(ten_k > 0);
// <--------------------------- delta ----> // <--------------------------- delta ---->
// <---- dist ---------> // <---- dist --------->
@ -567,10 +565,10 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d
// integer arithmetic. // integer arithmetic.
while (rest < dist while (rest < dist
and delta - rest >= ten_k && delta - rest >= ten_k
and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
{ {
assert(buf[len - 1] != '0'); JSON_ASSERT(buf[len - 1] != '0');
buf[len - 1]--; buf[len - 1]--;
rest += ten_k; 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 // Grisu2 generates the digits of M+ from left to right and stops as soon as
// V is in [M-,M+]. // V is in [M-,M+].
assert(M_plus.e >= kAlpha); JSON_ASSERT(M_plus.e >= kAlpha);
assert(M_plus.e <= kGamma); 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 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) 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] // 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; std::uint32_t pow10;
const int k = find_largest_pow10(p1, 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 // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
// = (buffer * 10 + 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<char>('0' + d); // buffer := buffer * 10 + d buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
// //
// M+ = buffer * 10^(n-1) + (r + p2 * 2^e) // 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 // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
assert(p2 > delta); JSON_ASSERT(p2 > delta);
int m = 0; int m = 0;
for (;;) 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) ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 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<std::uint64_t>::max)() / 10); JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
p2 *= 10; p2 *= 10;
const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e 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 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^-m + 10^-m * (1/10 * (d + r * 2^e))
// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * 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<char>('0' + d); // buffer := buffer * 10 + d buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
// //
// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e // 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, inline void grisu2(char* buf, int& len, int& decimal_exponent,
diyfp m_minus, diyfp v, diyfp m_plus) diyfp m_minus, diyfp v, diyfp m_plus)
{ {
assert(m_plus.e == m_minus.e); JSON_ASSERT(m_plus.e == m_minus.e);
assert(m_plus.e == v.e); JSON_ASSERT(m_plus.e == v.e);
// --------(-----------------------+-----------------------)-------- (A) // --------(-----------------------+-----------------------)-------- (A)
// m- v m+ // m- v m+
@ -886,8 +884,8 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3, static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
"internal error: not enough precision"); "internal error: not enough precision");
assert(std::isfinite(value)); JSON_ASSERT(std::isfinite(value));
assert(value > 0); JSON_ASSERT(value > 0);
// If the neighbors (and boundaries) of 'value' are always computed for double-precision // 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 // 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 JSON_HEDLEY_RETURNS_NON_NULL
inline char* append_exponent(char* buf, int e) inline char* append_exponent(char* buf, int e)
{ {
assert(e > -1000); JSON_ASSERT(e > -1000);
assert(e < 1000); JSON_ASSERT(e < 1000);
if (e < 0) if (e < 0)
{ {
@ -976,8 +974,8 @@ JSON_HEDLEY_RETURNS_NON_NULL
inline char* format_buffer(char* buf, int len, int decimal_exponent, inline char* format_buffer(char* buf, int len, int decimal_exponent,
int min_exp, int max_exp) int min_exp, int max_exp)
{ {
assert(min_exp < 0); JSON_ASSERT(min_exp < 0);
assert(max_exp > 0); JSON_ASSERT(max_exp > 0);
const int k = len; const int k = len;
const int n = len + decimal_exponent; 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) // 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. // 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] // digits[000]
// len <= max_exp + 2 // len <= max_exp + 2
@ -998,19 +996,19 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
return buf + (static_cast<size_t>(n) + 2); return buf + (static_cast<size_t>(n) + 2);
} }
if (0 < n and n <= max_exp) if (0 < n && n <= max_exp)
{ {
// dig.its // dig.its
// len <= max_digits10 + 1 // len <= max_digits10 + 1
assert(k > n); JSON_ASSERT(k > n);
std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n)); std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
buf[n] = '.'; buf[n] = '.';
return buf + (static_cast<size_t>(k) + 1U); return buf + (static_cast<size_t>(k) + 1U);
} }
if (min_exp < n and n <= 0) if (min_exp < n && n <= 0)
{ {
// 0.[000]digits // 0.[000]digits
// len <= 2 + (-min_exp - 1) + max_digits10 // len <= 2 + (-min_exp - 1) + max_digits10
@ -1061,7 +1059,7 @@ JSON_HEDLEY_RETURNS_NON_NULL
char* to_chars(char* first, const char* last, FloatType value) char* to_chars(char* first, const char* last, FloatType value)
{ {
static_cast<void>(last); // maybe unused - fix warning static_cast<void>(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. // Use signbit(value) instead of (value < 0) since signbit works for -0.
if (std::signbit(value)) if (std::signbit(value))
@ -1079,7 +1077,7 @@ char* to_chars(char* first, const char* last, FloatType value)
return first; return first;
} }
assert(last - first >= std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
// Compute v = buffer * 10^decimal_exponent. // Compute v = buffer * 10^decimal_exponent.
// The decimal digits are stored in the buffer, which needs to be interpreted // 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; int decimal_exponent = 0;
dtoa_impl::grisu2(first, len, decimal_exponent, value); dtoa_impl::grisu2(first, len, decimal_exponent, value);
assert(len <= std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
// Format the buffer like printf("%.*g", prec, value) // Format the buffer like printf("%.*g", prec, value)
constexpr int kMinExp = -4; constexpr int kMinExp = -4;
// Use digits10 here to increase compatibility with version 2. // Use digits10 here to increase compatibility with version 2.
constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10; constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
assert(last - first >= kMaxExp + 2); JSON_ASSERT(last - first >= kMaxExp + 2);
assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6); JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
} }

View file

@ -9,7 +9,6 @@
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp> #include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
@ -57,7 +56,7 @@ struct external_constructor<value_t::string>
} }
template < typename BasicJsonType, typename CompatibleStringType, template < typename BasicJsonType, typename CompatibleStringType,
enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value, enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
int > = 0 > int > = 0 >
static void construct(BasicJsonType& j, const CompatibleStringType& str) static void construct(BasicJsonType& j, const CompatibleStringType& str)
{ {
@ -145,7 +144,7 @@ struct external_constructor<value_t::array>
} }
template < typename BasicJsonType, typename CompatibleArrayType, template < typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value, enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
int > = 0 > int > = 0 >
static void construct(BasicJsonType& j, const CompatibleArrayType& arr) static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
@ -204,7 +203,7 @@ struct external_constructor<value_t::object>
} }
template < typename BasicJsonType, typename CompatibleObjectType, template < typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0> enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
static void construct(BasicJsonType& j, const CompatibleObjectType& obj) static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
using std::begin; using std::begin;
@ -277,11 +276,11 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e)
template < typename BasicJsonType, typename CompatibleArrayType, template < typename BasicJsonType, typename CompatibleArrayType,
enable_if_t < is_compatible_array_type<BasicJsonType, enable_if_t < is_compatible_array_type<BasicJsonType,
CompatibleArrayType>::value and CompatibleArrayType>::value&&
not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
not std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value and !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
not is_basic_json<CompatibleArrayType>::value, !is_basic_json<CompatibleArrayType>::value,
int > = 0 > int > = 0 >
void to_json(BasicJsonType& j, const CompatibleArrayType& arr) void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
@ -308,7 +307,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
} }
template < typename BasicJsonType, typename CompatibleObjectType, template < typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0> enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
void to_json(BasicJsonType& j, const CompatibleObjectType& obj) void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
external_constructor<value_t::object>::construct(j, obj); external_constructor<value_t::object>::construct(j, obj);
@ -322,7 +321,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
template < template <
typename BasicJsonType, typename T, std::size_t N, typename BasicJsonType, typename T, std::size_t N,
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
const T(&)[N]>::value, const T(&)[N]>::value,
int > = 0 > int > = 0 >
void to_json(BasicJsonType& j, const T(&arr)[N]) void to_json(BasicJsonType& j, const T(&arr)[N])

View file

@ -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.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.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.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 @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 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.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.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.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.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 | 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 |

View file

@ -0,0 +1,117 @@
#pragma once
#include <cstddef> // size_t, uint8_t
#include <functional> // 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<typename BasicJsonType>
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<std::size_t>(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<string_t> {}(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<string_t> {}(j.template get_ref<const string_t&>());
return combine(type, h);
}
case BasicJsonType::value_t::boolean:
{
const auto h = std::hash<bool> {}(j.template get<bool>());
return combine(type, h);
}
case BasicJsonType::value_t::number_integer:
{
const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
return combine(type, h);
}
case nlohmann::detail::value_t::number_unsigned:
{
const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
return combine(type, h);
}
case nlohmann::detail::value_t::number_float:
{
const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
return combine(type, h);
}
case nlohmann::detail::value_t::binary:
{
auto seed = combine(type, j.get_binary().size());
const auto h = std::hash<bool> {}(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<std::uint8_t> {}(byte));
}
return seed;
}
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
}
} // namespace detail
} // namespace nlohmann

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cassert> // assert
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdio> //FILE * #include <cstdio> //FILE *
#include <cstring> // strlen #include <cstring> // strlen
@ -76,7 +75,7 @@ class input_stream_adapter
{ {
// clear stream flags; we use underlying streambuf I/O, do not // clear stream flags; we use underlying streambuf I/O, do not
// maintain ifstream flags, except eof // maintain ifstream flags, except eof
if (is) if (is != nullptr)
{ {
is->clear(is->rdstate() & std::ios::eofbit); 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&) = delete;
input_stream_adapter& operator=(input_stream_adapter&& rhs) = 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.is = nullptr;
rhs.sb = nullptr; rhs.sb = nullptr;
@ -251,7 +250,7 @@ struct wide_string_input_helper<BaseInputAdapter, 2>
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
utf8_bytes_filled = 2; utf8_bytes_filled = 2;
} }
else if (0xD800 > wc or wc >= 0xE000) else if (0xD800 > wc || wc >= 0xE000)
{ {
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u))); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
@ -260,7 +259,7 @@ struct wide_string_input_helper<BaseInputAdapter, 2>
} }
else else
{ {
if (JSON_HEDLEY_UNLIKELY(not input.empty())) if (JSON_HEDLEY_UNLIKELY(!input.empty()))
{ {
const auto wc2 = static_cast<unsigned int>(input.get_character()); const auto wc2 = static_cast<unsigned int>(input.get_character());
const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
@ -297,13 +296,13 @@ class wide_string_input_adapter
{ {
fill_buffer<sizeof(WideCharType)>(); fill_buffer<sizeof(WideCharType)>();
assert(utf8_bytes_filled > 0); JSON_ASSERT(utf8_bytes_filled > 0);
assert(utf8_bytes_index == 0); JSON_ASSERT(utf8_bytes_index == 0);
} }
// use buffer // use buffer
assert(utf8_bytes_filled > 0); JSON_ASSERT(utf8_bytes_filled > 0);
assert(utf8_bytes_index < utf8_bytes_filled); JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
return utf8_bytes[utf8_bytes_index++]; return utf8_bytes[utf8_bytes_index++];
} }
@ -403,15 +402,15 @@ using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const
// Null-delimited strings, and the like. // Null-delimited strings, and the like.
template < typename CharT, template < typename CharT,
typename std::enable_if < typename std::enable_if <
std::is_pointer<CharT>::value and std::is_pointer<CharT>::value&&
not std::is_array<CharT>::value and !std::is_array<CharT>::value&&
std::is_integral<typename std::remove_pointer<CharT>::type>::value and std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
sizeof(typename std::remove_pointer<CharT>::type) == 1, sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 > int >::type = 0 >
contiguous_bytes_input_adapter input_adapter(CharT b) contiguous_bytes_input_adapter input_adapter(CharT b)
{ {
auto length = std::strlen(reinterpret_cast<const char*>(b)); auto length = std::strlen(reinterpret_cast<const char*>(b));
auto ptr = reinterpret_cast<const char*>(b); const auto* ptr = reinterpret_cast<const char*>(b);
return input_adapter(ptr, ptr + length); return input_adapter(ptr, ptr + length);
} }
@ -429,8 +428,8 @@ class span_input_adapter
public: public:
template < typename CharT, template < typename CharT,
typename std::enable_if < typename std::enable_if <
std::is_pointer<CharT>::value and std::is_pointer<CharT>::value&&
std::is_integral<typename std::remove_pointer<CharT>::type>::value and std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
sizeof(typename std::remove_pointer<CharT>::type) == 1, sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 > int >::type = 0 >
span_input_adapter(CharT b, std::size_t l) span_input_adapter(CharT b, std::size_t l)

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cassert> // assert
#include <cstddef> #include <cstddef>
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
@ -218,7 +217,7 @@ class json_sax_dom_parser
{ {
ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); 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, JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(len))); "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)); 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, JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(len))); "excessive array size: " + std::to_string(len)));
@ -259,30 +258,15 @@ class json_sax_dom_parser
return true; return true;
} }
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
const detail::exception& ex) const Exception& ex)
{ {
errored = true; errored = true;
static_cast<void>(ex);
if (allow_exceptions) if (allow_exceptions)
{ {
// determine the proper exception type from the id JSON_THROW(ex);
switch ((ex.id / 100) % 100)
{
case 1:
JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
case 4:
JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START
case 2:
JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
case 3:
JSON_THROW(*static_cast<const detail::type_error*>(&ex));
case 5:
JSON_THROW(*static_cast<const detail::other_error*>(&ex));
default:
assert(false);
// LCOV_EXCL_STOP
}
} }
return false; return false;
} }
@ -309,7 +293,7 @@ class json_sax_dom_parser
return &root; 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()) if (ref_stack.back()->is_array())
{ {
@ -317,8 +301,8 @@ class json_sax_dom_parser
return &(ref_stack.back()->m_value.array->back()); return &(ref_stack.back()->m_value.array->back());
} }
assert(ref_stack.back()->is_object()); JSON_ASSERT(ref_stack.back()->is_object());
assert(object_element); JSON_ASSERT(object_element);
*object_element = BasicJsonType(std::forward<Value>(v)); *object_element = BasicJsonType(std::forward<Value>(v));
return object_element; return object_element;
} }
@ -414,7 +398,7 @@ class json_sax_dom_callback_parser
ref_stack.push_back(val.second); ref_stack.push_back(val.second);
// check object limit // 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))); 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); key_keep_stack.push_back(keep);
// add discarded value at given key and store the reference for later // 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); object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
} }
@ -441,18 +425,18 @@ class json_sax_dom_callback_parser
bool end_object() bool end_object()
{ {
if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) if (ref_stack.back() && !callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{ {
// discard object // discard object
*ref_stack.back() = discarded; *ref_stack.back() = discarded;
} }
assert(not ref_stack.empty()); JSON_ASSERT(!ref_stack.empty());
assert(not keep_stack.empty()); JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back(); ref_stack.pop_back();
keep_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 // remove discarded value
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) 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); ref_stack.push_back(val.second);
// check array limit // 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))); 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()) if (ref_stack.back())
{ {
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
if (not keep) if (!keep)
{ {
// discard array // discard array
*ref_stack.back() = discarded; *ref_stack.back() = discarded;
} }
} }
assert(not ref_stack.empty()); JSON_ASSERT(!ref_stack.empty());
assert(not keep_stack.empty()); JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back(); ref_stack.pop_back();
keep_stack.pop_back(); keep_stack.pop_back();
// remove discarded value // 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(); ref_stack.back()->m_value.array->pop_back();
} }
@ -513,30 +497,15 @@ class json_sax_dom_callback_parser
return true; return true;
} }
template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
const detail::exception& ex) const Exception& ex)
{ {
errored = true; errored = true;
static_cast<void>(ex);
if (allow_exceptions) if (allow_exceptions)
{ {
// determine the proper exception type from the id JSON_THROW(ex);
switch ((ex.id / 100) % 100)
{
case 1:
JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
case 4:
JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START
case 2:
JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
case 3:
JSON_THROW(*static_cast<const detail::type_error*>(&ex));
case 5:
JSON_THROW(*static_cast<const detail::other_error*>(&ex));
default:
assert(false);
// LCOV_EXCL_STOP
}
} }
return false; return false;
} }
@ -565,11 +534,11 @@ class json_sax_dom_callback_parser
template<typename Value> template<typename Value>
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false) std::pair<bool, BasicJsonType*> 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 // do not handle this value if we know it would be added to a discarded
// container // container
if (not keep_stack.back()) if (!keep_stack.back())
{ {
return {false, nullptr}; return {false, nullptr};
} }
@ -578,10 +547,10 @@ class json_sax_dom_callback_parser
auto value = BasicJsonType(std::forward<Value>(v)); auto value = BasicJsonType(std::forward<Value>(v));
// check callback // check callback
const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value); const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
// do not handle this value if we just learnt it shall be discarded // do not handle this value if we just learnt it shall be discarded
if (not keep) if (!keep)
{ {
return {false, nullptr}; return {false, nullptr};
} }
@ -594,13 +563,13 @@ class json_sax_dom_callback_parser
// skip this value if we already decided to skip the parent // skip this value if we already decided to skip the parent
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
if (not ref_stack.back()) if (!ref_stack.back())
{ {
return {false, nullptr}; return {false, nullptr};
} }
// we now only expect arrays and objects // 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 // array
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
@ -610,18 +579,18 @@ class json_sax_dom_callback_parser
} }
// object // 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 // 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(); const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back(); key_keep_stack.pop_back();
if (not store_element) if (!store_element)
{ {
return {false, nullptr}; return {false, nullptr};
} }
assert(object_element); JSON_ASSERT(object_element);
*object_element = std::move(value); *object_element = std::move(value);
return {true, object_element}; return {true, object_element};
} }

View file

@ -112,8 +112,11 @@ class lexer : public lexer_base<BasicJsonType>
public: public:
using token_type = typename lexer_base<BasicJsonType>::token_type; using token_type = typename lexer_base<BasicJsonType>::token_type;
explicit lexer(InputAdapterType&& adapter) explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false)
: ia(std::move(adapter)), decimal_point_char(static_cast<char_int_type>(get_decimal_point())) {} : ia(std::move(adapter))
, ignore_comments(ignore_comments_)
, decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
{}
// delete because of pointer members // delete because of pointer members
lexer(const lexer&) = delete; lexer(const lexer&) = delete;
@ -131,8 +134,8 @@ class lexer : public lexer_base<BasicJsonType>
JSON_HEDLEY_PURE JSON_HEDLEY_PURE
static char get_decimal_point() noexcept static char get_decimal_point() noexcept
{ {
const auto loc = localeconv(); const auto* loc = localeconv();
assert(loc != nullptr); JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
} }
@ -158,7 +161,7 @@ class lexer : public lexer_base<BasicJsonType>
int get_codepoint() int get_codepoint()
{ {
// this function only makes sense after reading `\u` // this function only makes sense after reading `\u`
assert(current == 'u'); JSON_ASSERT(current == 'u');
int codepoint = 0; int codepoint = 0;
const auto factors = { 12u, 8u, 4u, 0u }; const auto factors = { 12u, 8u, 4u, 0u };
@ -166,15 +169,15 @@ class lexer : public lexer_base<BasicJsonType>
{ {
get(); get();
if (current >= '0' and current <= '9') if (current >= '0' && current <= '9')
{ {
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
} }
else if (current >= 'A' and current <= 'F') else if (current >= 'A' && current <= 'F')
{ {
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
} }
else if (current >= 'a' and current <= 'f') else if (current >= 'a' && current <= 'f')
{ {
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
} }
@ -184,7 +187,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
} }
assert(0x0000 <= codepoint and codepoint <= 0xFFFF); JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
return codepoint; return codepoint;
} }
@ -205,13 +208,13 @@ class lexer : public lexer_base<BasicJsonType>
*/ */
bool next_byte_in_range(std::initializer_list<char_int_type> ranges) bool next_byte_in_range(std::initializer_list<char_int_type> 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); add(current);
for (auto range = ranges.begin(); range != ranges.end(); ++range) for (auto range = ranges.begin(); range != ranges.end(); ++range)
{ {
get(); get();
if (JSON_HEDLEY_LIKELY(*range <= current and current <= *(++range))) if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))
{ {
add(current); add(current);
} }
@ -246,7 +249,7 @@ class lexer : public lexer_base<BasicJsonType>
reset(); reset();
// we entered the function by reading an open quote // we entered the function by reading an open quote
assert(current == '\"'); JSON_ASSERT(current == '\"');
while (true) while (true)
{ {
@ -317,10 +320,10 @@ class lexer : public lexer_base<BasicJsonType>
} }
// check if code point is a high surrogate // check if code point is a high surrogate
if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
{ {
// expect next \uxxxx entry // expect next \uxxxx entry
if (JSON_HEDLEY_LIKELY(get() == '\\' and get() == 'u')) if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
{ {
const int codepoint2 = get_codepoint(); const int codepoint2 = get_codepoint();
@ -331,7 +334,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
// check if codepoint2 is a low surrogate // 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 // overwrite codepoint
codepoint = static_cast<int>( codepoint = static_cast<int>(
@ -358,7 +361,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
else 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"; error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
return token_type::parse_error; return token_type::parse_error;
@ -366,7 +369,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
// result of the above calculation yields a proper codepoint // 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 // translate codepoint into bytes
if (codepoint < 0x80) if (codepoint < 0x80)
@ -733,7 +736,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xDE: case 0xDE:
case 0xDF: 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; return token_type::parse_error;
} }
@ -743,7 +746,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+0800..U+0FFF: bytes E0 A0..BF 80..BF // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case 0xE0: 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; return token_type::parse_error;
} }
@ -767,7 +770,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xEE: case 0xEE:
case 0xEF: 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; return token_type::parse_error;
} }
@ -777,7 +780,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+D000..U+D7FF: bytes ED 80..9F 80..BF // U+D000..U+D7FF: bytes ED 80..9F 80..BF
case 0xED: 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; return token_type::parse_error;
} }
@ -787,7 +790,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case 0xF0: 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; return token_type::parse_error;
} }
@ -799,7 +802,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xF2: case 0xF2:
case 0xF3: 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; return token_type::parse_error;
} }
@ -809,7 +812,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case 0xF4: 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; return token_type::parse_error;
} }
@ -826,6 +829,77 @@ class lexer : public lexer_base<BasicJsonType>
} }
} }
/*!
* @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<char_type>::eof():
case '\0':
return true;
default:
break;
}
}
}
// multi-line comments skip input until */ is read
case '*':
{
while (true)
{
switch (get())
{
case std::char_traits<char_type>::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) JSON_HEDLEY_NON_NULL(2)
static void strtof(float& f, const char* str, char** endptr) noexcept static void strtof(float& f, const char* str, char** endptr) noexcept
{ {
@ -924,7 +998,7 @@ class lexer : public lexer_base<BasicJsonType>
// all other characters are rejected outside scan_number() // all other characters are rejected outside scan_number()
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
scan_number_minus: scan_number_minus:
@ -1171,7 +1245,7 @@ scan_number_done:
const auto x = std::strtoull(token_buffer.data(), &endptr, 10); const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
// we checked the number format before // 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) if (errno == 0)
{ {
@ -1187,7 +1261,7 @@ scan_number_done:
const auto x = std::strtoll(token_buffer.data(), &endptr, 10); const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
// we checked the number format before // 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) if (errno == 0)
{ {
@ -1204,7 +1278,7 @@ scan_number_done:
strtof(value_float, token_buffer.data(), &endptr); strtof(value_float, token_buffer.data(), &endptr);
// we checked the number format before // 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; 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 scan_literal(const char_type* literal_text, const std::size_t length,
token_type return_type) token_type return_type)
{ {
assert(std::char_traits<char_type>::to_char_type(current) == literal_text[0]); JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
for (std::size_t i = 1; i < length; ++i) for (std::size_t i = 1; i < length; ++i)
{ {
if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i])) if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
@ -1310,7 +1384,7 @@ scan_number_done:
if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof())) if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
{ {
assert(not token_string.empty()); JSON_ASSERT(!token_string.empty());
token_string.pop_back(); token_string.pop_back();
} }
} }
@ -1406,7 +1480,7 @@ scan_number_done:
if (get() == 0xEF) if (get() == 0xEF)
{ {
// check if we completely parse the BOM // 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 // the first character is not the beginning of the BOM; unget it to
@ -1415,21 +1489,38 @@ scan_number_done:
return true; return true;
} }
void skip_whitespace()
{
do
{
get();
}
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
}
token_type scan() token_type scan()
{ {
// initially, skip the BOM // 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"; error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
return token_type::parse_error; return token_type::parse_error;
} }
// read next character and ignore whitespace // 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) switch (current)
{ {
@ -1499,6 +1590,9 @@ scan_number_done:
/// input adapter /// input adapter
InputAdapterType ia; InputAdapterType ia;
/// whether comments should be ignored (true) or signaled as errors (false)
const bool ignore_comments = false;
/// the current character /// the current character
char_int_type current = std::char_traits<char_type>::eof(); char_int_type current = std::char_traits<char_type>::eof();

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cassert> // assert
#include <cmath> // isfinite #include <cmath> // isfinite
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <functional> // function #include <functional> // function
@ -63,8 +62,11 @@ class parser
/// a parser reading from an input adapter /// a parser reading from an input adapter
explicit parser(InputAdapterType&& adapter, explicit parser(InputAdapterType&& adapter,
const parser_callback_t<BasicJsonType> cb = nullptr, const parser_callback_t<BasicJsonType> cb = nullptr,
const bool allow_exceptions_ = true) const bool allow_exceptions_ = true,
: callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_) const bool skip_comments = false)
: callback(cb)
, m_lexer(std::move(adapter), skip_comments)
, allow_exceptions(allow_exceptions_)
{ {
// read first token // read first token
get_token(); get_token();
@ -89,7 +91,7 @@ class parser
result.assert_invariant(); result.assert_invariant();
// in strict mode, input must be completely read // 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(), sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@ -118,7 +120,7 @@ class parser
result.assert_invariant(); result.assert_invariant();
// in strict mode, input must be completely read // 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(), sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@ -155,7 +157,7 @@ class parser
const bool result = sax_parse_internal(sax); const bool result = sax_parse_internal(sax);
// strict mode: next byte must be EOF // 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(), return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@ -179,14 +181,14 @@ class parser
while (true) while (true)
{ {
if (not skip_to_state_evaluation) if (!skip_to_state_evaluation)
{ {
// invariant: get_token() was called before each iteration // invariant: get_token() was called before each iteration
switch (last_token) switch (last_token)
{ {
case token_type::begin_object: 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; return false;
} }
@ -194,7 +196,7 @@ class parser
// closing } -> we are done // closing } -> we are done
if (get_token() == token_type::end_object) if (get_token() == token_type::end_object)
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->end_object())) if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{ {
return false; return false;
} }
@ -209,7 +211,7 @@ class parser
parse_error::create(101, m_lexer.get_position(), parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::value_string, "object key"))); 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; return false;
} }
@ -233,7 +235,7 @@ class parser
case token_type::begin_array: 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; return false;
} }
@ -241,7 +243,7 @@ class parser
// closing ] -> we are done // closing ] -> we are done
if (get_token() == token_type::end_array) if (get_token() == token_type::end_array)
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->end_array())) if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
{ {
return false; return false;
} }
@ -259,14 +261,14 @@ class parser
{ {
const auto res = m_lexer.get_number_float(); 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(), return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
out_of_range::create(406, "number overflow parsing '" + 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; return false;
} }
@ -276,7 +278,7 @@ class parser
case token_type::literal_false: case token_type::literal_false:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->boolean(false))) if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
{ {
return false; return false;
} }
@ -285,7 +287,7 @@ class parser
case token_type::literal_null: case token_type::literal_null:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->null())) if (JSON_HEDLEY_UNLIKELY(!sax->null()))
{ {
return false; return false;
} }
@ -294,7 +296,7 @@ class parser
case token_type::literal_true: case token_type::literal_true:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->boolean(true))) if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
{ {
return false; return false;
} }
@ -303,7 +305,7 @@ class parser
case token_type::value_integer: 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; return false;
} }
@ -312,7 +314,7 @@ class parser
case token_type::value_string: 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; return false;
} }
@ -321,7 +323,7 @@ class parser
case token_type::value_unsigned: 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; return false;
} }
@ -371,7 +373,7 @@ class parser
// closing ] // closing ]
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) 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; return false;
} }
@ -380,7 +382,7 @@ class parser
// new value, we need to evaluate the new state first. // new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we // By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if. // are effectively jumping to the beginning of this if.
assert(not states.empty()); JSON_ASSERT(!states.empty());
states.pop_back(); states.pop_back();
skip_to_state_evaluation = true; skip_to_state_evaluation = true;
continue; continue;
@ -405,7 +407,7 @@ class parser
exception_message(token_type::value_string, "object key"))); 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; return false;
} }
@ -427,7 +429,7 @@ class parser
// closing } // closing }
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) 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; return false;
} }
@ -436,7 +438,7 @@ class parser
// new value, we need to evaluate the new state first. // new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we // By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if. // are effectively jumping to the beginning of this if.
assert(not states.empty()); JSON_ASSERT(!states.empty());
states.pop_back(); states.pop_back();
skip_to_state_evaluation = true; skip_to_state_evaluation = true;
continue; continue;
@ -460,7 +462,7 @@ class parser
{ {
std::string error_msg = "syntax error "; std::string error_msg = "syntax error ";
if (not context.empty()) if (!context.empty())
{ {
error_msg += "while parsing " + context + " "; error_msg += "while parsing " + context + " ";
} }

View file

@ -18,8 +18,6 @@ template<typename BasicJsonType> struct internal_iterator
typename BasicJsonType::object_t::iterator object_iterator {}; typename BasicJsonType::object_t::iterator object_iterator {};
/// iterator for JSON arrays /// iterator for JSON arrays
typename BasicJsonType::array_t::iterator array_iterator {}; 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 /// generic iterator for all other types
primitive_iterator_t primitive_iterator {}; primitive_iterator_t primitive_iterator {};
}; };

View file

@ -3,7 +3,6 @@
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
#include <type_traits> // conditional, is_const, remove_const #include <type_traits> // conditional, is_const, remove_const
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/iterators/internal_iterator.hpp> #include <nlohmann/detail/iterators/internal_iterator.hpp>
#include <nlohmann/detail/iterators/primitive_iterator.hpp> #include <nlohmann/detail/iterators/primitive_iterator.hpp>
@ -85,7 +84,7 @@ class iter_impl
*/ */
explicit iter_impl(pointer object) noexcept : m_object(object) explicit iter_impl(pointer object) noexcept : m_object(object)
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -171,7 +170,7 @@ class iter_impl
*/ */
void set_begin() noexcept void set_begin() noexcept
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -208,7 +207,7 @@ class iter_impl
*/ */
void set_end() noexcept void set_end() noexcept
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -239,19 +238,19 @@ class iter_impl
*/ */
reference operator*() const reference operator*() const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
case value_t::object: 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; return m_it.object_iterator->second;
} }
case value_t::array: 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; return *m_it.array_iterator;
} }
@ -276,19 +275,19 @@ class iter_impl
*/ */
pointer operator->() const pointer operator->() const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
case value_t::object: 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); return &(m_it.object_iterator->second);
} }
case value_t::array: 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; return &*m_it.array_iterator;
} }
@ -321,7 +320,7 @@ class iter_impl
*/ */
iter_impl& operator++() iter_impl& operator++()
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -364,7 +363,7 @@ class iter_impl
*/ */
iter_impl& operator--() iter_impl& operator--()
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -402,7 +401,7 @@ class iter_impl
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); 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) switch (m_object->m_type)
{ {
@ -423,7 +422,7 @@ class iter_impl
*/ */
bool operator!=(const iter_impl& other) const 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")); 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) switch (m_object->m_type)
{ {
@ -459,7 +458,7 @@ class iter_impl
*/ */
bool operator<=(const iter_impl& other) const 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 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 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) iter_impl& operator+=(difference_type i)
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -557,7 +556,7 @@ class iter_impl
*/ */
difference_type operator-(const iter_impl& other) const difference_type operator-(const iter_impl& other) const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -578,7 +577,7 @@ class iter_impl
*/ */
reference operator[](difference_type n) const reference operator[](difference_type n) const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@ -609,7 +608,7 @@ class iter_impl
*/ */
const typename object_t::key_type& key() const 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())) if (JSON_HEDLEY_LIKELY(m_object->is_object()))
{ {

View file

@ -15,7 +15,9 @@ namespace detail
template<typename string_type> template<typename string_type>
void int_to_string( string_type& target, std::size_t value ) 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<typename IteratorType> class iteration_proxy_value template<typename IteratorType> class iteration_proxy_value
{ {
@ -72,7 +74,7 @@ template <typename IteratorType> class iteration_proxy_value
/// return key of the iterator /// return key of the iterator
const string_type& key() const const string_type& key() const
{ {
assert(anchor.m_object != nullptr); JSON_ASSERT(anchor.m_object != nullptr);
switch (anchor.m_object->type()) switch (anchor.m_object->type())
{ {

View file

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <algorithm> // all_of #include <algorithm> // all_of
#include <cassert> // assert
#include <cctype> // isdigit #include <cctype> // isdigit
#include <limits> // max
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
@ -325,12 +325,17 @@ class json_pointer
@return integer representation of @a s @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.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) // 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, JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + s + "array index '" + s +
@ -338,16 +343,16 @@ class json_pointer
} }
// error condition (cf. RFC 6901, Sect. 4) // 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")); JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number"));
} }
std::size_t processed_chars = 0; std::size_t processed_chars = 0;
int res = 0; unsigned long long res = 0;
JSON_TRY JSON_TRY
{ {
res = std::stoi(s, &processed_chars); res = std::stoull(s, &processed_chars);
} }
JSON_CATCH(std::out_of_range&) 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 + "'")); 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<unsigned long long>((std::numeric_limits<size_type>::max)()))
{
JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE
}
return static_cast<size_type>(res);
} }
json_pointer top() const json_pointer top() const
@ -385,7 +397,6 @@ class json_pointer
*/ */
BasicJsonType& get_and_create(BasicJsonType& j) const BasicJsonType& get_and_create(BasicJsonType& j) const
{ {
using size_type = typename BasicJsonType::size_type;
auto result = &j; auto result = &j;
// in case no reference tokens exist, return a reference to the JSON value // 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: case detail::value_t::array:
{ {
// create an entry in the array // create an entry in the array
result = &result->operator[](static_cast<size_type>(array_index(reference_token))); result = &result->operator[](array_index(reference_token));
break; break;
} }
@ -458,7 +469,6 @@ class json_pointer
*/ */
BasicJsonType& get_unchecked(BasicJsonType* ptr) const BasicJsonType& get_unchecked(BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
// convert null values to arrays or objects before continuing // 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 // 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::array
: detail::value_t::object; : detail::value_t::object;
} }
@ -497,8 +507,7 @@ class json_pointer
else else
{ {
// convert array index to number; unchecked access // convert array index to number; unchecked access
ptr = &ptr->operator[]( ptr = &ptr->operator[](array_index(reference_token));
static_cast<size_type>(array_index(reference_token)));
} }
break; break;
} }
@ -519,7 +528,6 @@ class json_pointer
*/ */
BasicJsonType& get_checked(BasicJsonType* ptr) const BasicJsonType& get_checked(BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
@ -542,7 +550,7 @@ class json_pointer
} }
// note: at performs range check // note: at performs range check
ptr = &ptr->at(static_cast<size_type>(array_index(reference_token))); ptr = &ptr->at(array_index(reference_token));
break; break;
} }
@ -569,7 +577,6 @@ class json_pointer
*/ */
const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
@ -592,8 +599,7 @@ class json_pointer
} }
// use unchecked array access // use unchecked array access
ptr = &ptr->operator[]( ptr = &ptr->operator[](array_index(reference_token));
static_cast<size_type>(array_index(reference_token)));
break; break;
} }
@ -613,7 +619,6 @@ class json_pointer
*/ */
const BasicJsonType& get_checked(const BasicJsonType* ptr) const const BasicJsonType& get_checked(const BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
@ -636,7 +641,7 @@ class json_pointer
} }
// note: at performs range check // note: at performs range check
ptr = &ptr->at(static_cast<size_type>(array_index(reference_token))); ptr = &ptr->at(array_index(reference_token));
break; break;
} }
@ -654,14 +659,13 @@ class json_pointer
*/ */
bool contains(const BasicJsonType* ptr) const bool contains(const BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
{ {
case detail::value_t::object: 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 // we did not find the key in the object
return false; return false;
@ -678,21 +682,21 @@ class json_pointer
// "-" always fails the range check // "-" always fails the range check
return false; 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 // invalid char
return false; return false;
} }
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) 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' // first char should be between '1' and '9'
return false; return false;
} }
for (std::size_t i = 1; i < reference_token.size(); i++) 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' // other char should be between '0' and '9'
return false; return false;
@ -700,7 +704,7 @@ class json_pointer
} }
} }
const auto idx = static_cast<size_type>(array_index(reference_token)); const auto idx = array_index(reference_token);
if (idx >= ptr->size()) if (idx >= ptr->size())
{ {
// index out of range // index out of range
@ -776,11 +780,11 @@ class json_pointer
pos != std::string::npos; pos != std::string::npos;
pos = reference_token.find_first_of('~', pos + 1)) pos = reference_token.find_first_of('~', pos + 1))
{ {
assert(reference_token[pos] == '~'); JSON_ASSERT(reference_token[pos] == '~');
// ~ must be followed by 0 or 1 // ~ must be followed by 0 or 1
if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
(reference_token[pos + 1] != '0' and (reference_token[pos + 1] != '0' &&
reference_token[pos + 1] != '1'))) reference_token[pos + 1] != '1')))
{ {
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '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, static void replace_substring(std::string& s, const std::string& f,
const std::string& t) const std::string& t)
{ {
assert(not f.empty()); JSON_ASSERT(!f.empty());
for (auto pos = s.find(f); // find first occurrence of f for (auto pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t, and s.replace(pos, f.size(), t), // replace with t, and
@ -906,7 +910,7 @@ class json_pointer
static BasicJsonType static BasicJsonType
unflatten(const BasicJsonType& value) 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")); JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
} }
@ -916,7 +920,7 @@ class json_pointer
// iterate the JSON object values // iterate the JSON object values
for (const auto& element : *value.m_value.object) 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")); 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, friend bool operator!=(json_pointer const& lhs,
json_pointer const& rhs) noexcept json_pointer const& rhs) noexcept
{ {
return not (lhs == rhs); return !(lhs == rhs);
} }
/// the reference tokens /// the reference tokens

View file

@ -16,23 +16,30 @@ class json_ref
using value_type = BasicJsonType; using value_type = BasicJsonType;
json_ref(value_type&& value) 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) json_ref(const value_type& value)
: value_ref(const_cast<value_type*>(&value)), is_rvalue(false) : value_ref(const_cast<value_type*>(&value))
, is_rvalue(false)
{} {}
json_ref(std::initializer_list<json_ref> init) json_ref(std::initializer_list<json_ref> init)
: owned_value(init), value_ref(&owned_value), is_rvalue(true) : owned_value(init)
, value_ref(&owned_value)
, is_rvalue(true)
{} {}
template < template <
class... Args, class... Args,
enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 > enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
json_ref(Args && ... args) json_ref(Args && ... args)
: owned_value(std::forward<Args>(args)...), value_ref(&owned_value), : owned_value(std::forward<Args>(args)...)
is_rvalue(true) {} , value_ref(&owned_value)
, is_rvalue(true)
{}
// class should be movable only // class should be movable only
json_ref(json_ref&&) = default; json_ref(json_ref&&) = default;
@ -63,7 +70,7 @@ class json_ref
private: private:
mutable value_type owned_value = nullptr; mutable value_type owned_value = nullptr;
value_type* value_ref = nullptr; value_type* value_ref = nullptr;
const bool is_rvalue; const bool is_rvalue = true;
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

View file

@ -20,7 +20,11 @@
#endif #endif
// C++ language standard detection // 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_17
#define JSON_HAS_CPP_14 #define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
@ -73,6 +77,12 @@
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
#endif #endif
// allow to override assert
#if !defined(JSON_ASSERT)
#include <cassert> // assert
#define JSON_ASSERT(x) assert(x)
#endif
/*! /*!
@brief macro to briefly define a mapping between an enum and JSON @brief macro to briefly define a mapping between an enum and JSON
@def NLOHMANN_JSON_SERIALIZE_ENUM @def NLOHMANN_JSON_SERIALIZE_ENUM
@ -120,3 +130,167 @@
basic_json<ObjectType, ArrayType, StringType, BooleanType, \ basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \ NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType> AllocatorType, JSONSerializer, BinaryType>
// 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

View file

@ -9,6 +9,7 @@
#endif #endif
// clean up // clean up
#undef JSON_ASSERT
#undef JSON_INTERNAL_CATCH #undef JSON_INTERNAL_CATCH
#undef JSON_CATCH #undef JSON_CATCH
#undef JSON_THROW #undef JSON_THROW
@ -17,5 +18,6 @@
#undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_17
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
#undef NLOHMANN_BASIC_JSON_TPL #undef NLOHMANN_BASIC_JSON_TPL
#undef JSON_EXPLICIT
#include <nlohmann/thirdparty/hedley/hedley_undef.hpp> #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>

View file

@ -3,8 +3,6 @@
#include <cstddef> // size_t #include <cstddef> // size_t
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
#include <nlohmann/detail/boolean_operators.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail

View file

@ -34,6 +34,10 @@ template <typename T, typename String>
using string_function_t = using string_function_t =
decltype(std::declval<T&>().string(std::declval<String&>())); decltype(std::declval<T&>().string(std::declval<String&>()));
template<typename T, typename Binary>
using binary_function_t =
decltype(std::declval<T&>().binary(std::declval<Binary&>()));
template<typename T> template<typename T>
using start_object_function_t = using start_object_function_t =
decltype(std::declval<T&>().start_object(std::declval<std::size_t>())); decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
@ -68,19 +72,18 @@ struct is_sax
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
using exception_t = typename BasicJsonType::exception; using exception_t = typename BasicJsonType::exception;
public: public:
static constexpr bool value = static constexpr bool value =
is_detected_exact<bool, null_function_t, SAX>::value && is_detected_exact<bool, null_function_t, SAX>::value &&
is_detected_exact<bool, boolean_function_t, SAX>::value && is_detected_exact<bool, boolean_function_t, SAX>::value &&
is_detected_exact<bool, number_integer_function_t, SAX, is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
number_integer_t>::value && is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
is_detected_exact<bool, number_unsigned_function_t, SAX, is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
number_unsigned_t>::value &&
is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
string_t>::value &&
is_detected_exact<bool, string_function_t, SAX, string_t>::value && is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
is_detected_exact<bool, start_object_function_t, SAX>::value && is_detected_exact<bool, start_object_function_t, SAX>::value &&
is_detected_exact<bool, key_function_t, SAX, string_t>::value && is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
is_detected_exact<bool, end_object_function_t, SAX>::value && is_detected_exact<bool, end_object_function_t, SAX>::value &&
@ -100,6 +103,7 @@ struct is_sax_static_asserts
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
using exception_t = typename BasicJsonType::exception; using exception_t = typename BasicJsonType::exception;
public: public:
@ -123,6 +127,9 @@ struct is_sax_static_asserts
static_assert( static_assert(
is_detected_exact<bool, string_function_t, SAX, string_t>::value, is_detected_exact<bool, string_function_t, SAX, string_t>::value,
"Missing/invalid function: bool string(string_t&)"); "Missing/invalid function: bool string(string_t&)");
static_assert(
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
"Missing/invalid function: bool binary(binary_t&)");
static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value, static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
"Missing/invalid function: bool start_object(std::size_t)"); "Missing/invalid function: bool start_object(std::size_t)");
static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value, static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,

View file

@ -4,7 +4,6 @@
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <utility> // declval #include <utility> // declval
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
@ -95,9 +94,19 @@ using get_template_function = decltype(std::declval<T>().template get<U>());
template<typename BasicJsonType, typename T, typename = void> template<typename BasicJsonType, typename T, typename = void>
struct has_from_json : std::false_type {}; struct has_from_json : std::false_type {};
// trait checking if j.get<T> is valid
// use this trait instead of std::is_constructible or std::is_convertible,
// both rely on, or make use of implicit conversions, and thus fail when T
// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
template <typename BasicJsonType, typename T>
struct is_getable
{
static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_from_json < BasicJsonType, T, struct has_from_json < BasicJsonType, T,
enable_if_t<not is_basic_json<T>::value>> enable_if_t < !is_basic_json<T>::value >>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
@ -112,7 +121,7 @@ template <typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {}; struct has_non_default_from_json : std::false_type {};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
@ -127,7 +136,7 @@ template <typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {}; struct has_to_json : std::false_type {};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
@ -174,7 +183,7 @@ struct is_compatible_object_type_impl : std::false_type {};
template<typename BasicJsonType, typename CompatibleObjectType> template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl < struct is_compatible_object_type_impl <
BasicJsonType, CompatibleObjectType, BasicJsonType, CompatibleObjectType,
enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
is_detected<key_type_t, CompatibleObjectType>::value >> is_detected<key_type_t, CompatibleObjectType>::value >>
{ {
@ -183,7 +192,7 @@ struct is_compatible_object_type_impl <
// macOS's is_constructible does not play well with nonesuch... // macOS's is_constructible does not play well with nonesuch...
static constexpr bool value = static constexpr bool value =
std::is_constructible<typename object_t::key_type, std::is_constructible<typename object_t::key_type,
typename CompatibleObjectType::key_type>::value and typename CompatibleObjectType::key_type>::value &&
std::is_constructible<typename object_t::mapped_type, std::is_constructible<typename object_t::mapped_type,
typename CompatibleObjectType::mapped_type>::value; typename CompatibleObjectType::mapped_type>::value;
}; };
@ -199,22 +208,22 @@ struct is_constructible_object_type_impl : std::false_type {};
template<typename BasicJsonType, typename ConstructibleObjectType> template<typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type_impl < struct is_constructible_object_type_impl <
BasicJsonType, ConstructibleObjectType, BasicJsonType, ConstructibleObjectType,
enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
is_detected<key_type_t, ConstructibleObjectType>::value >> is_detected<key_type_t, ConstructibleObjectType>::value >>
{ {
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
static constexpr bool value = static constexpr bool value =
(std::is_default_constructible<ConstructibleObjectType>::value and (std::is_default_constructible<ConstructibleObjectType>::value &&
(std::is_move_assignable<ConstructibleObjectType>::value or (std::is_move_assignable<ConstructibleObjectType>::value ||
std::is_copy_assignable<ConstructibleObjectType>::value) and std::is_copy_assignable<ConstructibleObjectType>::value) &&
(std::is_constructible<typename ConstructibleObjectType::key_type, (std::is_constructible<typename ConstructibleObjectType::key_type,
typename object_t::key_type>::value and typename object_t::key_type>::value &&
std::is_same < std::is_same <
typename object_t::mapped_type, typename object_t::mapped_type,
typename ConstructibleObjectType::mapped_type >::value)) or typename ConstructibleObjectType::mapped_type >::value)) ||
(has_from_json<BasicJsonType, (has_from_json<BasicJsonType,
typename ConstructibleObjectType::mapped_type>::value or typename ConstructibleObjectType::mapped_type>::value ||
has_non_default_from_json < has_non_default_from_json <
BasicJsonType, BasicJsonType,
typename ConstructibleObjectType::mapped_type >::value); typename ConstructibleObjectType::mapped_type >::value);
@ -268,12 +277,12 @@ struct is_compatible_array_type_impl : std::false_type {};
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl < struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType, BasicJsonType, CompatibleArrayType,
enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and enable_if_t < is_detected<value_type_t, CompatibleArrayType>::value&&
is_detected<iterator_t, CompatibleArrayType>::value and is_detected<iterator_t, CompatibleArrayType>::value&&
// This is needed because json_reverse_iterator has a ::iterator type... // This is needed because json_reverse_iterator has a ::iterator type...
// Therefore it is detected as a CompatibleArrayType. // Therefore it is detected as a CompatibleArrayType.
// The real fix would be to have an Iterable concept. // The real fix would be to have an Iterable concept.
not is_iterator_traits< !is_iterator_traits <
iterator_traits<CompatibleArrayType >>::value >> iterator_traits<CompatibleArrayType >>::value >>
{ {
static constexpr bool value = static constexpr bool value =
@ -298,13 +307,13 @@ struct is_constructible_array_type_impl <
template<typename BasicJsonType, typename ConstructibleArrayType> template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl < struct is_constructible_array_type_impl <
BasicJsonType, ConstructibleArrayType, BasicJsonType, ConstructibleArrayType,
enable_if_t<not std::is_same<ConstructibleArrayType, enable_if_t < !std::is_same<ConstructibleArrayType,
typename BasicJsonType::value_type>::value and typename BasicJsonType::value_type>::value&&
std::is_default_constructible<ConstructibleArrayType>::value and std::is_default_constructible<ConstructibleArrayType>::value&&
(std::is_move_assignable<ConstructibleArrayType>::value or (std::is_move_assignable<ConstructibleArrayType>::value ||
std::is_copy_assignable<ConstructibleArrayType>::value) and std::is_copy_assignable<ConstructibleArrayType>::value)&&
is_detected<value_type_t, ConstructibleArrayType>::value and is_detected<value_type_t, ConstructibleArrayType>::value&&
is_detected<iterator_t, ConstructibleArrayType>::value and is_detected<iterator_t, ConstructibleArrayType>::value&&
is_complete_type < is_complete_type <
detected_t<value_type_t, ConstructibleArrayType >>::value >> detected_t<value_type_t, ConstructibleArrayType >>::value >>
{ {
@ -314,12 +323,12 @@ detected_t<value_type_t, ConstructibleArrayType>>::value >>
// base class `iterator`... Therefore it is detected as a // base class `iterator`... Therefore it is detected as a
// ConstructibleArrayType. The real fix would be to have an Iterable // ConstructibleArrayType. The real fix would be to have an Iterable
// concept. // concept.
not is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value and !is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value &&
(std::is_same<typename ConstructibleArrayType::value_type, (std::is_same<typename ConstructibleArrayType::value_type,
typename BasicJsonType::array_t::value_type>::value or typename BasicJsonType::array_t::value_type>::value ||
has_from_json<BasicJsonType, has_from_json<BasicJsonType,
typename ConstructibleArrayType::value_type>::value or typename ConstructibleArrayType::value_type>::value ||
has_non_default_from_json < has_non_default_from_json <
BasicJsonType, typename ConstructibleArrayType::value_type >::value); BasicJsonType, typename ConstructibleArrayType::value_type >::value);
}; };
@ -335,9 +344,9 @@ struct is_compatible_integer_type_impl : std::false_type {};
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl < struct is_compatible_integer_type_impl <
RealIntegerType, CompatibleNumberIntegerType, RealIntegerType, CompatibleNumberIntegerType,
enable_if_t<std::is_integral<RealIntegerType>::value and enable_if_t < std::is_integral<RealIntegerType>::value&&
std::is_integral<CompatibleNumberIntegerType>::value and std::is_integral<CompatibleNumberIntegerType>::value&&
not std::is_same<bool, CompatibleNumberIntegerType>::value >> !std::is_same<bool, CompatibleNumberIntegerType>::value >>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>; using RealLimits = std::numeric_limits<RealIntegerType>;
@ -345,8 +354,8 @@ struct is_compatible_integer_type_impl <
static constexpr auto value = static constexpr auto value =
std::is_constructible<RealIntegerType, std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and CompatibleNumberIntegerType>::value &&
CompatibleLimits::is_integer and CompatibleLimits::is_integer &&
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };

View file

@ -28,6 +28,7 @@ class binary_writer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
using number_float_t = typename BasicJsonType::number_float_t;
public: public:
/*! /*!
@ -37,7 +38,7 @@ class binary_writer
*/ */
explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter) explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
{ {
assert(oa); JSON_ASSERT(oa);
} }
/*! /*!
@ -194,18 +195,7 @@ class binary_writer
} }
else else
{ {
if (static_cast<double>(j.m_value.number_float) >= static_cast<double>(std::numeric_limits<float>::lowest()) and write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
static_cast<double>(j.m_value.number_float) <= static_cast<double>((std::numeric_limits<float>::max)()) and
static_cast<double>(static_cast<float>(j.m_value.number_float)) == static_cast<double>(j.m_value.number_float))
{
oa->write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float)));
write_number(static_cast<float>(j.m_value.number_float));
}
else
{
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
write_number(j.m_value.number_float);
}
} }
break; break;
} }
@ -289,6 +279,12 @@ class binary_writer
case value_t::binary: case value_t::binary:
{ {
if (j.m_value.binary->has_subtype())
{
write_number(static_cast<std::uint8_t>(0xd8));
write_number(j.m_value.binary->subtype());
}
// step 1: write control byte and the binary array size // step 1: write control byte and the binary array size
const auto N = j.m_value.binary->size(); const auto N = j.m_value.binary->size();
if (N <= 0x17) if (N <= 0x17)
@ -436,28 +432,28 @@ class binary_writer
// negative fixnum // negative fixnum
write_number(static_cast<std::int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
// int 8 // int 8
oa->write_character(to_char_type(0xD0)); oa->write_character(to_char_type(0xD0));
write_number(static_cast<std::int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
// int 16 // int 16
oa->write_character(to_char_type(0xD1)); oa->write_character(to_char_type(0xD1));
write_number(static_cast<std::int16_t>(j.m_value.number_integer)); write_number(static_cast<std::int16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
// int 32 // int 32
oa->write_character(to_char_type(0xD2)); oa->write_character(to_char_type(0xD2));
write_number(static_cast<std::int32_t>(j.m_value.number_integer)); write_number(static_cast<std::int32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{ {
// int 64 // int 64
@ -504,8 +500,7 @@ class binary_writer
case value_t::number_float: case value_t::number_float:
{ {
oa->write_character(get_msgpack_float_prefix(j.m_value.number_float)); write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
write_number(j.m_value.number_float);
break; break;
} }
@ -584,7 +579,7 @@ class binary_writer
const auto N = j.m_value.binary->size(); const auto N = j.m_value.binary->size();
if (N <= (std::numeric_limits<std::uint8_t>::max)()) if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
std::uint8_t output_type; std::uint8_t output_type{};
bool fixed = true; bool fixed = true;
if (use_ext) if (use_ext)
{ {
@ -619,37 +614,25 @@ class binary_writer
} }
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
if (not fixed) if (!fixed)
{ {
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
std::uint8_t output_type; std::uint8_t output_type = use_ext
if (use_ext) ? 0xC8 // ext 16
{ : 0xC5; // bin 16
output_type = 0xC8; // ext 16
}
else
{
output_type = 0xC5; // bin 16
}
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
std::uint8_t output_type; std::uint8_t output_type = use_ext
if (use_ext) ? 0xC9 // ext 32
{ : 0xC6; // bin 32
output_type = 0xC9; // ext 32
}
else
{
output_type = 0xC6; // bin 32
}
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
@ -775,9 +758,9 @@ class binary_writer
} }
bool prefix_required = true; bool prefix_required = true;
if (use_type and not j.m_value.array->empty()) if (use_type && !j.m_value.array->empty())
{ {
assert(use_count); JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front()); const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin() + 1, j.end(), const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
[this, first_prefix](const BasicJsonType & v) [this, first_prefix](const BasicJsonType & v)
@ -804,7 +787,7 @@ class binary_writer
write_ubjson(el, use_count, use_type, prefix_required); write_ubjson(el, use_count, use_type, prefix_required);
} }
if (not use_count) if (!use_count)
{ {
oa->write_character(to_char_type(']')); oa->write_character(to_char_type(']'));
} }
@ -819,9 +802,9 @@ class binary_writer
oa->write_character(to_char_type('[')); oa->write_character(to_char_type('['));
} }
if (use_type and not j.m_value.binary->empty()) if (use_type && !j.m_value.binary->empty())
{ {
assert(use_count); JSON_ASSERT(use_count);
oa->write_character(to_char_type('$')); oa->write_character(to_char_type('$'));
oa->write_character('U'); oa->write_character('U');
} }
@ -847,7 +830,7 @@ class binary_writer
} }
} }
if (not use_count) if (!use_count)
{ {
oa->write_character(to_char_type(']')); oa->write_character(to_char_type(']'));
} }
@ -863,9 +846,9 @@ class binary_writer
} }
bool prefix_required = true; bool prefix_required = true;
if (use_type and not j.m_value.object->empty()) if (use_type && !j.m_value.object->empty())
{ {
assert(use_count); JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front()); const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin(), j.end(), const bool same_prefix = std::all_of(j.begin(), j.end(),
[this, first_prefix](const BasicJsonType & v) [this, first_prefix](const BasicJsonType & v)
@ -896,7 +879,7 @@ class binary_writer
write_ubjson(el.second, use_count, use_type, prefix_required); write_ubjson(el.second, use_count, use_type, prefix_required);
} }
if (not use_count) if (!use_count)
{ {
oa->write_character(to_char_type('}')); oa->write_character(to_char_type('}'));
} }
@ -997,7 +980,7 @@ class binary_writer
*/ */
static std::size_t calc_bson_integer_size(const std::int64_t value) static std::size_t calc_bson_integer_size(const std::int64_t value)
{ {
return (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)() return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
? sizeof(std::int32_t) ? sizeof(std::int32_t)
: sizeof(std::int64_t); : sizeof(std::int64_t);
} }
@ -1008,7 +991,7 @@ class binary_writer
void write_bson_integer(const string_t& name, void write_bson_integer(const string_t& name,
const std::int64_t value) const std::int64_t value)
{ {
if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()) if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
{ {
write_bson_entry_header(name, 0x10); // int32 write_bson_entry_header(name, 0x10); // int32
write_number<std::int32_t, true>(static_cast<std::int32_t>(value)); write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
@ -1157,7 +1140,7 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
default: default:
assert(false); JSON_ASSERT(false);
return 0ul; return 0ul;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@ -1204,7 +1187,7 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
default: default:
assert(false); JSON_ASSERT(false);
return; return;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@ -1336,18 +1319,28 @@ class binary_writer
} }
else else
{ {
JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64")); if (add_prefix)
{
oa->write_character(to_char_type('H')); // high-precision number
}
const auto number = BasicJsonType(n).dump();
write_number_with_ubjson_prefix(number.size(), true);
for (std::size_t i = 0; i < number.size(); ++i)
{
oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
}
} }
} }
// UBJSON: write number (signed integer) // UBJSON: write number (signed integer)
template < typename NumberType, typename std::enable_if < template < typename NumberType, typename std::enable_if <
std::is_signed<NumberType>::value and std::is_signed<NumberType>::value&&
not std::is_floating_point<NumberType>::value, int>::type = 0> !std::is_floating_point<NumberType>::value, int >::type = 0 >
void write_number_with_ubjson_prefix(const NumberType n, void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix) const bool add_prefix)
{ {
if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@ -1355,7 +1348,7 @@ class binary_writer
} }
write_number(static_cast<std::int8_t>(n)); write_number(static_cast<std::int8_t>(n));
} }
else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)())) else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
@ -1363,7 +1356,7 @@ class binary_writer
} }
write_number(static_cast<std::uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)()) else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@ -1371,7 +1364,7 @@ class binary_writer
} }
write_number(static_cast<std::int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)()) else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@ -1379,7 +1372,7 @@ class binary_writer
} }
write_number(static_cast<std::int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)()) else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@ -1390,19 +1383,23 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
else else
{ {
JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64")); if (add_prefix)
{
oa->write_character(to_char_type('H')); // high-precision number
}
const auto number = BasicJsonType(n).dump();
write_number_with_ubjson_prefix(number.size(), true);
for (std::size_t i = 0; i < number.size(); ++i)
{
oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
}
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
/*! /*!
@brief determine the type prefix of container values @brief determine the type prefix of container values
@note This function does not need to be 100% accurate when it comes to
integer limits. In case a number exceeds the limits of int64_t,
this will be detected by a later call to function
write_number_with_ubjson_prefix. Therefore, we return 'L' for any
value that does not fit the previous limits.
*/ */
CharType ubjson_prefix(const BasicJsonType& j) const noexcept CharType ubjson_prefix(const BasicJsonType& j) const noexcept
{ {
@ -1416,25 +1413,29 @@ class binary_writer
case value_t::number_integer: case value_t::number_integer:
{ {
if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
return 'i'; return 'i';
} }
if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{ {
return 'U'; return 'U';
} }
if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
return 'I'; return 'I';
} }
if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
return 'l'; return 'l';
} }
// no check and assume int64_t (see note above) if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{
return 'L'; return 'L';
} }
// anything else is treated as high-precision number
return 'H'; // LCOV_EXCL_LINE
}
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
@ -1454,9 +1455,13 @@ class binary_writer
{ {
return 'l'; return 'l';
} }
// no check and assume int64_t (see note above) if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{
return 'L'; return 'L';
} }
// anything else is treated as high-precision number
return 'H'; // LCOV_EXCL_LINE
}
case value_t::number_float: case value_t::number_float:
return get_ubjson_float_prefix(j.m_value.number_float); return get_ubjson_float_prefix(j.m_value.number_float);
@ -1518,20 +1523,40 @@ class binary_writer
oa->write_characters(vec.data(), sizeof(NumberType)); oa->write_characters(vec.data(), sizeof(NumberType));
} }
void write_compact_float(const number_float_t n, detail::input_format_t format)
{
if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
{
oa->write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(static_cast<float>(n))
: get_msgpack_float_prefix(static_cast<float>(n)));
write_number(static_cast<float>(n));
}
else
{
oa->write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(n)
: get_msgpack_float_prefix(n));
write_number(n);
}
}
public: public:
// The following to_char_type functions are implement the conversion // The following to_char_type functions are implement the conversion
// between uint8_t and CharType. In case CharType is not unsigned, // between uint8_t and CharType. In case CharType is not unsigned,
// such a conversion is required to allow values greater than 128. // such a conversion is required to allow values greater than 128.
// See <https://github.com/nlohmann/json/issues/1286> for a discussion. // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
template < typename C = CharType, template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr > enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
static constexpr CharType to_char_type(std::uint8_t x) noexcept static constexpr CharType to_char_type(std::uint8_t x) noexcept
{ {
return *reinterpret_cast<char*>(&x); return *reinterpret_cast<char*>(&x);
} }
template < typename C = CharType, template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr > enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept static CharType to_char_type(std::uint8_t x) noexcept
{ {
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
@ -1550,8 +1575,8 @@ class binary_writer
template < typename InputCharType, typename C = CharType, template < typename InputCharType, typename C = CharType,
enable_if_t < enable_if_t <
std::is_signed<C>::value and std::is_signed<C>::value &&
std::is_signed<char>::value and std::is_signed<char>::value &&
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr > > * = nullptr >
static constexpr CharType to_char_type(InputCharType x) noexcept static constexpr CharType to_char_type(InputCharType x) noexcept

View file

@ -2,18 +2,16 @@
#include <algorithm> // reverse, remove, fill, find, none_of #include <algorithm> // reverse, remove, fill, find, none_of
#include <array> // array #include <array> // array
#include <cassert> // assert
#include <clocale> // localeconv, lconv #include <clocale> // localeconv, lconv
#include <cmath> // labs, isfinite, isnan, signbit #include <cmath> // labs, isfinite, isnan, signbit
#include <cstddef> // size_t, ptrdiff_t #include <cstddef> // size_t, ptrdiff_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string #include <string> // string, char_traits
#include <type_traits> // is_same #include <type_traits> // is_same
#include <utility> // move #include <utility> // move
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/conversions/to_chars.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@ -59,8 +57,8 @@ class serializer
error_handler_t error_handler_ = error_handler_t::strict) error_handler_t error_handler_ = error_handler_t::strict)
: o(std::move(s)) : o(std::move(s))
, loc(std::localeconv()) , loc(std::localeconv())
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)) , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
, decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)) , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
, indent_char(ichar) , indent_char(ichar)
, indent_string(512, indent_char) , indent_string(512, indent_char)
, error_handler(error_handler_) , error_handler(error_handler_)
@ -135,8 +133,8 @@ class serializer
} }
// last element // last element
assert(i != val.m_value.object->cend()); JSON_ASSERT(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend()); JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
o->write_character('\"'); o->write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
@ -163,8 +161,8 @@ class serializer
} }
// last element // last element
assert(i != val.m_value.object->cend()); JSON_ASSERT(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend()); JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_character('\"'); o->write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2); o->write_characters("\":", 2);
@ -205,7 +203,7 @@ class serializer
} }
// last element // last element
assert(not val.m_value.array->empty()); JSON_ASSERT(!val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
@ -226,7 +224,7 @@ class serializer
} }
// last element // last element
assert(not val.m_value.array->empty()); JSON_ASSERT(!val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
o->write_character(']'); o->write_character(']');
@ -260,7 +258,7 @@ class serializer
o->write_characters("\"bytes\": [", 10); o->write_characters("\"bytes\": [", 10);
if (not val.m_value.binary->empty()) if (!val.m_value.binary->empty())
{ {
for (auto i = val.m_value.binary->cbegin(); for (auto i = val.m_value.binary->cbegin();
i != val.m_value.binary->cend() - 1; ++i) i != val.m_value.binary->cend() - 1; ++i)
@ -291,7 +289,7 @@ class serializer
{ {
o->write_characters("{\"bytes\":[", 10); o->write_characters("{\"bytes\":[", 10);
if (not val.m_value.binary->empty()) if (!val.m_value.binary->empty())
{ {
for (auto i = val.m_value.binary->cbegin(); for (auto i = val.m_value.binary->cbegin();
i != val.m_value.binary->cend() - 1; ++i) i != val.m_value.binary->cend() - 1; ++i)
@ -360,7 +358,7 @@ class serializer
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
} }
@ -452,7 +450,7 @@ class serializer
{ {
// escape control characters (0x00..0x1F) or, if // escape control characters (0x00..0x1F) or, if
// ensure_ascii parameter is used, non-ASCII characters // ensure_ascii parameter is used, non-ASCII characters
if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
{ {
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
@ -559,14 +557,14 @@ class serializer
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
break; break;
} }
default: // decode found yet incomplete multi-byte code point default: // decode found yet incomplete multi-byte code point
{ {
if (not ensure_ascii) if (!ensure_ascii)
{ {
// code point will not be escaped - copy byte to buffer // code point will not be escaped - copy byte to buffer
string_buffer[bytes++] = s[i]; string_buffer[bytes++] = s[i];
@ -622,7 +620,7 @@ class serializer
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
} }
} }
@ -671,8 +669,8 @@ class serializer
@tparam NumberType either @a number_integer_t or @a number_unsigned_t @tparam NumberType either @a number_integer_t or @a number_unsigned_t
*/ */
template < typename NumberType, detail::enable_if_t < template < typename NumberType, detail::enable_if_t <
std::is_same<NumberType, number_unsigned_t>::value or std::is_same<NumberType, number_unsigned_t>::value ||
std::is_same<NumberType, number_integer_t>::value or std::is_same<NumberType, number_integer_t>::value ||
std::is_same<NumberType, binary_char_t>::value, std::is_same<NumberType, binary_char_t>::value,
int > = 0 > int > = 0 >
void dump_integer(NumberType x) void dump_integer(NumberType x)
@ -703,7 +701,7 @@ class serializer
// use a pointer to fill the buffer // use a pointer to fill the buffer
auto buffer_ptr = number_buffer.begin(); auto buffer_ptr = number_buffer.begin();
const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755 const bool is_negative = std::is_same<NumberType, number_integer_t>::value && !(x >= 0); // see issue #755
number_unsigned_t abs_value; number_unsigned_t abs_value;
unsigned int n_chars; unsigned int n_chars;
@ -723,7 +721,7 @@ class serializer
} }
// spare 1 byte for '\0' // spare 1 byte for '\0'
assert(n_chars < number_buffer.size() - 1); JSON_ASSERT(n_chars < number_buffer.size() - 1);
// jump to the end to generate the string from backward // jump to the end to generate the string from backward
// so we later avoid reversing the result // so we later avoid reversing the result
@ -764,7 +762,7 @@ class serializer
void dump_float(number_float_t x) void dump_float(number_float_t x)
{ {
// NaN / inf // NaN / inf
if (not std::isfinite(x)) if (!std::isfinite(x))
{ {
o->write_characters("null", 4); o->write_characters("null", 4);
return; return;
@ -776,8 +774,8 @@ class serializer
// //
// NB: The test below works if <long double> == <double>. // NB: The test below works if <long double> == <double>.
static constexpr bool is_ieee_single_or_double static constexpr bool is_ieee_single_or_double
= (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
(std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024); (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>()); dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
} }
@ -799,9 +797,9 @@ class serializer
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
// negative value indicates an error // negative value indicates an error
assert(len > 0); JSON_ASSERT(len > 0);
// check if buffer was large enough // check if buffer was large enough
assert(static_cast<std::size_t>(len) < number_buffer.size()); JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
// erase thousands separator // erase thousands separator
if (thousands_sep != '\0') if (thousands_sep != '\0')
@ -809,12 +807,12 @@ class serializer
const auto end = std::remove(number_buffer.begin(), const auto end = std::remove(number_buffer.begin(),
number_buffer.begin() + len, thousands_sep); number_buffer.begin() + len, thousands_sep);
std::fill(end, number_buffer.end(), '\0'); std::fill(end, number_buffer.end(), '\0');
assert((end - number_buffer.begin()) <= len); JSON_ASSERT((end - number_buffer.begin()) <= len);
len = (end - number_buffer.begin()); len = (end - number_buffer.begin());
} }
// convert decimal point to '.' // convert decimal point to '.'
if (decimal_point != '\0' and decimal_point != '.') if (decimal_point != '\0' && decimal_point != '.')
{ {
const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
if (dec_pos != number_buffer.end()) if (dec_pos != number_buffer.end())
@ -830,7 +828,7 @@ class serializer
std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
[](char c) [](char c)
{ {
return c == '.' or c == 'e'; return c == '.' || c == 'e';
}); });
if (value_is_int_like) if (value_is_int_like)
@ -889,7 +887,7 @@ class serializer
: (0xFFu >> type) & (byte); : (0xFFu >> type) & (byte);
std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type); std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
assert(index < 400); JSON_ASSERT(index < 400);
state = utf8d[index]; state = utf8d[index];
return state; return state;
} }
@ -901,7 +899,7 @@ class serializer
*/ */
number_unsigned_t remove_sign(number_unsigned_t x) number_unsigned_t remove_sign(number_unsigned_t x)
{ {
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE return x; // LCOV_EXCL_LINE
} }
@ -916,7 +914,7 @@ class serializer
*/ */
inline number_unsigned_t remove_sign(number_integer_t x) noexcept inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{ {
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)()); JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1; return static_cast<number_unsigned_t>(-(x + 1)) + 1;
} }

View file

@ -5,8 +5,6 @@
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <string> // string #include <string> // string
#include <nlohmann/detail/boolean_operators.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
@ -77,7 +75,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
const auto l_index = static_cast<std::size_t>(lhs); const auto l_index = static_cast<std::size_t>(lhs);
const auto r_index = static_cast<std::size_t>(rhs); const auto r_index = static_cast<std::size_t>(rhs);
return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
} }
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

File diff suppressed because it is too large Load diff

View file

@ -60,6 +60,19 @@ uses the standard template types.
@since version 1.0.0 @since version 1.0.0
*/ */
using json = basic_json<>; using json = basic_json<>;
template<class Key, class T, class IgnoredLess, class Allocator>
struct ordered_map;
/*!
@brief ordered JSON class
This type preserves the insertion order of object keys.
@since version 3.9.0
*/
using ordered_json = basic_json<nlohmann::ordered_map>;
} // namespace nlohmann } // namespace nlohmann
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_

View file

@ -0,0 +1,71 @@
#pragma once
#include <functional> // less
#include <memory> // allocator
#include <utility> // pair
#include <vector> // vector
namespace nlohmann
{
/// ordered_map: a minimal map-like container that preserves insertion order
/// for use within nlohmann::basic_json<ordered_map>
template <class Key, class T, class IgnoredLess = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>>
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
{
using key_type = Key;
using mapped_type = T;
using Container = std::vector<std::pair<const Key, T>, Allocator>;
using typename Container::iterator;
using typename Container::size_type;
using typename Container::value_type;
// Explicit constructors instead of `using Container::Container`
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {}
template <class It>
ordered_map(It first, It last, const Allocator& alloc = Allocator())
: Container{first, last, alloc} {}
ordered_map(std::initializer_list<T> init, const Allocator& alloc = Allocator() )
: Container{init, alloc} {}
std::pair<iterator, bool> emplace(key_type&& key, T&& t)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
{
return {it, false};
}
}
Container::emplace_back(key, t);
return {--this->end(), true};
}
T& operator[](Key&& key)
{
return emplace(std::move(key), T{}).first->second;
}
size_type erase(const Key& key)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
{
// Since we cannot move const Keys, re-construct them in place
for (auto next = it; ++next != this->end(); ++it)
{
it->~value_type(); // Destroy but keep allocation
new (&*it) value_type{std::move(*next)};
}
Container::pop_back();
return 1;
}
}
return 0;
}
};
} // namespace nlohmann

View file

@ -1,6 +1,6 @@
project('nlohmann_json', project('nlohmann_json',
'cpp', 'cpp',
version : '3.8.0', version : '3.9.0',
license : 'MIT', license : 'MIT',
) )

File diff suppressed because it is too large Load diff

View file

@ -95,6 +95,7 @@ set(files
src/unit-algorithms.cpp src/unit-algorithms.cpp
src/unit-allocator.cpp src/unit-allocator.cpp
src/unit-alt-string.cpp src/unit-alt-string.cpp
src/unit-assert_macro.cpp
src/unit-bson.cpp src/unit-bson.cpp
src/unit-capacity.cpp src/unit-capacity.cpp
src/unit-cbor.cpp src/unit-cbor.cpp
@ -111,6 +112,7 @@ set(files
src/unit-deserialization.cpp src/unit-deserialization.cpp
src/unit-element_access1.cpp src/unit-element_access1.cpp
src/unit-element_access2.cpp src/unit-element_access2.cpp
src/unit-hash.cpp
src/unit-inspection.cpp src/unit-inspection.cpp
src/unit-items.cpp src/unit-items.cpp
src/unit-iterators1.cpp src/unit-iterators1.cpp
@ -123,6 +125,7 @@ set(files
src/unit-modifiers.cpp src/unit-modifiers.cpp
src/unit-msgpack.cpp src/unit-msgpack.cpp
src/unit-noexcept.cpp src/unit-noexcept.cpp
src/unit-ordered_json.cpp
src/unit-pointer_access.cpp src/unit-pointer_access.cpp
src/unit-readme.cpp src/unit-readme.cpp
src/unit-reference_access.cpp src/unit-reference_access.cpp
@ -132,6 +135,7 @@ set(files
src/unit-to_chars.cpp src/unit-to_chars.cpp
src/unit-ubjson.cpp src/unit-ubjson.cpp
src/unit-udt.cpp src/unit-udt.cpp
src/unit-udt_macro.cpp
src/unit-unicode.cpp src/unit-unicode.cpp
src/unit-user_defined_input.cpp src/unit-user_defined_input.cpp
src/unit-wstring.cpp) src/unit-wstring.cpp)
@ -189,3 +193,4 @@ add_subdirectory(cmake_import)
add_subdirectory(cmake_import_minver) add_subdirectory(cmake_import_minver)
add_subdirectory(cmake_add_subdirectory) add_subdirectory(cmake_add_subdirectory)
add_subdirectory(cmake_fetch_content) add_subdirectory(cmake_fetch_content)
add_subdirectory(cmake_target_include_directories)

View file

@ -1,98 +1,13 @@
########################################################################## ##############################################################################
# unit tests # OSS-Fuzz
########################################################################## ##############################################################################
# The following targets realize the integration to OSS-Fuzz.
# See <https://github.com/google/oss-fuzz/blob/master/projects/json/build.sh> for more information.
# additional flags # additional flags
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wcast-align -Wcast-qual -Wno-ctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wno-float-equal CXXFLAGS += -std=c++11
CPPFLAGS += -I ../single_include -I . -I thirdparty/doctest -I thirdparty/fifo_map -DDOCTEST_CONFIG_SUPER_FAST_ASSERTS CPPFLAGS += -I ../single_include
SOURCES = src/unit.cpp \
src/unit-algorithms.cpp \
src/unit-allocator.cpp \
src/unit-alt-string.cpp \
src/unit-bson.cpp \
src/unit-capacity.cpp \
src/unit-cbor.cpp \
src/unit-class_const_iterator.cpp \
src/unit-class_iterator.cpp \
src/unit-class_lexer.cpp \
src/unit-class_parser.cpp \
src/unit-comparison.cpp \
src/unit-concepts.cpp \
src/unit-constructor1.cpp \
src/unit-constructor2.cpp \
src/unit-convenience.cpp \
src/unit-conversions.cpp \
src/unit-deserialization.cpp \
src/unit-element_access1.cpp \
src/unit-element_access2.cpp \
src/unit-inspection.cpp \
src/unit-items.cpp \
src/unit-iterators1.cpp \
src/unit-iterators2.cpp \
src/unit-merge_patch.cpp \
src/unit-json_patch.cpp \
src/unit-json_pointer.cpp \
src/unit-meta.cpp \
src/unit-modifiers.cpp \
src/unit-msgpack.cpp \
src/unit-pointer_access.cpp \
src/unit-readme.cpp \
src/unit-reference_access.cpp \
src/unit-regression.cpp \
src/unit-serialization.cpp \
src/unit-testsuites.cpp \
src/unit-ubjson.cpp \
src/unit-unicode.cpp \
src/unit-user_defined_input.cpp \
src/unit-wstring.cpp
OBJECTS = $(SOURCES:.cpp=.o)
TESTCASES = $(patsubst src/unit-%.cpp,test-%,$(wildcard src/unit-*.cpp))
##############################################################################
# main rules
##############################################################################
all: $(TESTCASES)
clean:
rm -fr json_unit $(OBJECTS) $(SOURCES:.cpp=.gcno) $(SOURCES:.cpp=.gcda) $(TESTCASES) $(FUZZERS) test_data.hpp
test_data.hpp:
@echo "#define TEST_DATA_DIRECTORY" > $@
##############################################################################
# single test file
##############################################################################
json_unit: $(OBJECTS) ../single_include/nlohmann/json.hpp thirdparty/doctest/doctest.h
@echo "[CXXLD] $@"
@$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@
%.o: %.cpp ../single_include/nlohmann/json.hpp thirdparty/doctest/doctest.h test_data.hpp
@echo "[CXX] $@"
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
##############################################################################
# individual test cases
##############################################################################
test-%: src/unit-%.o src/unit.o ../single_include/nlohmann/json.hpp thirdparty/doctest/doctest.h test_data.hpp
@echo "[CXXLD] $@"
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $< src/unit.o -o $@
TEST_PATTERN ?= "*"
TEST_PREFIX = ""
check: $(OBJECTS) $(TESTCASES)
@cd .. ; for testcase in $(TESTCASES); do echo "Executing $$testcase..."; $(TEST_PREFIX)test/$$testcase $(TEST_PATTERN) || exit 1; done
##############################################################################
# fuzzer
##############################################################################
FUZZER_ENGINE = src/fuzzer-driver_afl.cpp FUZZER_ENGINE = src/fuzzer-driver_afl.cpp
FUZZERS = parse_afl_fuzzer parse_bson_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer parse_ubjson_fuzzer FUZZERS = parse_afl_fuzzer parse_bson_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer parse_ubjson_fuzzer

View file

@ -11,8 +11,10 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.11.0")
) )
set_tests_properties(cmake_fetch_content_configure PROPERTIES set_tests_properties(cmake_fetch_content_configure PROPERTIES
FIXTURES_SETUP cmake_fetch_content FIXTURES_SETUP cmake_fetch_content
LABELS git_required
) )
set_tests_properties(cmake_fetch_content_build PROPERTIES set_tests_properties(cmake_fetch_content_build PROPERTIES
FIXTURES_REQUIRED cmake_fetch_content FIXTURES_REQUIRED cmake_fetch_content
LABELS git_required
) )
endif() endif()

View file

@ -4,9 +4,8 @@ project(DummyImport CXX)
include(FetchContent) include(FetchContent)
FetchContent_Declare(json get_filename_component(GIT_REPOSITORY_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE)
GIT_REPOSITORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. FetchContent_Declare(json GIT_REPOSITORY ${GIT_REPOSITORY_DIRECTORY} GIT_TAG HEAD)
GIT_TAG HEAD)
FetchContent_GetProperties(json) FetchContent_GetProperties(json)
if(NOT json_POPULATED) if(NOT json_POPULATED)

View file

@ -0,0 +1,16 @@
add_test(NAME cmake_target_include_directories_configure
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-Dnlohmann_json_source=${PROJECT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/project
)
add_test(NAME cmake_target_include_directories_build
COMMAND ${CMAKE_COMMAND} --build .
)
set_tests_properties(cmake_target_include_directories_configure PROPERTIES
FIXTURES_SETUP cmake_target_include_directories
)
set_tests_properties(cmake_target_include_directories_build PROPERTIES
FIXTURES_REQUIRED cmake_target_include_directories
)

View file

@ -0,0 +1,3 @@
#include "Bar.hpp"
class Bar;

View file

@ -0,0 +1,4 @@
#include <nlohmann/json.hpp>
#include "Foo.hpp"
class Bar : public Foo{};

View file

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.1)
project(DummyImport CXX)
add_executable(with_private_target main.cpp)
target_include_directories(with_private_target PRIVATE ${nlohmann_json_source}/include)
set_target_properties(with_private_target PROPERTIES CXX_STANDARD 11)
add_executable(with_private_system_target main.cpp)
target_include_directories(with_private_system_target PRIVATE SYSTEM ${nlohmann_json_source}/include)
set_target_properties(with_private_system_target PROPERTIES CXX_STANDARD 11)
# regression from https://github.com/nlohmann/json/discussions/2281
add_library(Foo STATIC Foo.cpp Bar.cpp)
target_include_directories(Foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${nlohmann_json_source}/include)
set_target_properties(Foo PROPERTIES CXX_STANDARD 11)
add_library(Bar STATIC Bar.cpp)
target_link_libraries(Bar PRIVATE Foo)
target_include_directories(Bar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${nlohmann_json_source}/include)
set_target_properties(Bar PROPERTIES CXX_STANDARD 11)

View file

@ -0,0 +1,3 @@
#include "Foo.hpp"
class Foo;

View file

@ -0,0 +1,4 @@
#pragma once
#include <nlohmann/json.hpp>
class Foo{};

View file

@ -0,0 +1,8 @@
#include <nlohmann/json.hpp>
int main(int argc, char **argv)
{
nlohmann::json j;
return 0;
}

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a parser test suitable for fuzz testing. Given a byte This file implements a parser test suitable for fuzz testing. Given a byte

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a parser test suitable for fuzz testing. Given a byte This file implements a parser test suitable for fuzz testing. Given a byte

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a parser test suitable for fuzz testing. Given a byte This file implements a parser test suitable for fuzz testing. Given a byte

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a parser test suitable for fuzz testing. Given a byte This file implements a parser test suitable for fuzz testing. Given a byte

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a parser test suitable for fuzz testing. Given a byte This file implements a parser test suitable for fuzz testing. Given a byte

25
test/src/test_utils.hpp Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include <cstdint> // uint8_t
#include <fstream> // ifstream, istreambuf_iterator, ios
#include <vector> // vector
namespace utils
{
inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary);
file.unsetf(std::ios::skipws);
file.seekg(0, std::ios::end);
const auto size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<std::uint8_t> byte_vector;
byte_vector.reserve(static_cast<std::size_t>(size));
byte_vector.insert(byte_vector.begin(), std::istream_iterator<std::uint8_t>(file), std::istream_iterator<std::uint8_t>());
return byte_vector;
}
} // namespace utils

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@ -55,7 +55,7 @@ TEST_CASE("algorithms")
{ {
CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value) CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
{ {
return value.is_string() and value.get<std::string>() == "foo"; return value.is_string() && value.get<std::string>() == "foo";
})); }));
CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value) CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
{ {
@ -139,14 +139,14 @@ TEST_CASE("algorithms")
{ {
CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin())); CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin())); CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
CHECK(not std::equal(j_array.begin(), j_array.end(), j_object.begin())); CHECK(!std::equal(j_array.begin(), j_array.end(), j_object.begin()));
} }
SECTION("using user-defined comparison") SECTION("using user-defined comparison")
{ {
// compare objects only by size of its elements // compare objects only by size of its elements
json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"}; json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
CHECK(not std::equal(j_array.begin(), j_array.end(), j_array2.begin())); CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(), CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
[](const json & a, const json & b) [](const json & a, const json & b)
{ {
@ -213,7 +213,7 @@ TEST_CASE("algorithms")
return v.is_string(); return v.is_string();
}); });
CHECK(std::distance(j_array.begin(), it) == 2); CHECK(std::distance(j_array.begin(), it) == 2);
CHECK(not it[2].is_string()); CHECK(!it[2].is_string());
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.

View file

@ -0,0 +1,65 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// avoid warning when assert does not abort
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#endif
#include "doctest_compatibility.h"
/// global variable to record side effect of assert calls
static int assert_counter;
/// set failure variable to true instead of calling assert(x)
#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; }
#include <nlohmann/json.hpp>
using nlohmann::json;
// the test assumes exceptions to work
#if !defined(JSON_NOEXCEPTION)
TEST_CASE("JSON_ASSERT(x)")
{
SECTION("basic_json(first, second)")
{
assert_counter = 0;
CHECK(assert_counter == 0);
json::iterator it;
json j;
// in case assertions do not abort execution, an exception is thrown
CHECK_THROWS_WITH_AS(json(it, j.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator);
// check that assertion actually happened
CHECK(assert_counter == 1);
}
}
#endif

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@ -35,6 +35,7 @@ using nlohmann::json;
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <test_data.hpp> #include <test_data.hpp>
#include "test_utils.hpp"
TEST_CASE("BSON") TEST_CASE("BSON")
{ {
@ -766,7 +767,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Incomplete BSON Input 2") SECTION("Incomplete BSON Input 2")
@ -784,7 +785,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Incomplete BSON Input 3") SECTION("Incomplete BSON Input 3")
@ -808,7 +809,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Incomplete BSON Input 4") SECTION("Incomplete BSON Input 4")
@ -825,7 +826,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Improve coverage") SECTION("Improve coverage")
@ -835,7 +836,7 @@ TEST_CASE("Incomplete BSON Input")
json j = {{"key", "value"}}; json j = {{"key", "value"}};
auto bson_vec = json::to_bson(j); auto bson_vec = json::to_bson(j);
SaxCountdown scp(2); SaxCountdown scp(2);
CHECK(not json::sax_parse(bson_vec, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
} }
SECTION("array") SECTION("array")
@ -846,7 +847,7 @@ TEST_CASE("Incomplete BSON Input")
}; };
auto bson_vec = json::to_bson(j); auto bson_vec = json::to_bson(j);
SaxCountdown scp(2); SaxCountdown scp(2);
CHECK(not json::sax_parse(bson_vec, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
} }
} }
} }
@ -887,7 +888,7 @@ TEST_CASE("Unsupported BSON input")
CHECK(json::from_bson(bson, true, false).is_discarded()); CHECK(json::from_bson(bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
} }
TEST_CASE("BSON numerical data") TEST_CASE("BSON numerical data")
@ -1263,10 +1264,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse BSON file // parse BSON file
std::ifstream f_bson(filename + ".bson", std::ios::binary); auto packed = utils::read_binary_file(filename + ".bson");
std::vector<std::uint8_t> packed(
(std::istreambuf_iterator<char>(f_bson)),
std::istreambuf_iterator<char>());
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_bson(packed)); CHECK_NOTHROW(j2 = json::from_bson(packed));
@ -1296,10 +1294,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse BSON file // parse BSON file
std::ifstream f_bson(filename + ".bson", std::ios::binary); auto packed = utils::read_binary_file(filename + ".bson");
std::vector<std::uint8_t> packed(
(std::istreambuf_iterator<char>(f_bson)),
std::istreambuf_iterator<char>());
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()})); CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()}));
@ -1314,10 +1309,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse BSON file // parse BSON file
std::ifstream f_bson(filename + ".bson", std::ios::binary); auto packed = utils::read_binary_file(filename + ".bson");
std::vector<std::uint8_t> packed(
(std::istreambuf_iterator<char>(f_bson)),
std::istreambuf_iterator<char>());
{ {
INFO_WITH_TEMP(filename + ": output adapters: std::vector<std::uint8_t>"); INFO_WITH_TEMP(filename + ": output adapters: std::vector<std::uint8_t>");

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0 | | |__ | | | | | | version 3.9.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@ -39,6 +39,7 @@ using nlohmann::json;
#include <iostream> #include <iostream>
#include <set> #include <set>
#include <test_data.hpp> #include <test_data.hpp>
#include "test_utils.hpp"
namespace namespace
{ {
@ -1011,21 +1012,21 @@ TEST_CASE("CBOR")
SECTION("0 (0 00000 0000000000)") SECTION("0 (0 00000 0000000000)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == 0.0); CHECK(d == 0.0);
} }
SECTION("-0 (1 00000 0000000000)") SECTION("-0 (1 00000 0000000000)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x80, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x80, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == -0.0); CHECK(d == -0.0);
} }
SECTION("2**-24 (0 00000 0000000001)") SECTION("2**-24 (0 00000 0000000001)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x01})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x01}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == std::pow(2.0, -24.0)); CHECK(d == std::pow(2.0, -24.0));
} }
} }
@ -1035,7 +1036,7 @@ TEST_CASE("CBOR")
SECTION("infinity (0 11111 0000000000)") SECTION("infinity (0 11111 0000000000)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == std::numeric_limits<json::number_float_t>::infinity()); CHECK(d == std::numeric_limits<json::number_float_t>::infinity());
CHECK(j.dump() == "null"); CHECK(j.dump() == "null");
} }
@ -1043,7 +1044,7 @@ TEST_CASE("CBOR")
SECTION("-infinity (1 11111 0000000000)") SECTION("-infinity (1 11111 0000000000)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0xfc, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0xfc, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == -std::numeric_limits<json::number_float_t>::infinity()); CHECK(d == -std::numeric_limits<json::number_float_t>::infinity());
CHECK(j.dump() == "null"); CHECK(j.dump() == "null");
} }
@ -1054,21 +1055,21 @@ TEST_CASE("CBOR")
SECTION("1 (0 01111 0000000000)") SECTION("1 (0 01111 0000000000)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x3c, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x3c, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == 1); CHECK(d == 1);
} }
SECTION("-2 (1 10000 0000000000)") SECTION("-2 (1 10000 0000000000)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0xc0, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0xc0, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == -2); CHECK(d == -2);
} }
SECTION("65504 (0 11110 1111111111)") SECTION("65504 (0 11110 1111111111)")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7b, 0xff})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7b, 0xff}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(d == 65504); CHECK(d == 65504);
} }
} }
@ -1076,15 +1077,15 @@ TEST_CASE("CBOR")
SECTION("infinity") SECTION("infinity")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(not std::isfinite(d)); CHECK(!std::isfinite(d));
CHECK(j.dump() == "null"); CHECK(j.dump() == "null");
} }
SECTION("NaN") SECTION("NaN")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7e, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7e, 0x00}));
json::number_float_t d = j; json::number_float_t d{j};
CHECK(std::isnan(d)); CHECK(std::isnan(d));
CHECK(j.dump() == "null"); CHECK(j.dump() == "null");
} }
@ -1869,7 +1870,7 @@ TEST_CASE("CBOR")
{ {
const auto result = json::from_cbor(vec, false); const auto result = json::from_cbor(vec, false);
CHECK(result == json()); CHECK(result == json());
CHECK(not json::from_cbor(vec, false, false).is_discarded()); CHECK(!json::from_cbor(vec, false, false).is_discarded());
} }
SECTION("strict mode") SECTION("strict mode")
@ -1889,21 +1890,21 @@ TEST_CASE("CBOR")
{ {
std::vector<uint8_t> v = {0x83, 0x01, 0x02, 0x03}; std::vector<uint8_t> v = {0x83, 0x01, 0x02, 0x03};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::cbor));
} }
SECTION("start_object(len)") SECTION("start_object(len)")
{ {
std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4}; std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::cbor));
} }
SECTION("key()") SECTION("key()")
{ {
std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4}; std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4};
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::cbor));
} }
} }
} }
@ -1920,9 +1921,7 @@ TEST_CASE("single CBOR roundtrip")
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse CBOR file // parse CBOR file
std::ifstream f_cbor(filename + ".cbor", std::ios::binary); auto packed = utils::read_binary_file(filename + ".cbor");
std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_cbor)),
std::istreambuf_iterator<char>());
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_cbor(packed)); CHECK_NOTHROW(j2 = json::from_cbor(packed));
@ -1954,7 +1953,7 @@ TEST_CASE("single CBOR roundtrip")
} }
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("CBOR regressions") TEST_CASE("CBOR regressions")
{ {
SECTION("fuzz test results") SECTION("fuzz test results")
@ -1994,10 +1993,7 @@ TEST_CASE("CBOR regressions")
try try
{ {
// parse CBOR file // parse CBOR file
std::ifstream f_cbor(filename, std::ios::binary); auto vec1 = utils::read_binary_file(filename);
std::vector<uint8_t> vec1(
(std::istreambuf_iterator<char>(f_cbor)),
std::istreambuf_iterator<char>());
json j1 = json::from_cbor(vec1); json j1 = json::from_cbor(vec1);
try try
@ -2204,10 +2200,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse CBOR file // parse CBOR file
std::ifstream f_cbor(filename + ".cbor", std::ios::binary); auto packed = utils::read_binary_file(filename + ".cbor");
std::vector<uint8_t> packed(
(std::istreambuf_iterator<char>(f_cbor)),
std::istreambuf_iterator<char>());
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_cbor(packed)); CHECK_NOTHROW(j2 = json::from_cbor(packed));
@ -2237,10 +2230,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse CBOR file // parse CBOR file
std::ifstream f_cbor(filename + ".cbor", std::ios::binary); auto packed = utils::read_binary_file(filename + ".cbor");
std::vector<uint8_t> packed(
(std::istreambuf_iterator<char>(f_cbor)),
std::istreambuf_iterator<char>());
json j2; json j2;
CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()})); CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()}));
@ -2255,10 +2245,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
// parse CBOR file // parse CBOR file
std::ifstream f_cbor(filename + ".cbor", std::ios::binary); auto packed = utils::read_binary_file(filename + ".cbor");
std::vector<uint8_t> packed(
(std::istreambuf_iterator<char>(f_cbor)),
std::istreambuf_iterator<char>());
if (!exclude_packed.count(filename)) if (!exclude_packed.count(filename))
{ {
@ -2274,7 +2261,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
} }
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("all CBOR first bytes") TEST_CASE("all CBOR first bytes")
{ {
// these bytes will fail immediately with exception parse_error.112 // these bytes will fail immediately with exception parse_error.112
@ -2493,16 +2480,14 @@ TEST_CASE("examples from RFC 7049 Appendix A")
SECTION("byte arrays") SECTION("byte arrays")
{ {
std::ifstream f_cbor(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.cbor", std::ios::binary); auto packed = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.cbor");
std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_cbor)),
std::istreambuf_iterator<char>());
json j; json j;
CHECK_NOTHROW(j = json::from_cbor(packed)); CHECK_NOTHROW(j = json::from_cbor(packed));
std::ifstream f_bin(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out", std::ios::binary); auto expected = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out");
std::vector<uint8_t> expected((std::istreambuf_iterator<char>(f_bin)),
std::istreambuf_iterator<char>());
CHECK(j == json::binary(expected)); CHECK(j == json::binary(expected));
CHECK(json::to_cbor(json::binary(std::vector<uint8_t> {}, 0x42)) == std::vector<uint8_t> {0xd8, 0x42, 0x40});
} }
SECTION("arrays") SECTION("arrays")
@ -2548,3 +2533,197 @@ TEST_CASE("examples from RFC 7049 Appendix A")
CHECK(json::parse("{\"Fun\": true, \"Amt\": -2}") == json::from_cbor(std::vector<uint8_t>({0xbf, 0x63, 0x46, 0x75, 0x6e, 0xf5, 0x63, 0x41, 0x6d, 0x74, 0x21, 0xff}))); CHECK(json::parse("{\"Fun\": true, \"Amt\": -2}") == json::from_cbor(std::vector<uint8_t>({0xbf, 0x63, 0x46, 0x75, 0x6e, 0xf5, 0x63, 0x41, 0x6d, 0x74, 0x21, 0xff})));
} }
} }
TEST_CASE("Tagged values")
{
json j = "s";
auto v = json::to_cbor(j);
SECTION("0xC6..0xD4")
{
for (auto b : std::vector<std::uint8_t>
{
0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4
})
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), b);
// check that parsing fails in error mode
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
// check that parsing succeeds and gets original value in ignore mode
auto j_tagged = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore);
CHECK(j_tagged == j);
}
}
SECTION("0xD8 - 1 byte follows")
{
SECTION("success")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x42); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xD8); // tag
// check that parsing fails in error mode
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
// check that parsing succeeds and gets original value in ignore mode
auto j_tagged = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore);
CHECK(j_tagged == j);
}
SECTION("missing byte after tag")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0xD8); // tag
// check that parsing fails in all modes
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore), json::parse_error);
}
}
SECTION("0xD9 - 2 byte follow")
{
SECTION("success")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x42); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xD9); // tag
// check that parsing fails in error mode
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
// check that parsing succeeds and gets original value in ignore mode
auto j_tagged = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore);
CHECK(j_tagged == j);
}
SECTION("missing byte after tag")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xD9); // tag
// check that parsing fails in all modes
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore), json::parse_error);
}
}
SECTION("0xDA - 4 bytes follow")
{
SECTION("success")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x42); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x22); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x11); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xDA); // tag
// check that parsing fails in error mode
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
// check that parsing succeeds and gets original value in ignore mode
auto j_tagged = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore);
CHECK(j_tagged == j);
}
SECTION("missing bytes after tag")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x22); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x11); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xDA); // tag
// check that parsing fails in all modes
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore), json::parse_error);
}
}
SECTION("0xDB - 8 bytes follow")
{
SECTION("success")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x42); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x22); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x11); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x42); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x22); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x11); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xDB); // tag
// check that parsing fails in error mode
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
// check that parsing succeeds and gets original value in ignore mode
auto j_tagged = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore);
CHECK(j_tagged == j);
}
SECTION("missing byte after tag")
{
// add tag to value
auto v_tagged = v;
v_tagged.insert(v_tagged.begin(), 0x42); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x22); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x11); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x23); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x22); // 1 byte
v_tagged.insert(v_tagged.begin(), 0x11); // 1 byte
v_tagged.insert(v_tagged.begin(), 0xDB); // tag
// check that parsing fails in all modes
CHECK_THROWS_AS(json::from_cbor(v_tagged), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::error), json::parse_error);
CHECK_THROWS_AS(json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore), json::parse_error);
}
}
SECTION("tagged binary")
{
// create a binary value of subtype 42
json j_binary;
j_binary["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42);
// convert to CBOR
const auto vec = json::to_cbor(j_binary);
CHECK(vec == std::vector<std::uint8_t> {0xA1, 0x66, 0x62, 0x69, 0x6E, 0x61, 0x72, 0x79, 0xD8, 0x2A, 0x44, 0xCA, 0xFE, 0xBA, 0xBE});
// parse error when parsing tagged value
CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.112] parse error at byte 9: syntax error while parsing CBOR value: invalid byte: 0xD8");
// binary without subtype when tags are ignored
json jb = json::from_cbor(vec, true, true, json::cbor_tag_handler_t::ignore);
CHECK(jb.is_object());
CHECK(jb["binary"].is_binary());
CHECK(!jb["binary"].get_binary().has_subtype());
}
}

Some files were not shown because too many files have changed in this diff Show more