Merge remote-tracking branch 'nlohmann/develop' into iterate-on-destruction

This commit is contained in:
Isaac Nickaein 2019-11-09 14:50:48 +03:30
commit eec1974218
148 changed files with 27046 additions and 18980 deletions

30
.circleci/config.yml Normal file
View file

@ -0,0 +1,30 @@
version: 2
jobs:
build:
docker:
- image: debian:stretch
steps:
- checkout
- run:
name: Install sudo
command: 'apt-get update && apt-get install -y sudo && rm -rf /var/lib/apt/lists/*'
- run:
name: Install GCC
command: 'apt-get update && apt-get install -y gcc g++'
- run:
name: Install CMake
command: 'apt-get update && sudo apt-get install -y cmake'
- run:
name: Create build files
command: 'mkdir build ; cd build ; cmake ..'
- run:
name: Versions
command: 'g++ --version ; uname -a'
- run:
name: Compile
command: 'cmake --build build'
- run:
name: Execute test suite
command: 'cd build ; ctest -j 2'

26
.clang-tidy Normal file
View file

@ -0,0 +1,26 @@
Checks: '-*,
bugprone-*,
cert-*,
clang-analyzer-*,
google-*,
-google-runtime-references,
-google-explicit-constructor,
hicpp-*,
-hicpp-no-array-decay,
-hicpp-uppercase-literal-suffix,
-hicpp-explicit-conversions,
misc-*,
-misc-non-private-member-variables-in-classes,
llvm-*,
-llvm-header-guard,
modernize-*,
-modernize-use-trailing-return-type,
performance-*,
portability-*,
readability-*,
-readability-magic-numbers,
-readability-uppercase-literal-suffix'
CheckOptions:
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
value: 1

82
.doozer.json Normal file
View file

@ -0,0 +1,82 @@
{
"targets": {
"raspbian-jessie": {
"buildenv": "raspbian-jessie",
"builddeps": ["build-essential", "wget"],
"buildcmd": [
"uname -a",
"cat /etc/os-release",
"g++ --version",
"cd",
"wget https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz",
"tar xfz cmake-3.14.0.tar.gz",
"cd cmake-3.14.0",
"./bootstrap",
"make -j8",
"cd",
"mkdir build",
"cd build",
"../cmake-3.14.0/bin/cmake /project/repo/checkout",
"make -j8",
"../cmake-3.14.0/bin/ctest -VV -j4 --timeout 10000"
]
},
"xenial-armhf": {
"buildenv": "xenial-armhf",
"builddeps": ["build-essential", "wget"],
"buildcmd": [
"uname -a",
"lsb_release -a",
"g++ --version",
"cd",
"wget --no-check-certificate https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz",
"tar xfz cmake-3.14.0.tar.gz",
"cd cmake-3.14.0",
"./bootstrap",
"make -j8",
"cd",
"mkdir build",
"cd build",
"../cmake-3.14.0/bin/cmake /project/repo/checkout",
"make -j8",
"../cmake-3.14.0/bin/ctest -VV -j4 --timeout 10000"
]
},
"fedora24-x86_64": {
"buildenv": "fedora24-x86_64",
"builddeps": ["cmake", "make", "gcc gcc-c++"],
"buildcmd": [
"uname -a",
"cat /etc/fedora-release",
"g++ --version",
"cd",
"mkdir build",
"cd build",
"cmake /project/repo/checkout",
"make -j8",
"ctest -VV -j8"
]
},
"centos7-x86_64": {
"buildenv": "centos7-x86_64",
"builddeps": ["make", "wget", "gcc-c++"],
"buildcmd": [
"uname -a",
"rpm -q centos-release",
"g++ --version",
"cd",
"wget https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0.tar.gz",
"tar xfz cmake-3.14.0.tar.gz",
"cd cmake-3.14.0",
"./bootstrap",
"make -j8",
"cd",
"mkdir build",
"cd build",
"../cmake-3.14.0/bin/cmake /project/repo/checkout",
"make -j8",
"../cmake-3.14.0/bin/ctest -VV -j8"
]
}
}
}

6
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,6 @@
# JSON for Modern C++ has been originally written by Niels Lohmann.
# Since 2013 over 140 contributors have helped to improve the library.
# This CODEOWNERS file is only to make sure that @nlohmann is requsted
# for a code review in case of a pull request.
* @nlohmann

View file

@ -4,7 +4,7 @@
This project started as a little excuse to exercise some of the cool new C++11 features. Over time, people actually started to use the JSON library (yey!) and started to help improve it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers. This project started as a little excuse to exercise some of the cool new C++11 features. Over time, people actually started to use the JSON library (yey!) and started to help improve it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers.
To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it! To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new/choose) or a pull request if you find a way to improve it!
## Private reports ## Private reports
@ -12,7 +12,7 @@ Usually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann
## Prerequisites ## Prerequisites
Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. Please [create an issue](https://github.com/nlohmann/json/issues/new/choose), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this.
## Describe your issue ## Describe your issue
@ -22,7 +22,7 @@ Clearly describe the issue:
- If you propose a change or addition, try to give an **example** how the improved code could look like or how to use it. - If you propose a change or addition, try to give an **example** how the improved code could look like or how to use it.
- If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste the (relevant part of) the error messages to the ticket. - If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste the (relevant part of) the error messages to the ticket.
Please stick to the [issue template](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE.md) if possible. Please stick to the provided issue templates ([bug report](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/Bug_report.md), [feature request](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/Feature_request.md), or [question](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/question.md)) if possible.
## Files to change ## Files to change
@ -32,7 +32,7 @@ To make changes, you need to edit the following files:
1. [`include/nlohmann/*`](https://github.com/nlohmann/json/tree/develop/include/nlohmann) - These files are the sources of the library. Before testing or creating a pull request, execute `make amalgamate` to regenerate `single_include/nlohmann/json.hpp`. 1. [`include/nlohmann/*`](https://github.com/nlohmann/json/tree/develop/include/nlohmann) - These files are the sources of the library. Before testing or creating a pull request, execute `make amalgamate` to regenerate `single_include/nlohmann/json.hpp`.
2. [`test/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/test/src) - These files contain the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code. 2. [`test/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/test/src) - These files contain the [doctest](https://github.com/onqtam/doctest) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code.
If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
custom: http://paypal.me/nlohmann

View file

@ -1,19 +1,22 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: ''
--- labels: 'kind: bug'
assignees: ''
- What is the issue you have?
---
- Please describe the steps to reproduce the issue. Can you provide a small but working code example?
- What is the issue you have?
- What is the expected behavior?
- Please describe the steps to reproduce the issue. Can you provide a small but working code example?
- And what is the actual behavior instead?
- What is the expected behavior?
- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)?
- And what is the actual behavior instead?
- Did you use a released version of the library or the version from the `develop` branch?
- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)?
- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)?
- Did you use a released version of the library or the version from the `develop` branch?
- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)?

View file

@ -1,9 +1,12 @@
--- ---
name: Feature request name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
title: ''
--- labels: 'kind: enhancement/improvement'
assignees: ''
- Describe the feature in as much detail as possible.
---
- Include sample usage where appropriate.
- Describe the feature in as much detail as possible.
- Include sample usage where appropriate.

16
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View file

@ -0,0 +1,16 @@
---
name: Question
about: Ask a question regarding the library.
title: ''
labels: 'kind: question'
assignees: ''
---
- Describe what you want to achieve.
- Describe what you tried.
- Describe which system (OS, compiler) you are using.
- Describe which version of the library you are using (release version, develop branch).

5
.github/SECURITY.md vendored Normal file
View file

@ -0,0 +1,5 @@
# Security Policy
## Reporting a Vulnerability
Usually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be published), please send an email to <mail@nlohmann.me>. You can use [this key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69) for encryption.

19
.github/workflows/ccpp.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: C/C++ CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: mkdir build
- name: cmake
run: cd build ; cmake ..
- name: build
run: make -C build
- name: test
run: cd build ; ctest -j 10

View file

@ -43,12 +43,15 @@ matrix:
- os: linux - os: linux
compiler: clang compiler: clang
env: env:
- COMPILER=clang++-5.0 - COMPILER=clang++-7
- CMAKE_OPTIONS=-DJSON_Sanitizer=ON - CMAKE_OPTIONS=-DJSON_Sanitizer=ON
- UBSAN_OPTIONS=print_stacktrace=1,suppressions=$(pwd)/test/src/UBSAN.supp
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-5.0', 'ninja-build'] packages: ['g++-6', 'clang-7', 'ninja-build']
before_script:
- export PATH=$PATH:/usr/lib/llvm-7/bin
# cppcheck # cppcheck
- os: linux - os: linux
@ -128,21 +131,6 @@ matrix:
# OSX / Clang # OSX / Clang
- os: osx
osx_image: xcode6.4
- os: osx
osx_image: xcode7.3
- os: osx
osx_image: xcode8
- os: osx
osx_image: xcode8.1
- os: osx
osx_image: xcode8.2
- os: osx - os: osx
osx_image: xcode8.3 osx_image: xcode8.3
@ -164,11 +152,17 @@ matrix:
- os: osx - os: osx
osx_image: xcode10 osx_image: xcode10
- os: osx
osx_image: xcode10.1
- os: osx
osx_image: xcode10.2
# Linux / GCC # Linux / GCC
- os: linux - os: linux
compiler: gcc compiler: gcc
env: compiler=g++-4.8 env: COMPILER=g++-4.8
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
@ -176,7 +170,7 @@ matrix:
- os: linux - os: linux
compiler: gcc compiler: gcc
env: compiler=g++-4.9 env: COMPILER=g++-4.9
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
@ -216,13 +210,21 @@ matrix:
- os: linux - os: linux
compiler: gcc compiler: gcc
env: env: COMPILER=g++-9
- COMPILER=g++-8
- CXXFLAGS=-std=c++17
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-8', 'ninja-build'] packages: ['g++-9', 'ninja-build']
- os: linux
compiler: gcc
env:
- COMPILER=g++-9
- CXXFLAGS=-std=c++2a
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-9', 'ninja-build']
# Linux / Clang # Linux / Clang
@ -290,15 +292,23 @@ matrix:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
packages: ['g++-6', 'clang-6.0', 'ninja-build'] packages: ['g++-6', 'clang-6.0', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-7
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-7', 'ninja-build']
- os: linux - os: linux
compiler: clang compiler: clang
env: env:
- COMPILER=clang++-6.0 - COMPILER=clang++-7
- CXXFLAGS=-std=c++1z - CXXFLAGS=-std=c++1z
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-6.0', 'ninja-build'] packages: ['g++-6', 'clang-7', 'ninja-build']
################ ################
# build script # # build script #
@ -326,7 +336,7 @@ script:
# 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} -GNinja && cmake --build . --config Release - cmake .. ${CMAKE_OPTIONS} -DJSON_MultipleHeaders=${MULTIPLE_HEADERS} -GNinja && cmake --build . --config Release
- ctest -C Release -V -j - ctest -C Release --timeout 2700 -V -j
- cd .. - cd ..
# check if homebrew works (only checks develop branch) # check if homebrew works (only checks develop branch)

8
.whitesource Normal file
View file

@ -0,0 +1,8 @@
{
"checkRunSettings": {
"vulnerableCheckRunConclusionLevel": "failure"
},
"issueSettings": {
"minSeverityLevel": "LOW"
}
}

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.5.0 LANGUAGES CXX) project(nlohmann_json VERSION 3.7.1 LANGUAGES CXX)
## ##
## INCLUDE ## INCLUDE
@ -16,15 +16,17 @@ include(ExternalProject)
## OPTIONS ## OPTIONS
## ##
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_MultipleHeaders "Use non-amalgamated version of the library." OFF) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
## ##
## CONFIGURATION ## CONFIGURATION
## ##
include(GNUInstallDirs)
set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME}) set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME})
set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}" set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE INTERNAL "")
CACHE INTERNAL "") set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include")
set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in") set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in")
set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}") set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
@ -46,7 +48,11 @@ endif()
## ##
add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE) add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE)
add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME}) add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME})
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11) if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_range_for)
else()
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
endif()
target_include_directories( target_include_directories(
${NLOHMANN_JSON_TARGET_NAME} ${NLOHMANN_JSON_TARGET_NAME}
@ -92,32 +98,34 @@ configure_file(
@ONLY @ONLY
) )
install( if(JSON_Install)
DIRECTORY ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}
DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
)
install(
FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
if (NLOHMANN_ADD_NATVIS)
install( install(
FILES ${NLOHMANN_NATVIS_FILE} DIRECTORY ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}
DESTINATION . DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
) )
install(
FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
if (NLOHMANN_ADD_NATVIS)
install(
FILES ${NLOHMANN_NATVIS_FILE}
DESTINATION .
)
endif()
export(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
NAMESPACE ${PROJECT_NAME}::
FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}
)
install(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
)
install(
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
endif() endif()
export(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
NAMESPACE ${PROJECT_NAME}::
FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}
)
install(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
)
install(
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)

View file

@ -1,6 +1,408 @@
# Change Log # Change Log
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.7.1](https://github.com/nlohmann/json/releases/tag/v3.7.1) (2019-11-06)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.7.0...v3.7.1)
- std::is\_constructible is always true with tuple [\#1825](https://github.com/nlohmann/json/issues/1825)
- Can't compile from\_json\(std::valarray\<T\>\). [\#1824](https://github.com/nlohmann/json/issues/1824)
- json class should have a get\_or member function [\#1823](https://github.com/nlohmann/json/issues/1823)
- NLOHMANN\_JSON\_SERIALIZE\_ENUM macro capture's json objects by value [\#1822](https://github.com/nlohmann/json/issues/1822)
- Parse fails when number literals start with zero [\#1820](https://github.com/nlohmann/json/issues/1820)
- Parsing string into json doesn't preserve the order correctly. [\#1817](https://github.com/nlohmann/json/issues/1817)
- Weird behaviour of `contains` with `json\_pointer` [\#1815](https://github.com/nlohmann/json/issues/1815)
- strange behaviour with json\_pointer and .contains\(\) [\#1811](https://github.com/nlohmann/json/issues/1811)
- Can \#1695 be re-opened? [\#1808](https://github.com/nlohmann/json/issues/1808)
- Merge two json objects [\#1807](https://github.com/nlohmann/json/issues/1807)
- std::is\_constructible\<json, std::unordered\_map\<std::string, Data\>\> when to\_json not defined [\#1805](https://github.com/nlohmann/json/issues/1805)
- Private data on parsing [\#1802](https://github.com/nlohmann/json/issues/1802)
- Capturing Line and Position when querying [\#1800](https://github.com/nlohmann/json/issues/1800)
- json error on parsing DBL\_MAX from string [\#1796](https://github.com/nlohmann/json/issues/1796)
- De/Serialisation of vector of tupple object with nested obect need Help please [\#1794](https://github.com/nlohmann/json/issues/1794)
- Output json is corrupted [\#1793](https://github.com/nlohmann/json/issues/1793)
- variable name byte sometimes used as a \#define [\#1792](https://github.com/nlohmann/json/issues/1792)
- Can't read json file [\#1791](https://github.com/nlohmann/json/issues/1791)
- Problems with special German letters [\#1789](https://github.com/nlohmann/json/issues/1789)
- Support for trailing commas [\#1787](https://github.com/nlohmann/json/issues/1787)
- json\_pointer construction bug [\#1786](https://github.com/nlohmann/json/issues/1786)
- Visual Studio 2017 warning [\#1784](https://github.com/nlohmann/json/issues/1784)
- ciso646 header become obsolete [\#1782](https://github.com/nlohmann/json/issues/1782)
- Migrate LGTM.com installation from OAuth to GitHub App [\#1781](https://github.com/nlohmann/json/issues/1781)
- JSON comparison, contains and operator& [\#1778](https://github.com/nlohmann/json/issues/1778)
- pass a json object to a class contructor adds an array around the object [\#1776](https://github.com/nlohmann/json/issues/1776)
- 'Float' number\_float\_function\_t template parameter name conflicts with C '\#define Float float' [\#1775](https://github.com/nlohmann/json/issues/1775)
- A weird building problem :-\( [\#1774](https://github.com/nlohmann/json/issues/1774)
- What is this json\_ref? [\#1772](https://github.com/nlohmann/json/issues/1772)
- Interoperability with other languages [\#1770](https://github.com/nlohmann/json/issues/1770)
- Json dump [\#1768](https://github.com/nlohmann/json/issues/1768)
- json\_pointer\<\>::back\(\) should be const [\#1764](https://github.com/nlohmann/json/issues/1764)
- How to get value from array [\#1762](https://github.com/nlohmann/json/issues/1762)
- Merge two jsons [\#1757](https://github.com/nlohmann/json/issues/1757)
- Unable to locate nlohmann\_jsonConfig.cmake [\#1755](https://github.com/nlohmann/json/issues/1755)
- json.hpp won;t compile VS2019 CLR/CLI app but does in console app [\#1754](https://github.com/nlohmann/json/issues/1754)
- \[Nested Json Objects\] Segmentation fault [\#1753](https://github.com/nlohmann/json/issues/1753)
- remove/replace assert with exceptions [\#1752](https://github.com/nlohmann/json/issues/1752)
- Add array support for update\(\) function [\#1751](https://github.com/nlohmann/json/issues/1751)
- Is there a reason the `get\_to` method is defined in `include/nlohmann/json.hpp` but not in `single\_include/nlohmann/json.hpp`? [\#1750](https://github.com/nlohmann/json/issues/1750)
- how to validate json object before calling dump\(\) [\#1748](https://github.com/nlohmann/json/issues/1748)
- Unable to invoke accessors on json objects in lldb [\#1745](https://github.com/nlohmann/json/issues/1745)
- Escaping string before parsing [\#1743](https://github.com/nlohmann/json/issues/1743)
- Construction in a member initializer list using curly braces is set as 'array' [\#1742](https://github.com/nlohmann/json/issues/1742)
- Read a subkey from json object [\#1740](https://github.com/nlohmann/json/issues/1740)
- Serialize vector of glm:vec2 [\#1739](https://github.com/nlohmann/json/issues/1739)
- Support nlohmann::basic\_json::value with JSON\_NOEXCEPTION [\#1738](https://github.com/nlohmann/json/issues/1738)
- how to know the parse is error [\#1737](https://github.com/nlohmann/json/issues/1737)
- How to check if a given key exists in a JSON object [\#1736](https://github.com/nlohmann/json/issues/1736)
- Allow The Colon Key-Value Delimiter To Have A Space Before It \[@ READ ONLY\] [\#1735](https://github.com/nlohmann/json/issues/1735)
- Allow Tail { "Key": "Value" } Comma \[@ READ ONLY\] [\#1734](https://github.com/nlohmann/json/issues/1734)
- No-throw json::value\(\) [\#1733](https://github.com/nlohmann/json/issues/1733)
- JsonObject.dump\(\) [\#1732](https://github.com/nlohmann/json/issues/1732)
- basic\_json has no member "parse" [\#1731](https://github.com/nlohmann/json/issues/1731)
- Exception "type must be string, but is array" [\#1730](https://github.com/nlohmann/json/issues/1730)
- json::contains usage to find a path [\#1727](https://github.com/nlohmann/json/issues/1727)
- How to create JSON Object from my Structures of Data and Json File from that Object [\#1726](https://github.com/nlohmann/json/issues/1726)
- please provide an API to read JSON from file directly. [\#1725](https://github.com/nlohmann/json/issues/1725)
- How to modify a value stored at a key? [\#1723](https://github.com/nlohmann/json/issues/1723)
- CMake not correctly finding the configuration package for 3.7.0 [\#1721](https://github.com/nlohmann/json/issues/1721)
- name typo in the "spack package management" section of README.md [\#1720](https://github.com/nlohmann/json/issues/1720)
- How to add json to another json? [\#1718](https://github.com/nlohmann/json/issues/1718)
- How can I save json object in file in order? [\#1717](https://github.com/nlohmann/json/issues/1717)
- json::parse\(\) ubsan regression with v3.7.0 [\#1716](https://github.com/nlohmann/json/issues/1716)
- What I am doing wrong?!? [\#1714](https://github.com/nlohmann/json/issues/1714)
- Potential memory leak detected by Valgrind [\#1713](https://github.com/nlohmann/json/issues/1713)
- json::parse is not thread safe? [\#1712](https://github.com/nlohmann/json/issues/1712)
- static analysis alarm by cppcheck [\#1711](https://github.com/nlohmann/json/issues/1711)
- The compilation time is slow [\#1710](https://github.com/nlohmann/json/issues/1710)
- not linking properly with cmake [\#1709](https://github.com/nlohmann/json/issues/1709)
- Error in dump\(\) with int64\_t minimum value [\#1708](https://github.com/nlohmann/json/issues/1708)
- Crash on trying to deserialize json string on 3ds homebrew [\#1707](https://github.com/nlohmann/json/issues/1707)
- Can't compile VS2019. 13 Errors [\#1706](https://github.com/nlohmann/json/issues/1706)
- find an object that matches the search criteria [\#1705](https://github.com/nlohmann/json/issues/1705)
- IntelliSense goes crazy on VS2019 [\#1704](https://github.com/nlohmann/json/issues/1704)
- Installing on Ubuntu 16.04 [\#1703](https://github.com/nlohmann/json/issues/1703)
- Where is json::parse now? [\#1702](https://github.com/nlohmann/json/issues/1702)
- Forward header should't be amalgamated [\#1700](https://github.com/nlohmann/json/issues/1700)
- Json support for Cmake version 2.8.12 [\#1699](https://github.com/nlohmann/json/issues/1699)
- Intruisive scientific notation when using .dump\(\); [\#1698](https://github.com/nlohmann/json/issues/1698)
- Is there support for automatic serialization/deserialization? [\#1696](https://github.com/nlohmann/json/issues/1696)
- on MSVC dump\(\) will hard crash for larger json [\#1693](https://github.com/nlohmann/json/issues/1693)
- puzzled implicit conversions [\#1692](https://github.com/nlohmann/json/issues/1692)
- Information: My project uses this awesome library [\#1691](https://github.com/nlohmann/json/issues/1691)
- Consider listing files explicitly instead of using GLOB [\#1686](https://github.com/nlohmann/json/issues/1686)
- Failing tests on MSVC with VS2019 15.9.13 x64 [\#1685](https://github.com/nlohmann/json/issues/1685)
- Consider putting the user-defined literals in a namespace [\#1682](https://github.com/nlohmann/json/issues/1682)
- Change from v2 to v3. Encoding with cp1252 [\#1680](https://github.com/nlohmann/json/issues/1680)
- How to add Fifo\_map into json using Cmake [\#1679](https://github.com/nlohmann/json/issues/1679)
- include.zip should contain meson.build [\#1672](https://github.com/nlohmann/json/issues/1672)
- \[Question\] How do I parse JSON into custom types? [\#1669](https://github.com/nlohmann/json/issues/1669)
- Binary \(0x05\) data type for BSON to JSON conversion [\#1668](https://github.com/nlohmann/json/issues/1668)
- Possible to call dump from lldb? [\#1666](https://github.com/nlohmann/json/issues/1666)
- Segmentation fault when linked with libunwind [\#1665](https://github.com/nlohmann/json/issues/1665)
- Should I include single-header after my to\_json and from\_json custom functions declaration? Why not? [\#1663](https://github.com/nlohmann/json/issues/1663)
- Errors/Warnings in VS 2019 when Including Header File [\#1659](https://github.com/nlohmann/json/issues/1659)
- Return null object from object's const operator\[\] as well. [\#1658](https://github.com/nlohmann/json/issues/1658)
- Can't stream json object in to std::basic\_stringstream\<wchar\_t\> [\#1656](https://github.com/nlohmann/json/issues/1656)
- C2440 in vs2015 cannot convert from 'initializer-list' to nlohmann::basic\_json [\#1655](https://github.com/nlohmann/json/issues/1655)
- Issues around get and pointers [\#1653](https://github.com/nlohmann/json/issues/1653)
- Non-member operator== breaks enum \(de\)serialization [\#1647](https://github.com/nlohmann/json/issues/1647)
- Valgrind: bytes in 1 blocks are definitely lost [\#1646](https://github.com/nlohmann/json/issues/1646)
- Convenient way to make 'basic\_json' accept 'QString' as an key type as well? [\#1640](https://github.com/nlohmann/json/issues/1640)
- mongodb: nan, inf [\#1599](https://github.com/nlohmann/json/issues/1599)
- Error in adl\_serializer [\#1590](https://github.com/nlohmann/json/issues/1590)
- Injecting class during serialization [\#1584](https://github.com/nlohmann/json/issues/1584)
- output\_adapter not user extensible [\#1534](https://github.com/nlohmann/json/issues/1534)
- Inclusion of nlohmann/json.hpp causes OS/ABI to change on Linux [\#1410](https://github.com/nlohmann/json/issues/1410)
- Add library versioning using inline namespaces [\#1394](https://github.com/nlohmann/json/issues/1394)
- CBOR byte string support [\#1129](https://github.com/nlohmann/json/issues/1129)
- How to deserialize array with derived objects [\#716](https://github.com/nlohmann/json/issues/716)
- Add restriction for tuple specialization of to\_json [\#1826](https://github.com/nlohmann/json/pull/1826) ([cbegue](https://github.com/cbegue))
- Fix for \#1647 [\#1821](https://github.com/nlohmann/json/pull/1821) ([AnthonyVH](https://github.com/AnthonyVH))
- Fix issue \#1805 [\#1806](https://github.com/nlohmann/json/pull/1806) ([cbegue](https://github.com/cbegue))
- Fix some spelling errors - mostly in comments & documentation. [\#1803](https://github.com/nlohmann/json/pull/1803) ([flopp](https://github.com/flopp))
- Update Hedley to v11. [\#1799](https://github.com/nlohmann/json/pull/1799) ([nemequ](https://github.com/nemequ))
- iteration\_proxy: Fix integer truncation from std::size\_t to int [\#1797](https://github.com/nlohmann/json/pull/1797) ([t-b](https://github.com/t-b))
- appveyor.yml: Add MSVC 16 2019 support [\#1780](https://github.com/nlohmann/json/pull/1780) ([t-b](https://github.com/t-b))
- test/CMakeLists.txt: Use an explicit list instead of GLOB [\#1779](https://github.com/nlohmann/json/pull/1779) ([t-b](https://github.com/t-b))
- Make json\_pointer::back const \(resolves \#1764\) [\#1769](https://github.com/nlohmann/json/pull/1769) ([chris0x44](https://github.com/chris0x44))
- did you mean 'serialization'? [\#1767](https://github.com/nlohmann/json/pull/1767) ([0xflotus](https://github.com/0xflotus))
- Allow items\(\) to be used with custom string [\#1765](https://github.com/nlohmann/json/pull/1765) ([crazyjul](https://github.com/crazyjul))
- Cppcheck fixes [\#1760](https://github.com/nlohmann/json/pull/1760) ([Xav83](https://github.com/Xav83))
- Fix and add test's for SFINAE problem [\#1741](https://github.com/nlohmann/json/pull/1741) ([tete17](https://github.com/tete17))
- Fix clang sanitizer invocation [\#1728](https://github.com/nlohmann/json/pull/1728) ([t-b](https://github.com/t-b))
- Add gcc 9 and compile with experimental C++20 support [\#1724](https://github.com/nlohmann/json/pull/1724) ([t-b](https://github.com/t-b))
- Fix int64 min issue [\#1722](https://github.com/nlohmann/json/pull/1722) ([t-b](https://github.com/t-b))
- release: add singleinclude and meson.build to include.zip [\#1694](https://github.com/nlohmann/json/pull/1694) ([eli-schwartz](https://github.com/eli-schwartz))
## [v3.7.0](https://github.com/nlohmann/json/releases/tag/v3.7.0) (2019-07-28)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.6.1...v3.7.0)
- How can I retrieve uknown strings from json file in my C++ program. [\#1684](https://github.com/nlohmann/json/issues/1684)
- contains\(\) is sometimes causing stack-based buffer overrun exceptions [\#1683](https://github.com/nlohmann/json/issues/1683)
- How to deserialize arrays from json [\#1681](https://github.com/nlohmann/json/issues/1681)
- Compilation failed in VS2015 [\#1678](https://github.com/nlohmann/json/issues/1678)
- Why the compiled object file is so huge? [\#1677](https://github.com/nlohmann/json/issues/1677)
- From Version 2.1.1 to 3.6.1 serialize std::set [\#1676](https://github.com/nlohmann/json/issues/1676)
- Qt deprecation model halting compiltion [\#1675](https://github.com/nlohmann/json/issues/1675)
- Build For Raspberry pi , Rapbery with new Compiler C++17 [\#1671](https://github.com/nlohmann/json/issues/1671)
- Build from Raspberry pi [\#1667](https://github.com/nlohmann/json/issues/1667)
- Can not translate map with integer key to dict string ? [\#1664](https://github.com/nlohmann/json/issues/1664)
- Double type converts to scientific notation [\#1661](https://github.com/nlohmann/json/issues/1661)
- Missing v3.6.1 tag on master branch [\#1657](https://github.com/nlohmann/json/issues/1657)
- Support Fleese Binary Data Format [\#1654](https://github.com/nlohmann/json/issues/1654)
- Suggestion: replace alternative tokens for !, && and || with their symbols [\#1652](https://github.com/nlohmann/json/issues/1652)
- Build failure test-allocator.vcxproj [\#1651](https://github.com/nlohmann/json/issues/1651)
- How to provide function json& to\_json\(\) which is similar as 'void to\_json\(json&j, const CObject& obj\)' ? [\#1650](https://github.com/nlohmann/json/issues/1650)
- Can't throw exception when starting file is a number [\#1649](https://github.com/nlohmann/json/issues/1649)
- to\_json / from\_json with nested type [\#1648](https://github.com/nlohmann/json/issues/1648)
- How to create a json object from a std::string, created by j.dump? [\#1645](https://github.com/nlohmann/json/issues/1645)
- Problem getting vector \(array\) of strings [\#1644](https://github.com/nlohmann/json/issues/1644)
- json.hpp compilation issue with other typedefs with same name [\#1642](https://github.com/nlohmann/json/issues/1642)
- nlohmann::adl\_serializer\<T,void\>::to\_json no matching overloaded function found [\#1641](https://github.com/nlohmann/json/issues/1641)
- overwrite adl\_serializer\<bool, void\> to change behaviour [\#1638](https://github.com/nlohmann/json/issues/1638)
- json.SelectToken\("Manufacturers.Products.Price"\); [\#1637](https://github.com/nlohmann/json/issues/1637)
- Add json type as value [\#1636](https://github.com/nlohmann/json/issues/1636)
- Unit conversion test error: conversion from 'nlohmann::json' to non-scalar type 'std::string\_view' requested [\#1634](https://github.com/nlohmann/json/issues/1634)
- nlohmann VS JsonCpp by C++17 [\#1633](https://github.com/nlohmann/json/issues/1633)
- To integrate an inline helper function that return type name as string [\#1632](https://github.com/nlohmann/json/issues/1632)
- Return JSON as reference [\#1631](https://github.com/nlohmann/json/issues/1631)
- Updating from an older version causes problems with assing a json object to a struct [\#1630](https://github.com/nlohmann/json/issues/1630)
- Can without default constructor function for user defined classes when only to\_json is needed? [\#1629](https://github.com/nlohmann/json/issues/1629)
- Compilation fails with clang 6.x-8.x in C++14 mode [\#1628](https://github.com/nlohmann/json/issues/1628)
- Treating floating point as string [\#1627](https://github.com/nlohmann/json/issues/1627)
- error parsing character å [\#1626](https://github.com/nlohmann/json/issues/1626)
- \[Help\] How to Improve Json Output Performance with Large Json Arrays [\#1624](https://github.com/nlohmann/json/issues/1624)
- Suggested link changes for reporting new issues \[blob/develop/REAME.md and blob/develop/.github/CONTRIBUTING.md\] [\#1623](https://github.com/nlohmann/json/issues/1623)
- Broken link to issue template in CONTRIBUTING.md [\#1622](https://github.com/nlohmann/json/issues/1622)
- Missing word in README.md file [\#1621](https://github.com/nlohmann/json/issues/1621)
- Package manager instructions in README for brew is incorrect [\#1620](https://github.com/nlohmann/json/issues/1620)
- Building with Visual Studio 2019 [\#1619](https://github.com/nlohmann/json/issues/1619)
- Precedence of to\_json and builtin harmful [\#1617](https://github.com/nlohmann/json/issues/1617)
- The type json is missing from the html documentation [\#1616](https://github.com/nlohmann/json/issues/1616)
- variant is not support in Release 3.6.1? [\#1615](https://github.com/nlohmann/json/issues/1615)
- Replace assert with throw for const operator\[\] [\#1614](https://github.com/nlohmann/json/issues/1614)
- Memory Overhead is Too High \(10x or more\) [\#1613](https://github.com/nlohmann/json/issues/1613)
- program crash everytime, when other data type incomming in json stream as expected [\#1612](https://github.com/nlohmann/json/issues/1612)
- Improved Enum Support [\#1611](https://github.com/nlohmann/json/issues/1611)
- is it possible convert json object back to stl container ? [\#1610](https://github.com/nlohmann/json/issues/1610)
- Add C++17-like emplace.back\(\) for arrays. [\#1609](https://github.com/nlohmann/json/issues/1609)
- is\_nothrow\_copy\_constructible fails for json::const\_iterator on MSVC2015 x86 Debug build [\#1608](https://github.com/nlohmann/json/issues/1608)
- Reading and writing array elements [\#1607](https://github.com/nlohmann/json/issues/1607)
- Converting json::value to int [\#1605](https://github.com/nlohmann/json/issues/1605)
- I have a vector of keys and and a string of value and i want to create nested json array [\#1604](https://github.com/nlohmann/json/issues/1604)
- In compatible JSON object from nlohmann::json to nohman::json - unexpected end of input; expected '\[', '{', or a literal [\#1603](https://github.com/nlohmann/json/issues/1603)
- json parser crash if having a large number integer in message [\#1602](https://github.com/nlohmann/json/issues/1602)
- Value method with undocumented throwing 302 exception [\#1601](https://github.com/nlohmann/json/issues/1601)
- Accessing value with json pointer adds key if not existing [\#1600](https://github.com/nlohmann/json/issues/1600)
- README.md broken link to project documentation [\#1597](https://github.com/nlohmann/json/issues/1597)
- Random Kudos: Thanks for your work on this! [\#1596](https://github.com/nlohmann/json/issues/1596)
- json::parse return value and errors [\#1595](https://github.com/nlohmann/json/issues/1595)
- initializer list constructor makes curly brace initialization fragile [\#1594](https://github.com/nlohmann/json/issues/1594)
- trying to log message for missing keyword, difference between \["foo"\] and at\("foo"\) [\#1593](https://github.com/nlohmann/json/issues/1593)
- std::string and std::wstring `to\_json` [\#1592](https://github.com/nlohmann/json/issues/1592)
- I have a C structure which I need to convert to a JSON. How do I do it? Haven't found proper examples so far. [\#1591](https://github.com/nlohmann/json/issues/1591)
- dump\_escaped possible error ? [\#1589](https://github.com/nlohmann/json/issues/1589)
- json::parse\(\) into a vector\<string\> results in unhandled exception [\#1587](https://github.com/nlohmann/json/issues/1587)
- push\_back\(\)/emplace\_back\(\) on array invalidates pointers to existing array items [\#1586](https://github.com/nlohmann/json/issues/1586)
- Getting nlohmann::detail::parse\_error on JSON generated by nlohmann::json not sure why [\#1583](https://github.com/nlohmann/json/issues/1583)
- getting error terminate called after throwing an instance of 'std::domain\_error' what\(\): cannot use at\(\) with string [\#1582](https://github.com/nlohmann/json/issues/1582)
- how i create json file [\#1581](https://github.com/nlohmann/json/issues/1581)
- prevent rounding of double datatype values [\#1580](https://github.com/nlohmann/json/issues/1580)
- Documentation Container Overview Doesn't Reference Const Methods [\#1579](https://github.com/nlohmann/json/issues/1579)
- Writing an array into a nlohmann::json object [\#1578](https://github.com/nlohmann/json/issues/1578)
- compilation error when using with another library [\#1577](https://github.com/nlohmann/json/issues/1577)
- Homebrew on OSX doesn't install cmake config file [\#1576](https://github.com/nlohmann/json/issues/1576)
- `unflatten` vs objects with number-ish keys [\#1575](https://github.com/nlohmann/json/issues/1575)
- JSON Parse Out of Range Error [\#1574](https://github.com/nlohmann/json/issues/1574)
- Integrating into existing CMake Project [\#1573](https://github.com/nlohmann/json/issues/1573)
- A "thinner" source code tar as part of release? [\#1572](https://github.com/nlohmann/json/issues/1572)
- conversion to std::string failed [\#1571](https://github.com/nlohmann/json/issues/1571)
- jPtr operation does not throw [\#1569](https://github.com/nlohmann/json/issues/1569)
- How to generate dll file for this project [\#1568](https://github.com/nlohmann/json/issues/1568)
- how to pass variable data to json in c [\#1567](https://github.com/nlohmann/json/issues/1567)
- I want to achieve an upgraded function. [\#1566](https://github.com/nlohmann/json/issues/1566)
- How to determine the type of elements read from a JSON array? [\#1564](https://github.com/nlohmann/json/issues/1564)
- try\_get\_to [\#1563](https://github.com/nlohmann/json/issues/1563)
- example code compile error [\#1562](https://github.com/nlohmann/json/issues/1562)
- How to iterate over nested json object [\#1561](https://github.com/nlohmann/json/issues/1561)
- Build Option/Separate Function to Allow to Throw on Duplicate Keys [\#1560](https://github.com/nlohmann/json/issues/1560)
- Compiler Switches -Weffc++ & -Wshadow are throwing errors [\#1558](https://github.com/nlohmann/json/issues/1558)
- warning: use of the 'nodiscard' attribute is a C++17 extension [\#1557](https://github.com/nlohmann/json/issues/1557)
- Import/Export compressed JSON files [\#1556](https://github.com/nlohmann/json/issues/1556)
- GDB renderers for json library [\#1554](https://github.com/nlohmann/json/issues/1554)
- Is it possible to construct a json string object from a binary buffer? [\#1553](https://github.com/nlohmann/json/issues/1553)
- json objects in list [\#1552](https://github.com/nlohmann/json/issues/1552)
- Matrix output [\#1550](https://github.com/nlohmann/json/issues/1550)
- Using json merge\_patch on ordered non-alphanumeric datasets [\#1549](https://github.com/nlohmann/json/issues/1549)
- Invalid parsed value for big integer [\#1548](https://github.com/nlohmann/json/issues/1548)
- Integrating with android ndk issues. [\#1547](https://github.com/nlohmann/json/issues/1547)
- add noexcept json::value\("key", default\) method variant? [\#1546](https://github.com/nlohmann/json/issues/1546)
- Thank you! 🙌 [\#1545](https://github.com/nlohmann/json/issues/1545)
- Output and input matrix [\#1544](https://github.com/nlohmann/json/issues/1544)
- Add regression tests for MSVC [\#1543](https://github.com/nlohmann/json/issues/1543)
- \[Help Needed!\] Season of Docs [\#1542](https://github.com/nlohmann/json/issues/1542)
- program still abort\(\) or exit\(\) with try catch [\#1541](https://github.com/nlohmann/json/issues/1541)
- Have a json::type\_error exception because of JSON object [\#1540](https://github.com/nlohmann/json/issues/1540)
- Using versioned namespaces [\#1539](https://github.com/nlohmann/json/issues/1539)
- Quoted numbers [\#1538](https://github.com/nlohmann/json/issues/1538)
- Reading a JSON file into an object [\#1537](https://github.com/nlohmann/json/issues/1537)
- Releases 3.6.0 and 3.6.1 don't build on conda / windows [\#1536](https://github.com/nlohmann/json/issues/1536)
- \[Clang\] warning: use of the 'nodiscard' attribute is a C++17 extension \[-Wc++17-extensions\] [\#1535](https://github.com/nlohmann/json/issues/1535)
- wchar\_t/std::wstring json can be created but not accessed [\#1533](https://github.com/nlohmann/json/issues/1533)
- json stringify [\#1532](https://github.com/nlohmann/json/issues/1532)
- How can I use std::string\_view as the json\_key to "operator \[\]" ? [\#1529](https://github.com/nlohmann/json/issues/1529)
- How can I use it from gcc on RPI [\#1528](https://github.com/nlohmann/json/issues/1528)
- std::pair treated as an array instead of key-value in `std::vector\<std::pair\<\>\>` [\#1520](https://github.com/nlohmann/json/issues/1520)
- Excessive Memory Usage for Large Json File [\#1516](https://github.com/nlohmann/json/issues/1516)
- SAX dumper [\#1512](https://github.com/nlohmann/json/issues/1512)
- Conversion to user type containing a std::vector not working with documented approach [\#1511](https://github.com/nlohmann/json/issues/1511)
- How to get position info or parser context with custom from\_json\(\) that may throw exceptions? [\#1508](https://github.com/nlohmann/json/issues/1508)
- Inconsistent use of type alias. [\#1507](https://github.com/nlohmann/json/issues/1507)
- Is there a current way to represent strings as json int? [\#1503](https://github.com/nlohmann/json/issues/1503)
- Intermittent issues with loadJSON [\#1484](https://github.com/nlohmann/json/issues/1484)
- use json construct std::string [\#1462](https://github.com/nlohmann/json/issues/1462)
- JSON Creation [\#1461](https://github.com/nlohmann/json/issues/1461)
- Substantial performance penalty caused by polymorphic input adapter [\#1457](https://github.com/nlohmann/json/issues/1457)
- Null bytes in files are treated like EOF [\#1095](https://github.com/nlohmann/json/issues/1095)
- Feature: to\_string\(const json& j\); [\#916](https://github.com/nlohmann/json/issues/916)
- Use GNUInstallDirs instead of hard-coded path. [\#1673](https://github.com/nlohmann/json/pull/1673) ([remyabel](https://github.com/remyabel))
- Package Manager: MSYS2 \(pacman\) [\#1670](https://github.com/nlohmann/json/pull/1670) ([podsvirov](https://github.com/podsvirov))
- Fix json.hpp compilation issue with other typedefs with same name \(Issue \#1642\) [\#1643](https://github.com/nlohmann/json/pull/1643) ([kevinlul](https://github.com/kevinlul))
- Add explicit conversion from json to std::string\_view in conversion unit test [\#1639](https://github.com/nlohmann/json/pull/1639) ([taylorhoward92](https://github.com/taylorhoward92))
- Minor fixes in docs [\#1625](https://github.com/nlohmann/json/pull/1625) ([nickaein](https://github.com/nickaein))
- Fix broken links to documentation [\#1598](https://github.com/nlohmann/json/pull/1598) ([nickaein](https://github.com/nickaein))
- Added to\_string and added basic tests [\#1585](https://github.com/nlohmann/json/pull/1585) ([Macr0Nerd](https://github.com/Macr0Nerd))
- Regression tests for MSVC [\#1570](https://github.com/nlohmann/json/pull/1570) ([nickaein](https://github.com/nickaein))
- Fix/1511 [\#1555](https://github.com/nlohmann/json/pull/1555) ([theodelrieu](https://github.com/theodelrieu))
- Remove C++17 extension warning from clang; \#1535 [\#1551](https://github.com/nlohmann/json/pull/1551) ([heavywatal](https://github.com/heavywatal))
- moved from Catch to doctest for unit tests [\#1439](https://github.com/nlohmann/json/pull/1439) ([onqtam](https://github.com/onqtam))
## [v3.6.1](https://github.com/nlohmann/json/releases/tag/v3.6.1) (2019-03-20)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.6.0...v3.6.1)
- Failed to build with \<Windows.h\> [\#1531](https://github.com/nlohmann/json/issues/1531)
- Compiling 3.6.0 with GCC \> 7, array vs std::array \#590 is back [\#1530](https://github.com/nlohmann/json/issues/1530)
- 3.6.0: warning: missing initializer for member 'std::array\<char, 9ul\>::\_M\_elems' \[-Wmissing-field-initializers\] [\#1527](https://github.com/nlohmann/json/issues/1527)
- unable to parse json [\#1525](https://github.com/nlohmann/json/issues/1525)
## [v3.6.0](https://github.com/nlohmann/json/releases/tag/v3.6.0) (2019-03-19)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.5.0...v3.6.0)
- How can I turn a string of a json array into a json array? [\#1526](https://github.com/nlohmann/json/issues/1526)
- Minor: missing a std:: namespace tag [\#1521](https://github.com/nlohmann/json/issues/1521)
- how to precision to four decimal for double when use to\_json [\#1519](https://github.com/nlohmann/json/issues/1519)
- error parse [\#1518](https://github.com/nlohmann/json/issues/1518)
- Compile error: template argument deduction/substitution failed [\#1515](https://github.com/nlohmann/json/issues/1515)
- Support for Comments [\#1513](https://github.com/nlohmann/json/issues/1513)
- std::complex type [\#1510](https://github.com/nlohmann/json/issues/1510)
- CBOR byte string support [\#1509](https://github.com/nlohmann/json/issues/1509)
- Compilation error getting a std::pair\<\> on latest VS 2017 compiler [\#1506](https://github.com/nlohmann/json/issues/1506)
- "Integration" section of documentation needs update? [\#1505](https://github.com/nlohmann/json/issues/1505)
- Json object from string from a TCP socket [\#1504](https://github.com/nlohmann/json/issues/1504)
- MSVC warning C4946 \("reinterpret\_cast used between related classes"\) compiling json.hpp [\#1502](https://github.com/nlohmann/json/issues/1502)
- How to programmatically fill an n-th dimensional JSON object? [\#1501](https://github.com/nlohmann/json/issues/1501)
- Error compiling with clang and `JSON\_NOEXCEPTION`: need to include `cstdlib` [\#1500](https://github.com/nlohmann/json/issues/1500)
- The code compiles unsuccessfully with android-ndk-r10e [\#1499](https://github.com/nlohmann/json/issues/1499)
- Cmake 3.1 in develop, when is it likely to make it into a stable release? [\#1498](https://github.com/nlohmann/json/issues/1498)
- Repository is almost 450MB [\#1497](https://github.com/nlohmann/json/issues/1497)
- Some Help please object inside array [\#1494](https://github.com/nlohmann/json/issues/1494)
- How to get data into vector of user-defined type from a Json object [\#1493](https://github.com/nlohmann/json/issues/1493)
- how to find subelement without loop [\#1490](https://github.com/nlohmann/json/issues/1490)
- json to std::map [\#1487](https://github.com/nlohmann/json/issues/1487)
- Type in README.md [\#1486](https://github.com/nlohmann/json/issues/1486)
- Error in parsing and reading msgpack-lite [\#1485](https://github.com/nlohmann/json/issues/1485)
- Compiling issues with libc 2.12 [\#1483](https://github.com/nlohmann/json/issues/1483)
- How do I use reference or pointer binding values? [\#1482](https://github.com/nlohmann/json/issues/1482)
- Compilation fails in MSVC with the Microsoft Language Extensions disabled [\#1481](https://github.com/nlohmann/json/issues/1481)
- Functional visit [\#1480](https://github.com/nlohmann/json/issues/1480)
- \[Question\] Unescaped dump [\#1479](https://github.com/nlohmann/json/issues/1479)
- Some Help please [\#1478](https://github.com/nlohmann/json/issues/1478)
- Global variables are stored within the JSON file, how do I declare them as global variables when I read them out in my C++ program? [\#1476](https://github.com/nlohmann/json/issues/1476)
- Unable to modify one of the values within the JSON file, and save it [\#1475](https://github.com/nlohmann/json/issues/1475)
- Documentation of parse function has two identical @pre causes [\#1473](https://github.com/nlohmann/json/issues/1473)
- GCC 9.0 build failure [\#1472](https://github.com/nlohmann/json/issues/1472)
- Can we have an `exists\(\)` method? [\#1471](https://github.com/nlohmann/json/issues/1471)
- How to parse multi object json from file? [\#1470](https://github.com/nlohmann/json/issues/1470)
- How to returns the name of the upper object? [\#1467](https://github.com/nlohmann/json/issues/1467)
- Error: "tuple\_size" has already been declared in the current scope [\#1466](https://github.com/nlohmann/json/issues/1466)
- Checking keys of two jsons against eachother [\#1465](https://github.com/nlohmann/json/issues/1465)
- Disable installation when used as meson subproject [\#1463](https://github.com/nlohmann/json/issues/1463)
- Unpack list of integers to a std::vector\<int\> [\#1460](https://github.com/nlohmann/json/issues/1460)
- Implement DRY definition of JSON representation of a c++ class [\#1459](https://github.com/nlohmann/json/issues/1459)
- json.exception.type\_error.305 with GCC 4.9 when using C++ {} initializer [\#1458](https://github.com/nlohmann/json/issues/1458)
- API to convert an "uninitialized" json into an empty object or empty array [\#1456](https://github.com/nlohmann/json/issues/1456)
- How to parse a vector of objects with const attributes [\#1453](https://github.com/nlohmann/json/issues/1453)
- NLOHMANN\_JSON\_SERIALIZE\_ENUM potentially requires duplicate definitions [\#1450](https://github.com/nlohmann/json/issues/1450)
- Question about making json object from file directory [\#1449](https://github.com/nlohmann/json/issues/1449)
- .get\(\) throws error if used with userdefined structs in unordered\_map [\#1448](https://github.com/nlohmann/json/issues/1448)
- Integer Overflow \(OSS-Fuzz 12506\) [\#1447](https://github.com/nlohmann/json/issues/1447)
- If a string has too many invalid UTF-8 characters, json::dump attempts to index an array out of bounds. [\#1445](https://github.com/nlohmann/json/issues/1445)
- Setting values of .JSON file [\#1444](https://github.com/nlohmann/json/issues/1444)
- alias object\_t::key\_type in basic\_json [\#1442](https://github.com/nlohmann/json/issues/1442)
- Latest Ubuntu package is 2.1.1 [\#1438](https://github.com/nlohmann/json/issues/1438)
- lexer.hpp\(1363\) '\_snprintf': is not a member | Visualstudio 2017 [\#1437](https://github.com/nlohmann/json/issues/1437)
- Static method invites inadvertent logic error. [\#1433](https://github.com/nlohmann/json/issues/1433)
- EOS compilation produces "fatal error: 'nlohmann/json.hpp' file not found" [\#1432](https://github.com/nlohmann/json/issues/1432)
- Support for bad commas [\#1429](https://github.com/nlohmann/json/issues/1429)
- Please have one base exception class for all json exceptions [\#1427](https://github.com/nlohmann/json/issues/1427)
- Compilation warning: 'tuple\_size' defined as a class template here but previously declared as a struct template [\#1426](https://github.com/nlohmann/json/issues/1426)
- Which version can be used with GCC 4.8.2 ? [\#1424](https://github.com/nlohmann/json/issues/1424)
- Ignore nullptr values on constructing json object from a container [\#1422](https://github.com/nlohmann/json/issues/1422)
- Support for custom float precision via unquoted strings [\#1421](https://github.com/nlohmann/json/issues/1421)
- Segmentation fault \(stack overflow\) due to unbounded recursion [\#1419](https://github.com/nlohmann/json/issues/1419)
- It is possible to call `json::find` with a json\_pointer as argument. This causes runtime UB/crash. [\#1418](https://github.com/nlohmann/json/issues/1418)
- Dump throwing exception [\#1416](https://github.com/nlohmann/json/issues/1416)
- Build error [\#1415](https://github.com/nlohmann/json/issues/1415)
- Append version to include.zip [\#1412](https://github.com/nlohmann/json/issues/1412)
- error C2039: '\_snprintf': is not a member of 'std' - Windows [\#1408](https://github.com/nlohmann/json/issues/1408)
- Deserializing to vector [\#1407](https://github.com/nlohmann/json/issues/1407)
- Efficient way to set a `json` object as value into another `json` key [\#1406](https://github.com/nlohmann/json/issues/1406)
- Document return value of parse\(\) when allow\_exceptions == false and parsing fails [\#1405](https://github.com/nlohmann/json/issues/1405)
- Unexpected behaviour with structured binding [\#1404](https://github.com/nlohmann/json/issues/1404)
- Which native types does get\<type\>\(\) allow? [\#1403](https://github.com/nlohmann/json/issues/1403)
- Add something like Json::StaticString [\#1402](https://github.com/nlohmann/json/issues/1402)
- -Wmismatched-tags in 3.5.0? [\#1401](https://github.com/nlohmann/json/issues/1401)
- Coverity Scan reports an UNCAUGHT\_EXCEPT issue [\#1400](https://github.com/nlohmann/json/issues/1400)
- fff [\#1399](https://github.com/nlohmann/json/issues/1399)
- sorry this is not an issue, just a Question, How to change a key value in a file and save it ? [\#1398](https://github.com/nlohmann/json/issues/1398)
- appveyor x64 builds appear to be using Win32 toolset [\#1374](https://github.com/nlohmann/json/issues/1374)
- Serializing/Deserializing a Class containing a vector of itself [\#1373](https://github.com/nlohmann/json/issues/1373)
- Retrieving array elements. [\#1369](https://github.com/nlohmann/json/issues/1369)
- Deserialize [\#1366](https://github.com/nlohmann/json/issues/1366)
- call of overloaded for push\_back and operator+= is ambiguous [\#1352](https://github.com/nlohmann/json/issues/1352)
- got an error and cann't figure it out [\#1351](https://github.com/nlohmann/json/issues/1351)
- Improve number-to-string conversion [\#1334](https://github.com/nlohmann/json/issues/1334)
- Implicit type conversion error on MSVC [\#1333](https://github.com/nlohmann/json/issues/1333)
- NuGet Package [\#1132](https://github.com/nlohmann/json/issues/1132)
- Change macros to numeric\_limits [\#1514](https://github.com/nlohmann/json/pull/1514) ([naszta](https://github.com/naszta))
- fix GCC 7.1.1 - 7.2.1 on CentOS [\#1496](https://github.com/nlohmann/json/pull/1496) ([lieff](https://github.com/lieff))
- Update Buckaroo instructions in README.md [\#1495](https://github.com/nlohmann/json/pull/1495) ([njlr](https://github.com/njlr))
- Fix gcc9 build error test/src/unit-allocator.cpp \(Issue \#1472\) [\#1492](https://github.com/nlohmann/json/pull/1492) ([stac47](https://github.com/stac47))
- Fix typo in README.md [\#1491](https://github.com/nlohmann/json/pull/1491) ([nickaein](https://github.com/nickaein))
- Do proper endian conversions [\#1489](https://github.com/nlohmann/json/pull/1489) ([andreas-schwab](https://github.com/andreas-schwab))
- Fix documentation [\#1477](https://github.com/nlohmann/json/pull/1477) ([nickaein](https://github.com/nickaein))
- Implement contains\(\) member function [\#1474](https://github.com/nlohmann/json/pull/1474) ([nickaein](https://github.com/nickaein))
- Add operator/= and operator/ to construct a JSON pointer by appending two JSON pointers [\#1469](https://github.com/nlohmann/json/pull/1469) ([garethsb-sony](https://github.com/garethsb-sony))
- Disable Clang -Wmismatched-tags warning on tuple\_size / tuple\_element [\#1468](https://github.com/nlohmann/json/pull/1468) ([past-due](https://github.com/past-due))
- Disable installation when used as meson subproject. \#1463 [\#1464](https://github.com/nlohmann/json/pull/1464) ([elvisoric](https://github.com/elvisoric))
- docs: README typo [\#1455](https://github.com/nlohmann/json/pull/1455) ([wythe](https://github.com/wythe))
- remove extra semicolon from readme [\#1451](https://github.com/nlohmann/json/pull/1451) ([Afforix](https://github.com/Afforix))
- attempt to fix \#1445, flush buffer in serializer::dump\_escaped in UTF8\_REJECT case. [\#1446](https://github.com/nlohmann/json/pull/1446) ([scinart](https://github.com/scinart))
- Use C++11 features supported by CMake 3.1. [\#1441](https://github.com/nlohmann/json/pull/1441) ([iwanders](https://github.com/iwanders))
- :rotating\_light: fixed unused variable warning [\#1435](https://github.com/nlohmann/json/pull/1435) ([pboettch](https://github.com/pboettch))
- allow push\_back\(\) and pop\_back\(\) calls on json\_pointer [\#1434](https://github.com/nlohmann/json/pull/1434) ([pboettch](https://github.com/pboettch))
- Add instructions about using nlohmann/json with the conda package manager [\#1430](https://github.com/nlohmann/json/pull/1430) ([nicoddemus](https://github.com/nicoddemus))
- Updated year in README.md [\#1425](https://github.com/nlohmann/json/pull/1425) ([hijxf](https://github.com/hijxf))
- Fixed broken links in the README file [\#1423](https://github.com/nlohmann/json/pull/1423) ([skypjack](https://github.com/skypjack))
- Fixed broken links in the README file [\#1420](https://github.com/nlohmann/json/pull/1420) ([skypjack](https://github.com/skypjack))
- docs: typo in README [\#1417](https://github.com/nlohmann/json/pull/1417) ([wythe](https://github.com/wythe))
- Fix x64 target platform for appveyor [\#1414](https://github.com/nlohmann/json/pull/1414) ([nickaein](https://github.com/nickaein))
- Improve dump\_integer performance [\#1411](https://github.com/nlohmann/json/pull/1411) ([nickaein](https://github.com/nickaein))
- buildsystem: relax requirement on cmake version [\#1409](https://github.com/nlohmann/json/pull/1409) ([yann-morin-1998](https://github.com/yann-morin-1998))
- CMake: Optional Install if Embedded [\#1330](https://github.com/nlohmann/json/pull/1330) ([ax3l](https://github.com/ax3l))
## [v3.5.0](https://github.com/nlohmann/json/releases/tag/v3.5.0) (2018-12-21) ## [v3.5.0](https://github.com/nlohmann/json/releases/tag/v3.5.0) (2018-12-21)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.4.0...v3.5.0) [Full Changelog](https://github.com/nlohmann/json/compare/v3.4.0...v3.5.0)
@ -46,7 +448,6 @@ All notable changes to this project will be documented in this file. This projec
- Protect macro expansion of commonly defined macros [\#1337](https://github.com/nlohmann/json/issues/1337) - Protect macro expansion of commonly defined macros [\#1337](https://github.com/nlohmann/json/issues/1337)
- How to validate an input before parsing? [\#1336](https://github.com/nlohmann/json/issues/1336) - How to validate an input before parsing? [\#1336](https://github.com/nlohmann/json/issues/1336)
- Non-verifying dump\(\) alternative for debugging/logging needed [\#1335](https://github.com/nlohmann/json/issues/1335) - Non-verifying dump\(\) alternative for debugging/logging needed [\#1335](https://github.com/nlohmann/json/issues/1335)
- Improve number-to-string conversion [\#1334](https://github.com/nlohmann/json/issues/1334)
- Json Libarary is not responding for me in c++ [\#1332](https://github.com/nlohmann/json/issues/1332) - Json Libarary is not responding for me in c++ [\#1332](https://github.com/nlohmann/json/issues/1332)
- Question - how to find an object in an array [\#1331](https://github.com/nlohmann/json/issues/1331) - Question - how to find an object in an array [\#1331](https://github.com/nlohmann/json/issues/1331)
- Nesting additional data in json object [\#1328](https://github.com/nlohmann/json/issues/1328) - Nesting additional data in json object [\#1328](https://github.com/nlohmann/json/issues/1328)
@ -76,7 +477,7 @@ All notable changes to this project will be documented in this file. This projec
- Fix merge\_patch shadow warning [\#1346](https://github.com/nlohmann/json/pull/1346) ([ax3l](https://github.com/ax3l)) - Fix merge\_patch shadow warning [\#1346](https://github.com/nlohmann/json/pull/1346) ([ax3l](https://github.com/ax3l))
- Allow installation via Meson [\#1345](https://github.com/nlohmann/json/pull/1345) ([mpoquet](https://github.com/mpoquet)) - Allow installation via Meson [\#1345](https://github.com/nlohmann/json/pull/1345) ([mpoquet](https://github.com/mpoquet))
- Set eofbit on exhausted input stream. [\#1343](https://github.com/nlohmann/json/pull/1343) ([mefyl](https://github.com/mefyl)) - Set eofbit on exhausted input stream. [\#1343](https://github.com/nlohmann/json/pull/1343) ([mefyl](https://github.com/mefyl))
- Add a SFINAE friendly iterator\_traits and use that instead. [\#1342](https://github.com/nlohmann/json/pull/1342) ([davedissian](https://github.com/davedissian)) - Add a SFINAE friendly iterator\_traits and use that instead. [\#1342](https://github.com/nlohmann/json/pull/1342) ([dgavedissian](https://github.com/dgavedissian))
- Fix EOL Whitespaces & CMake Spelling [\#1329](https://github.com/nlohmann/json/pull/1329) ([ax3l](https://github.com/ax3l)) - Fix EOL Whitespaces & CMake Spelling [\#1329](https://github.com/nlohmann/json/pull/1329) ([ax3l](https://github.com/ax3l))
## [v3.4.0](https://github.com/nlohmann/json/releases/tag/v3.4.0) (2018-10-30) ## [v3.4.0](https://github.com/nlohmann/json/releases/tag/v3.4.0) (2018-10-30)
@ -115,7 +516,6 @@ All notable changes to this project will be documented in this file. This projec
- enum to json mapping [\#1208](https://github.com/nlohmann/json/issues/1208) - enum to json mapping [\#1208](https://github.com/nlohmann/json/issues/1208)
- Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198) - Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198)
- CMakeLists.txt in release zips? [\#1184](https://github.com/nlohmann/json/issues/1184) - CMakeLists.txt in release zips? [\#1184](https://github.com/nlohmann/json/issues/1184)
- CBOR byte string support [\#1129](https://github.com/nlohmann/json/issues/1129)
- Add macro to define enum/JSON mapping [\#1323](https://github.com/nlohmann/json/pull/1323) ([nlohmann](https://github.com/nlohmann)) - Add macro to define enum/JSON mapping [\#1323](https://github.com/nlohmann/json/pull/1323) ([nlohmann](https://github.com/nlohmann))
- Add BSON support [\#1320](https://github.com/nlohmann/json/pull/1320) ([nlohmann](https://github.com/nlohmann)) - Add BSON support [\#1320](https://github.com/nlohmann/json/pull/1320) ([nlohmann](https://github.com/nlohmann))
@ -274,7 +674,6 @@ All notable changes to this project will be documented in this file. This projec
- accessing key by reference [\#1098](https://github.com/nlohmann/json/issues/1098) - accessing key by reference [\#1098](https://github.com/nlohmann/json/issues/1098)
- clang 3.8.0 croaks while trying to compile with debug symbols [\#1097](https://github.com/nlohmann/json/issues/1097) - clang 3.8.0 croaks while trying to compile with debug symbols [\#1097](https://github.com/nlohmann/json/issues/1097)
- Serialize a list of class objects with json [\#1096](https://github.com/nlohmann/json/issues/1096) - Serialize a list of class objects with json [\#1096](https://github.com/nlohmann/json/issues/1096)
- Null bytes in files are treated like EOF [\#1095](https://github.com/nlohmann/json/issues/1095)
- Small question [\#1094](https://github.com/nlohmann/json/issues/1094) - Small question [\#1094](https://github.com/nlohmann/json/issues/1094)
- Upgrading to 3.x: to\_/from\_json with enum class [\#1093](https://github.com/nlohmann/json/issues/1093) - Upgrading to 3.x: to\_/from\_json with enum class [\#1093](https://github.com/nlohmann/json/issues/1093)
- Q: few questions about json construction [\#1092](https://github.com/nlohmann/json/issues/1092) - Q: few questions about json construction [\#1092](https://github.com/nlohmann/json/issues/1092)
@ -406,7 +805,6 @@ All notable changes to this project will be documented in this file. This projec
- os\_defines.h:44:19: error: missing binary operator before token "\(" [\#970](https://github.com/nlohmann/json/issues/970) - os\_defines.h:44:19: error: missing binary operator before token "\(" [\#970](https://github.com/nlohmann/json/issues/970)
- Passing an iteration object by reference to a function [\#967](https://github.com/nlohmann/json/issues/967) - Passing an iteration object by reference to a function [\#967](https://github.com/nlohmann/json/issues/967)
- Json and fmt::lib's format\_arg\(\) [\#964](https://github.com/nlohmann/json/issues/964) - Json and fmt::lib's format\_arg\(\) [\#964](https://github.com/nlohmann/json/issues/964)
- Feature: to\_string\(const json& j\); [\#916](https://github.com/nlohmann/json/issues/916)
- 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))
@ -645,7 +1043,6 @@ All notable changes to this project will be documented in this file. This projec
- Compile-Error C2100 \(MS VS2015\) in line 887 json.hpp [\#719](https://github.com/nlohmann/json/issues/719) - Compile-Error C2100 \(MS VS2015\) in line 887 json.hpp [\#719](https://github.com/nlohmann/json/issues/719)
- from\_json not working for boost::optional example [\#718](https://github.com/nlohmann/json/issues/718) - from\_json not working for boost::optional example [\#718](https://github.com/nlohmann/json/issues/718)
- about from\_json and to\_json function [\#717](https://github.com/nlohmann/json/issues/717) - about from\_json and to\_json function [\#717](https://github.com/nlohmann/json/issues/717)
- How to deserialize array with derived objects [\#716](https://github.com/nlohmann/json/issues/716)
- How to detect parse failure? [\#715](https://github.com/nlohmann/json/issues/715) - How to detect parse failure? [\#715](https://github.com/nlohmann/json/issues/715)
- Parse throw std::ios\_base::failure exception when failbit set to true [\#714](https://github.com/nlohmann/json/issues/714) - Parse throw std::ios\_base::failure exception when failbit set to true [\#714](https://github.com/nlohmann/json/issues/714)
- Is there a way of format just making a pretty print without changing the key's orders ? [\#713](https://github.com/nlohmann/json/issues/713) - Is there a way of format just making a pretty print without changing the key's orders ? [\#713](https://github.com/nlohmann/json/issues/713)

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2013-2018 Niels Lohmann Copyright (c) 2013-2019 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

472
Makefile
View file

@ -1,44 +1,31 @@
.PHONY: pretty clean ChangeLog.md .PHONY: pretty clean ChangeLog.md release
SRCS = include/nlohmann/json.hpp \ ##########################################################################
include/nlohmann/json_fwd.hpp \ # configuration
include/nlohmann/adl_serializer.hpp \ ##########################################################################
include/nlohmann/detail/conversions/from_json.hpp \
include/nlohmann/detail/conversions/to_chars.hpp \
include/nlohmann/detail/conversions/to_json.hpp \
include/nlohmann/detail/exceptions.hpp \
include/nlohmann/detail/input/binary_reader.hpp \
include/nlohmann/detail/input/input_adapters.hpp \
include/nlohmann/detail/input/json_sax.hpp \
include/nlohmann/detail/input/lexer.hpp \
include/nlohmann/detail/input/parser.hpp \
include/nlohmann/detail/input/position_t.hpp \
include/nlohmann/detail/iterators/internal_iterator.hpp \
include/nlohmann/detail/iterators/iter_impl.hpp \
include/nlohmann/detail/iterators/iteration_proxy.hpp \
include/nlohmann/detail/iterators/json_reverse_iterator.hpp \
include/nlohmann/detail/iterators/primitive_iterator.hpp \
include/nlohmann/detail/json_pointer.hpp \
include/nlohmann/detail/json_ref.hpp \
include/nlohmann/detail/macro_scope.hpp \
include/nlohmann/detail/macro_unscope.hpp \
include/nlohmann/detail/meta/cpp_future.hpp \
include/nlohmann/detail/meta/detected.hpp \
include/nlohmann/detail/meta/type_traits.hpp \
include/nlohmann/detail/meta/void_t.hpp \
include/nlohmann/detail/output/binary_writer.hpp \
include/nlohmann/detail/output/output_adapters.hpp \
include/nlohmann/detail/output/serializer.hpp \
include/nlohmann/detail/value_t.hpp
UNAME = $(shell uname)
CXX=clang++
AMALGAMATED_FILE=single_include/nlohmann/json.hpp
# directory to recent compiler binaries # directory to recent compiler binaries
COMPILER_DIR=/Users/niels/Documents/projects/compilers/local/bin COMPILER_DIR=/Users/niels/Documents/projects/compilers/local/bin
# find GNU sed to use `-i` parameter
SED:=$(shell command -v gsed || which sed)
##########################################################################
# source files
##########################################################################
# the list of sources in the include folder
SRCS=$(shell find include -type f | sort)
# the single header (amalgamated from the source files)
AMALGAMATED_FILE=single_include/nlohmann/json.hpp
##########################################################################
# documentation of the Makefile's targets
##########################################################################
# main target # main target
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"
@ -48,7 +35,11 @@ all:
@echo "check-fast - compile and execute test suite (skip long-running tests)" @echo "check-fast - compile and execute test suite (skip long-running tests)"
@echo "clean - remove built files" @echo "clean - remove built files"
@echo "coverage - create coverage information with lcov" @echo "coverage - create coverage information with lcov"
@echo "coverage-fast - create coverage information with fastcov"
@echo "cppcheck - analyze code with cppcheck" @echo "cppcheck - analyze code with cppcheck"
@echo "cpplint - analyze code with cpplint"
@echo "clang_tidy - analyze code with Clang-Tidy"
@echo "clang_analyze - analyze code with Clang-Analyzer"
@echo "doctest - compile example files and check their output" @echo "doctest - compile example files and check their output"
@echo "fuzz_testing - prepare fuzz testing of the JSON parser" @echo "fuzz_testing - prepare fuzz testing of the JSON parser"
@echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser" @echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser"
@ -61,6 +52,7 @@ all:
@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 # unit tests
########################################################################## ##########################################################################
@ -73,30 +65,32 @@ json_unit:
check: check:
$(MAKE) check -C test $(MAKE) check -C test
# run unit tests and skip expensive tests
check-fast: check-fast:
$(MAKE) check -C test TEST_PATTERN="" $(MAKE) check -C test TEST_PATTERN=""
# clean up
clean:
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM
rm -fr benchmarks/files/numbers/*.json
rm -fr build_coverage build_benchmarks
$(MAKE) clean -Cdoc
$(MAKE) clean -Ctest
########################################################################## ##########################################################################
# coverage # coverage
########################################################################## ##########################################################################
coverage: coverage:
rm -fr build_coverage
mkdir build_coverage mkdir build_coverage
cd build_coverage ; CXX=g++-7 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON cd build_coverage ; CXX=g++-8 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
cd build_coverage ; ninja cd build_coverage ; ninja
cd build_coverage ; ctest -E '.*_default' -j10 cd build_coverage ; ctest -E '.*_default' -j10
cd build_coverage ; ninja lcov_html cd build_coverage ; ninja lcov_html
open build_coverage/test/html/index.html open build_coverage/test/html/index.html
coverage-fast:
rm -fr build_coverage
mkdir build_coverage
cd build_coverage ; CXX=g++-9 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
cd build_coverage ; ninja
cd build_coverage ; ctest -E '.*_default' -j10
cd build_coverage ; ninja fastcov_html
open build_coverage/test/html/index.html
########################################################################## ##########################################################################
# documentation tests # documentation tests
@ -112,105 +106,266 @@ doctest:
########################################################################## ##########################################################################
# calling Clang with all warnings, except: # calling Clang with all warnings, except:
# -Wno-documentation-unknown-command: code uses user-defined commands like @complexity
# -Wno-exit-time-destructors: warning in Catch code
# -Wno-keyword-macro: unit-tests use "#define private public"
# -Wno-deprecated-declarations: the library deprecated some functions
# -Wno-weak-vtables: exception class is defined inline, but has virtual method
# -Wno-range-loop-analysis: items tests "for(const auto i...)"
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
# -Wno-c++2a-compat: u8 literals will behave differently in C++20... # -Wno-c++2a-compat: u8 literals will behave differently in C++20...
# -Wno-deprecated-declarations: the library deprecated some functions
# -Wno-documentation-unknown-command: code uses user-defined commands like @complexity
# -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
# -Wno-keyword-macro: unit-tests use "#define private public"
# -Wno-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-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
# -Wno-weak-vtables: exception class is defined inline, but has virtual method
pedantic_clang: pedantic_clang:
$(MAKE) json_unit CXX=$(COMPILER_DIR)/clang++ CXXFLAGS="\ $(MAKE) json_unit CXX=c++ 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 \
-Weverything \ -Weverything \
-Wno-c++2a-compat \
-Wno-deprecated-declarations \
-Wno-documentation-unknown-command \ -Wno-documentation-unknown-command \
-Wno-exit-time-destructors \ -Wno-exit-time-destructors \
-Wno-keyword-macro \
-Wno-deprecated-declarations \
-Wno-weak-vtables \
-Wno-range-loop-analysis \
-Wno-float-equal \ -Wno-float-equal \
-Wno-keyword-macro \
-Wno-padded \
-Wno-range-loop-analysis \
-Wno-switch-enum -Wno-covered-switch-default \ -Wno-switch-enum -Wno-covered-switch-default \
-Wno-c++2a-compat \ -Wno-weak-vtables"
-Wno-padded"
# calling GCC with most warnings # calling GCC with most warnings
pedantic_gcc: pedantic_gcc:
$(MAKE) json_unit CXX=$(COMPILER_DIR)/g++ CXXFLAGS="\ $(MAKE) json_unit CXX=g++-9 CXXFLAGS=" \
-std=c++11 \ -std=c++11 \
-Wno-deprecated-declarations \ -Waddress \
-Werror \ -Waddress-of-packed-member \
-Wall -Wpedantic -Wextra \ -Waggressive-loop-optimizations \
-Waligned-new=all \
-Wall \
-Walloc-zero \
-Walloca \ -Walloca \
-Warray-bounds \
-Warray-bounds=2 \ -Warray-bounds=2 \
-Wcast-qual -Wcast-align \ -Wattribute-alias=2 \
-Wattribute-warning \
-Wattributes \
-Wbool-compare \
-Wbool-operation \
-Wbuiltin-declaration-mismatch \
-Wbuiltin-macro-redefined \
-Wcannot-profile \
-Wcast-align \
-Wcast-function-type \
-Wcast-qual \
-Wcatch-value=3 \
-Wchar-subscripts \ -Wchar-subscripts \
-Wclass-conversion \
-Wclass-memaccess \
-Wclobbered \
-Wcomment \
-Wcomments \
-Wconditionally-supported \ -Wconditionally-supported \
-Wconversion \ -Wconversion \
-Wconversion-null \
-Wcoverage-mismatch \
-Wcpp \
-Wctor-dtor-privacy \
-Wdangling-else \
-Wdate-time \ -Wdate-time \
-Wdelete-incomplete \
-Wdelete-non-virtual-dtor \
-Wdeprecated \ -Wdeprecated \
-Wdeprecated-copy \
-Wdeprecated-copy-dtor \
-Wdeprecated-declarations \
-Wdisabled-optimization \ -Wdisabled-optimization \
-Wdiv-by-zero \
-Wdouble-promotion \ -Wdouble-promotion \
-Wduplicated-branches \ -Wduplicated-branches \
-Wduplicated-cond \ -Wduplicated-cond \
-Weffc++ \
-Wempty-body \
-Wendif-labels \
-Wenum-compare \
-Wexpansion-to-defined \
-Werror \
-Wextra \
-Wextra-semi \
-Wfloat-conversion \
-Wformat \
-Wformat-contains-nul \
-Wformat-extra-args \
-Wformat-nonliteral \
-Wformat-overflow=2 \ -Wformat-overflow=2 \
-Wformat-security \
-Wformat-signedness \ -Wformat-signedness \
-Wformat-truncation=2 \ -Wformat-truncation=2 \
-Wformat-y2k \
-Wformat-zero-length \
-Wformat=2 \ -Wformat=2 \
-Wno-ignored-qualifiers \ -Wframe-address \
-Wfree-nonheap-object \
-Whsa \
-Wif-not-aligned \
-Wignored-attributes \
-Wignored-qualifiers \
-Wimplicit-fallthrough=5 \ -Wimplicit-fallthrough=5 \
-Winherited-variadic-ctor \
-Winit-list-lifetime \
-Winit-self \
-Winline \
-Wint-in-bool-context \
-Wint-to-pointer-cast \
-Winvalid-memory-model \
-Winvalid-offsetof \
-Winvalid-pch \
-Wliteral-suffix \
-Wlogical-not-parentheses \
-Wlogical-op \ -Wlogical-op \
-Wlto-type-mismatch \
-Wmain \
-Wmaybe-uninitialized \
-Wmemset-elt-size \
-Wmemset-transposed-args \
-Wmisleading-indentation \
-Wmissing-attributes \
-Wmissing-braces \
-Wmissing-declarations \ -Wmissing-declarations \
-Wmissing-field-initializers \
-Wmissing-format-attribute \ -Wmissing-format-attribute \
-Wmissing-include-dirs \ -Wmissing-include-dirs \
-Wmissing-noreturn \
-Wmissing-profile \
-Wmultichar \
-Wmultiple-inheritance \
-Wmultistatement-macros \
-Wnarrowing \
-Wno-deprecated-declarations \
-Wno-float-equal \
-Wno-long-long \
-Wno-namespaces \
-Wno-padded \
-Wno-switch-enum \
-Wno-system-headers \
-Wno-templates \
-Wno-undef \
-Wnoexcept \ -Wnoexcept \
-Wnoexcept-type \
-Wnon-template-friend \
-Wnon-virtual-dtor \
-Wnonnull \ -Wnonnull \
-Wnonnull-compare \
-Wnonportable-cfstrings \
-Wnormalized \
-Wnull-dereference \ -Wnull-dereference \
-Wodr \
-Wold-style-cast \ -Wold-style-cast \
-Wopenmp-simd \
-Woverflow \
-Woverlength-strings \
-Woverloaded-virtual \ -Woverloaded-virtual \
-Wpacked \
-Wpacked-bitfield-compat \
-Wpacked-not-aligned \
-Wparentheses \ -Wparentheses \
-Wpedantic \
-Wpessimizing-move \
-Wplacement-new=2 \ -Wplacement-new=2 \
-Wpmf-conversions \
-Wpointer-arith \
-Wpointer-compare \
-Wpragmas \
-Wprio-ctor-dtor \
-Wpsabi \
-Wredundant-decls \ -Wredundant-decls \
-Wredundant-move \
-Wregister \
-Wreorder \ -Wreorder \
-Wrestrict \ -Wrestrict \
-Wreturn-local-addr \
-Wreturn-type \
-Wscalar-storage-order \
-Wsequence-point \
-Wshadow \
-Wshadow-compatible-local \
-Wshadow-local \
-Wshadow=compatible-local \
-Wshadow=global \ -Wshadow=global \
-Wshadow=local \
-Wshift-count-negative \
-Wshift-count-overflow \
-Wshift-negative-value \
-Wshift-overflow=2 \ -Wshift-overflow=2 \
-Wsign-compare \
-Wsign-conversion \ -Wsign-conversion \
-Wsign-promo \ -Wsign-promo \
-Wsized-deallocation \ -Wsized-deallocation \
-Wsizeof-array-argument \
-Wsizeof-pointer-div \
-Wsizeof-pointer-memaccess \
-Wstack-protector \
-Wstrict-aliasing=3 \
-Wstrict-null-sentinel \
-Wstrict-overflow=5 \ -Wstrict-overflow=5 \
-Wstringop-overflow=4 \
-Wstringop-truncation \
-Wsubobject-linkage \
-Wsuggest-attribute=cold \
-Wsuggest-attribute=const \ -Wsuggest-attribute=const \
-Wsuggest-attribute=format \ -Wsuggest-attribute=format \
-Wsuggest-attribute=malloc \
-Wsuggest-attribute=noreturn \ -Wsuggest-attribute=noreturn \
-Wsuggest-attribute=pure \ -Wsuggest-attribute=pure \
-Wsuggest-final-methods \ -Wsuggest-final-methods \
-Wsuggest-final-types \ -Wsuggest-final-types \
-Wsuggest-override \ -Wsuggest-override \
-Wswitch \
-Wswitch-bool \
-Wswitch-default \
-Wswitch-unreachable \
-Wsync-nand \
-Wsynth \
-Wtautological-compare \
-Wterminate \
-Wtrampolines \
-Wtrigraphs \ -Wtrigraphs \
-Wundef \ -Wtype-limits \
-Wuninitialized -Wunknown-pragmas \ -Wuninitialized \
-Wunknown-pragmas \
-Wunreachable-code \
-Wunsafe-loop-optimizations \
-Wunused \ -Wunused \
-Wunused-but-set-parameter \
-Wunused-but-set-variable \
-Wunused-const-variable=2 \ -Wunused-const-variable=2 \
-Wunused-function \
-Wunused-label \
-Wunused-local-typedefs \
-Wunused-macros \ -Wunused-macros \
-Wunused-parameter \ -Wunused-parameter \
-Wunused-result \
-Wunused-value \
-Wunused-variable \
-Wuseless-cast \ -Wuseless-cast \
-Wvarargs \
-Wvariadic-macros \ -Wvariadic-macros \
-Wctor-dtor-privacy \ -Wvector-operation-performance \
-Winit-self \ -Wvirtual-inheritance \
-Wstrict-null-sentinel" -Wvirtual-move-assign \
-Wvla \
-Wvolatile-register-var \
-Wwrite-strings \
-Wzero-as-null-pointer-constant \
"
########################################################################## ##########################################################################
# benchmarks # benchmarks
########################################################################## ##########################################################################
run_benchmarks: run_benchmarks:
rm -fr build_benchmarks
mkdir build_benchmarks mkdir build_benchmarks
cd build_benchmarks ; cmake ../benchmarks cd build_benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release
cd build_benchmarks ; make cd build_benchmarks ; ninja
cd build_benchmarks ; ./json_benchmarks cd build_benchmarks ; ./json_benchmarks
########################################################################## ##########################################################################
@ -272,51 +427,111 @@ fuzzing-stop:
-killall fuzzer -killall fuzzer
-killall afl-fuzz -killall afl-fuzz
########################################################################## ##########################################################################
# static analyzer # Static analysis
########################################################################## ##########################################################################
# call cppcheck on the main header file # call cppcheck <http://cppcheck.sourceforge.net>
# Note: this target is called by Travis
cppcheck: cppcheck:
cppcheck --enable=warning --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1 cppcheck --enable=warning --inline-suppr --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1
# compile and check with Clang Static Analyzer # call Clang Static Analyzer <https://clang-analyzer.llvm.org>
clang_analyze: clang_analyze:
rm -fr clang_analyze_build rm -fr clang_analyze_build
mkdir clang_analyze_build mkdir clang_analyze_build
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja
cd clang_analyze_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 --use-c++=$(COMPILER_DIR)/clang++ --view -analyze-headers -o clang_analyze_build/report.html ninja cd clang_analyze_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 \
--use-c++=$(COMPILER_DIR)/clang++ -analyze-headers -o report ninja
open clang_analyze_build/report/*/index.html
# call cpplint <https://github.com/cpplint/cpplint>
# Note: some errors expected due to false positives
cpplint:
third_party/cpplint/cpplint.py \
--filter=-whitespace,-legal,-readability/alt_tokens,-runtime/references,-runtime/explicit \
--quiet --recursive $(SRCS)
# call Clang-Tidy <https://clang.llvm.org/extra/clang-tidy/>
clang_tidy:
$(COMPILER_DIR)/clang-tidy $(AMALGAMATED_FILE) -- -Iinclude -std=c++11
# call PVS-Studio Analyzer <https://www.viva64.com/en/pvs-studio/>
pvs_studio:
rm -fr pvs_studio_build
mkdir pvs_studio_build
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10
cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open pvs_studio_build/pvs/index.html
# call Infer <https://fbinfer.com> static analyzer
infer:
rm -fr infer_build
mkdir infer_build
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4
# call OCLint <http://oclint.org> static analyzer
oclint:
oclint $(SRCS) -report-type html -enable-global-analysis -o oclint_report.html -max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 -- -std=c++11 -Iinclude
open oclint_report.html
# execute the test suite with Clang sanitizers (address and undefined behavior)
clang_sanitize:
rm -fr clang_sanitize_build
mkdir clang_sanitize_build
cd clang_sanitize_build ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -GNinja
cd clang_sanitize_build ; ninja
cd clang_sanitize_build ; ctest -E '.*_default' -j10
########################################################################## ##########################################################################
# maintainer targets # Code format and source amalgamation
########################################################################## ##########################################################################
# pretty printer # call the Artistic Style pretty printer on all source files
pretty: pretty:
astyle --style=allman --indent=spaces=4 --indent-modifiers \ astyle \
--indent-switches --indent-preproc-block --indent-preproc-define \ --style=allman \
--indent-col1-comments --pad-oper --pad-header --align-pointer=type \ --indent=spaces=4 \
--align-reference=type --add-brackets --convert-tabs --close-templates \ --indent-modifiers \
--lineend=linux --preserve-date --suffix=none --formatted \ --indent-switches \
$(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp \ --indent-preproc-block \
benchmarks/src/benchmarks.cpp doc/examples/*.cpp --indent-preproc-define \
--indent-col1-comments \
--pad-oper \
--pad-header \
--align-pointer=type \
--align-reference=type \
--add-brackets \
--convert-tabs \
--close-templates \
--lineend=linux \
--preserve-date \
--suffix=none \
--formatted \
$(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp
# create single header file # create single header file
amalgamate: $(AMALGAMATED_FILE) amalgamate: $(AMALGAMATED_FILE)
# call the amalgamation tool and pretty print
$(AMALGAMATED_FILE): $(SRCS) $(AMALGAMATED_FILE): $(SRCS)
third_party/amalgamate/amalgamate.py -c third_party/amalgamate/config.json -s . --verbose=yes third_party/amalgamate/amalgamate.py -c third_party/amalgamate/config.json -s . --verbose=yes
$(MAKE) pretty $(MAKE) pretty
# check if single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources # check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
# Note: this target is called by Travis
check-amalgamation: check-amalgamation:
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ @mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
@$(MAKE) amalgamate @$(MAKE) amalgamate
@diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false) @diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false)
@mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) @mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE)
# check if every header in nlohmann includes sufficient headers to be compiled # check if every header in nlohmann includes sufficient headers to be compiled individually
# individually
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..." ; \
@ -325,29 +540,90 @@ check-single-includes:
rm -f single_include_test.cpp single_include_test; \ rm -f single_include_test.cpp single_include_test; \
done done
########################################################################## ##########################################################################
# changelog # CMake
########################################################################## ##########################################################################
# grep "^option" CMakeLists.txt test/CMakeLists.txt | sed 's/(/ /' | awk '{print $2}' | xargs
# check if all flags of our CMake files work
check_cmake_flags_do:
$(CMAKE_BINARY) --version
for flag in '' JSON_BuildTests JSON_Install JSON_MultipleHeaders JSON_Sanitizer JSON_Valgrind JSON_NoExceptions JSON_Coverage; do \
rm -fr cmake_build; \
mkdir cmake_build; \
echo "$(CMAKE_BINARY) .. -D$$flag=On" ; \
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" ; \
test -f Makefile || exit 1 ; \
cd .. ; \
done;
# call target `check_cmake_flags_do` twice: once for minimal required CMake version 3.1.0 and once for the installed version
check_cmake_flags:
wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Darwin64.tar.gz
tar xfz cmake-3.1.0-Darwin64.tar.gz
CMAKE_BINARY=$(abspath cmake-3.1.0-Darwin64/CMake.app/Contents/bin/cmake) $(MAKE) check_cmake_flags_do
CMAKE_BINARY=$(shell which cmake) $(MAKE) check_cmake_flags_do
##########################################################################
# ChangeLog
##########################################################################
# Create a ChangeLog based on the git log using the GitHub Changelog Generator
# (<https://github.com/github-changelog-generator/github-changelog-generator>).
# variable to control the diffs between the last released version and the current repository state
NEXT_VERSION ?= "unreleased" NEXT_VERSION ?= "unreleased"
ChangeLog.md: ChangeLog.md:
github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s --future-release $(NEXT_VERSION) github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s --future-release $(NEXT_VERSION)
gsed -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md $(SED) -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md
gsed -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md $(SED) -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md
########################################################################## ##########################################################################
# release # Release files
########################################################################## ##########################################################################
# Create the files for a release and add signatures and hashes. We use `-X` to make the resulting ZIP file
# reproducible, see <https://content.pivotal.io/blog/barriers-to-deterministic-reproducible-zip-files>.
release: release:
rm -fr release_files
mkdir release_files mkdir release_files
zip -9 -r include.zip include/* zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) meson.build
gpg --armor --detach-sig include.zip gpg --armor --detach-sig include.zip
mv include.zip include.zip.asc release_files mv include.zip include.zip.asc release_files
gpg --armor --detach-sig single_include/nlohmann/json.hpp gpg --armor --detach-sig $(AMALGAMATED_FILE)
cp single_include/nlohmann/json.hpp release_files cp $(AMALGAMATED_FILE) release_files
mv single_include/nlohmann/json.hpp.asc release_files mv $(AMALGAMATED_FILE).asc release_files
cd release_files ; shasum -a 256 json.hpp > hashes.txt cd release_files ; shasum -a 256 json.hpp > hashes.txt
cd release_files ; shasum -a 256 include.zip >> hashes.txt cd release_files ; shasum -a 256 include.zip >> hashes.txt
##########################################################################
# Maintenance
##########################################################################
# clean up
clean:
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html
rm -fr benchmarks/files/numbers/*.json
rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64
rm -fr build_coverage build_benchmarks fuzz-testing clang_analyze_build pvs_studio_build infer_build clang_sanitize_build cmake_build
$(MAKE) clean -Cdoc
$(MAKE) clean -Ctest
##########################################################################
# Thirdparty code
##########################################################################
update_hedley:
rm -f include/nlohmann/thirdparty/hedley/hedley.hpp include/nlohmann/thirdparty/hedley/hedley_undef.hpp
curl https://raw.githubusercontent.com/nemequ/hedley/master/hedley.h -o include/nlohmann/thirdparty/hedley/hedley.hpp
gsed -i 's/HEDLEY_/JSON_HEDLEY_/g' include/nlohmann/thirdparty/hedley/hedley.hpp
grep "[[:blank:]]*#[[:blank:]]*undef" include/nlohmann/thirdparty/hedley/hedley.hpp | grep -v "__" | sort | uniq | gsed 's/ //g' | gsed 's/undef/undef /g' > include/nlohmann/thirdparty/hedley/hedley_undef.hpp
$(MAKE) amalgamate

203
README.md
View file

@ -2,10 +2,12 @@
[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) [![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json)
[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json)
[![Build Status](https://circleci.com/gh/nlohmann/json.svg?style=svg)](https://circleci.com/gh/nlohmann/json)
[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nlohmann/json&amp;utm_campaign=Badge_Grade) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nlohmann/json&amp;utm_campaign=Badge_Grade)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf)
[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
@ -100,6 +102,10 @@ To embed the library directly into an existing CMake project, place the entire s
# run from your own project's code. # run from your own project's code.
set(JSON_BuildTests OFF CACHE INTERNAL "") set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it # Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
# unintended consequences that will break the build. It's generally # unintended consequences that will break the build. It's generally
# discouraged (although not necessarily well documented as such) to use # discouraged (although not necessarily well documented as such) to use
@ -145,17 +151,19 @@ endif()
### Package Managers ### Package Managers
:beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`. :beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`.
If you are using the [Meson Build System](http://mesonbuild.com), then you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. If you are using the [Meson Build System](http://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging.
The provided meson.build can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly.
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages. If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages.
If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the `nlohmann_json` package. Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging.
If you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. If you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging.
If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo install nlohmann/json`. Please file issues [here](https://github.com/LoopPerfect/buckaroo-recipes/issues/new?title=nlohmann/nlohmann/json). If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging. If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging.
@ -167,6 +175,8 @@ If you are using [NuGet](https://www.nuget.org), you can use the package [nlohma
If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues). If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues).
If you are using [MSYS2](http://www.msys2.org/), your can use the [mingw-w64-nlohmann_json](https://packages.msys2.org/base/mingw-w64-nlohmann_json) package, just type `pacman -S mingw-w64-i686-nlohmann_json` or `pacman -S mingw-w64-x86_64-nlohmann_json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann_json%5D) if you experience problems with the packages.
## 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)).
@ -238,7 +248,7 @@ json j2 = {
}; };
``` ```
Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa80485befaffcadaa39965494e0b4d2e.html#aa80485befaffcadaa39965494e0b4d2e) and [`json::object`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa13f7c0615867542ce80337cbcf13ada.html#aa13f7c0615867542ce80337cbcf13ada) will help: Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a9ad7ec0bc1082ed09d10900fbb20a21f.html#a9ad7ec0bc1082ed09d10900fbb20a21f) and [`json::object()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aaf509a7c029100d292187068f61c99b8.html#aaf509a7c029100d292187068f61c99b8) will help:
```cpp ```cpp
// a way to express the empty array [] // a way to express the empty array []
@ -273,7 +283,7 @@ auto j2 = R"(
Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object.
The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5a0339361f3282cb8fd2f9ede6e17d72.html#a5a0339361f3282cb8fd2f9ede6e17d72): The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_afd4ef1ac8ad50a5894a9afebca69140a.html#afd4ef1ac8ad50a5894a9afebca69140a):
```cpp ```cpp
// parse explicitly // parse explicitly
@ -316,7 +326,7 @@ std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::
std::cout << j_string << " == " << serialized_string << std::endl; std::cout << j_string << " == " << serialized_string << std::endl;
``` ```
[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value. [`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa6602bb24022183ab989439e19345d08.html#aa6602bb24022183ab989439e19345d08) returns the originally stored string value.
Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
@ -617,7 +627,7 @@ json j_patch = R"({
})"_json; })"_json;
// apply the patch // apply the patch
j_original.merge_patch(j_patch); j_document.merge_patch(j_patch);
// { // {
// "a": "z", // "a": "z",
// "c": { // "c": {
@ -920,7 +930,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
}) })
``` ```
The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serilization code. The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serialization code.
**Usage:** **Usage:**
@ -992,11 +1002,12 @@ json j_from_ubjson = json::from_ubjson(v_ubjson);
Though it's 2019 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: Though it's 2019 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
- GCC 4.8 - 9.0 (and possibly later) - GCC 4.8 - 9.2 (and possibly later)
- Clang 3.4 - 8.0 (and possibly later) - Clang 3.4 - 9.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)
- Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later)
I would be happy to learn about other compilers/versions. I would be happy to learn about other compilers/versions.
@ -1017,38 +1028,43 @@ Please note:
- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. - Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json): The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [CircleCI](https://circleci.com/gh/nlohmann/json), and [Doozer](https://doozer.io):
| Compiler | Operating System | Version String | | Compiler | Operating System | Version String |
|-----------------|------------------------------|----------------| |-----------------------|------------------------------|----------------|
| GCC 4.8.5 | Ubuntu 14.04.5 LTS | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 | | GCC 4.8.5 | Ubuntu 14.04.5 LTS | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 |
| GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | | GCC 4.8.5 | CentOS Release-7-6.1810.2.el7.centos.x86_64 | g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36) |
| GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | | GCC 4.9.2 (armv7l) | Raspbian GNU/Linux 8 (jessie) | g++ (Raspbian 4.9.2-10+deb8u2) 4.9.2 |
| GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | | GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 |
| GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 | | GCC 5.3.1 (armv7l) | Ubuntu 16.04 LTS | g++ (Ubuntu/Linaro 5.3.1-14ubuntu2) 5.3.1 20160413 |
| GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 | | GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 |
| GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 | | GCC 6.3.0 | Debian 9 (stretch) | g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 |
| Clang 3.5.0 | Ubuntu 14.04.1 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) | | GCC 6.3.1 | Fedora release 24 (Twenty Four) | g++ (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1) |
| Clang 3.6.2 | Ubuntu 14.04.1 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) | | GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 |
| Clang 3.7.1 | Ubuntu 14.04.1 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) | | GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 |
| Clang 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) | | GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 |
| Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) | | GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 |
| Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) | | GCC 9.2.1 | Ubuntu 14.05.1 LTS | g++-9 (Ubuntu 9.2.1-16ubuntu1~14.04.1) 9.2.1 20191030 |
| Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) | | Clang 3.5.0 | Ubuntu 14.04.1 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) |
| Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) | | Clang 3.6.2 | Ubuntu 14.04.1 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) |
| Clang Xcode 6.4 | OSX 10.10.5 | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | | Clang 3.7.1 | Ubuntu 14.04.1 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) |
| Clang Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) | | Clang 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) |
| Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) | | Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) |
| Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) | | Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) |
| Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) | | Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) |
| Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) | | Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) |
| Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) | | Clang 7.0.1 | Ubuntu 14.04.1 LTS | clang version 7.0.1-svn348686-1~exp1~20181213084532.54 (branches/release_70) |
| Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) | | Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) |
| Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) | | Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) |
| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | | Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) |
| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) | | Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) |
| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) |
| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) |
| Clang Xcode 10.1 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.5) |
| Clang Xcode 10.2 | OSX 10.14.4 | Apple LLVM version 10.0.1 (clang-1001.0.46.4) |
| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | | Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 |
| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 | | Visual Studio 15 2017 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 15.9.21+g9802d43bc3, MSVC 19.16.27032.1 |
| Visual Studio 16 2019 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 16.3.1+1def00d3d, MSVC 19.23.28106.4 |
## License ## License
@ -1056,7 +1072,7 @@ The following compilers are currently used in continuous integration at [Travis]
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-2018 [Niels Lohmann](http://nlohmann.me) Copyright &copy; 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: 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:
@ -1070,9 +1086,11 @@ The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed und
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](http://florian.loitsch.com/) The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](http://florian.loitsch.com/)
The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](http://creativecommons.org/publicdomain/zero/1.0/).
## Contact ## Contact
If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new/choose). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases.
Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc).
@ -1230,6 +1248,45 @@ I deeply appreciate the help of the following people.
- [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC. - [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.
- [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream. - [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.
- [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson. - [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.
- [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace.
- [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12.
- [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion.
- [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC.
- [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers.
- [John-Mark](https://github.com/johnmarkwayve) noted a missing header.
- [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0.
- [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0.
- [Ivor Wanders](https://github.com/iwanders) helped reducing the CMake requirement to version 3.1.
- [njlr](https://github.com/njlr) updated the Buckaroo instructions.
- [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS.
- [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function.
- [past-due](https://github.com/past-due) suppressed an unfixable warning.
- [Elvis Oric](https://github.com/elvisoric) improved Meson support.
- [Matěj Plch](https://github.com/Afforix) fixed an example in the README.
- [Mark Beckwith](https://github.com/wythe) fixed a typo.
- [scinart](https://github.com/scinart) fixed bug in the serializer.
- [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers.
- [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda.
- [Michele Caini](https://github.com/skypjack) fixed links in the README.
- [Hani](https://github.com/hnkb) documented how to install the library with NuGet.
- [Mark Beckwith](https://github.com/wythe) fixed a typo.
- [yann-morin-1998](https://github.com/yann-morin-1998) helped reducing the CMake requirement to version 3.1.
- [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro.
- [remyabel](https://github.com/remyabel) added GNUInstallDirs to the CMake files.
- [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test.
- [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method.
- [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning.
- [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/onqtam/doctest)
- [Juncheng E](https://github.com/ejcjason) fixed a typo.
- [tete17](https://github.com/tete17) fixed a bug in the `contains` function.
- [Xav83](https://github.com/Xav83) fixed some cppcheck warnings.
- [0xflotus](https://github.com/0xflotus) fixed some typos.
- [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`.
- [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types.
- [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly.
- [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos.
- [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`.
- [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization.
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.
@ -1241,18 +1298,23 @@ The library itself consists of a single header file licensed under the MIT licen
- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file - [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file
- [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing - [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows - [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code identation - [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation
- [**Catch**](https://github.com/philsquared/Catch) for the unit tests - [**CircleCI**](http://circleci.com) for [continuous integration](https://circleci.com/gh/nlohmann/json).
- [**Clang**](http://clang.llvm.org) for compilation with code sanitizers - [**Clang**](http://clang.llvm.org) for compilation with code sanitizers
- [**CMake**](https://cmake.org) for build automation - [**CMake**](https://cmake.org) for build automation
- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) - [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) - [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) - [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis - [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis
- [**doctest**](https://github.com/onqtam/doctest) for the unit tests
- [**Doozer**](https://doozer.io) for [continuous integration](https://doozer.io/nlohmann/json) on Linux (CentOS, Raspbian, Fedora)
- [**Doxygen**](http://www.stack.nl/~dimitri/doxygen/) to generate [documentation](https://nlohmann.github.io/json/) - [**Doxygen**](http://www.stack.nl/~dimitri/doxygen/) to generate [documentation](https://nlohmann.github.io/json/)
- [**fastcov**](https://github.com/RPGillespie6/fastcov) to process coverage information
- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages - [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages
- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) - [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks - [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks
- [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros
- [**lcov**](http://ltp.sourceforge.net/coverage/lcov.php) to process coverage information and create a HTML view
- [**libFuzzer**](http://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz - [**libFuzzer**](http://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) - [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json))
- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. - [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.
@ -1269,18 +1331,47 @@ The library is currently used in Apple macOS Sierra and iOS 10. I am not sure wh
## Notes ## 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). ### Character encoding
- As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc7159.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 library supports **Unicode input** as follows:
- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](https://tools.ietf.org/html/rfc7159.html#section-8.1).
- Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse or serialization errors.
- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
- 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 an `abort()` call.
- 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/rfc7159.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)).
The library supports **Unicode input** as follows:
- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1).
- `std::u16string` and `std::u32string` can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers.
- Other encodings such as Latin-1 or ISO 8859-1 are **not** supported and will yield parse or serialization errors.
- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
### Comments in JSON
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).
### 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)).
### 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).
- As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.
- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
## Execute unit tests ## Execute unit tests

View file

@ -3,6 +3,35 @@ version: '{build}'
environment: environment:
matrix: matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Debug
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Debug
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Debug
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Debug
platform: x64
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Debug
COMPILER: mingw COMPILER: mingw
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
@ -10,57 +39,88 @@ environment:
GENERATOR: Ninja GENERATOR: Ninja
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
COMPILER: mingw
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Ninja
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x86 platform: x86
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
GENERATOR: Visual Studio 14 2015 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x86 platform: x86
name: with_win_header
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x86 platform: x86
CXX_FLAGS: "/permissive- /std:c++latest /utf-8" CXX_FLAGS: "/permissive- /std:c++latest /utf-8"
LINKER_FLAGS: "" LINKER_FLAGS: ""
GENERATOR: Visual Studio 15 2017 GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Release
platform: x86
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
configuration: Release
platform: x64 platform: x64
CXX_FLAGS: "" CXX_FLAGS: ""
LINKER_FLAGS: "" LINKER_FLAGS: ""
GENERATOR: Visual Studio 14 2015 Win64 GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
platform: x64
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 15 2017 Win64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
configuration: Release
platform: x64 platform: x64
CXX_FLAGS: "/permissive- /std:c++latest /utf-8 /F4000000" CXX_FLAGS: "/permissive- /std:c++latest /utf-8 /F4000000"
LINKER_FLAGS: "/STACK:4000000" LINKER_FLAGS: "/STACK:4000000"
GENERATOR: Visual Studio 15 2017 Win64 GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
configuration: Release
platform: x64
CXX_FLAGS: ""
LINKER_FLAGS: ""
GENERATOR: Visual Studio 16 2019
init: init:
- cmake --version - cmake --version
- msbuild /version - msbuild /version
install: install:
- if "%COMPILER%"=="mingw" appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip - if "%COMPILER%"=="mingw" appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip
- if "%COMPILER%"=="mingw" 7z x ninja.zip -oC:\projects\deps\ninja > nul - if "%COMPILER%"=="mingw" 7z x ninja.zip -oC:\projects\deps\ninja > nul
- if "%COMPILER%"=="mingw" set PATH=C:\projects\deps\ninja;%PATH% - if "%COMPILER%"=="mingw" set PATH=C:\projects\deps\ninja;%PATH%
- if "%COMPILER%"=="mingw" set PATH=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH% - if "%COMPILER%"=="mingw" set PATH=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH%
- if "%COMPILER%"=="mingw" g++ --version - if "%COMPILER%"=="mingw" g++ --version
- if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32
before_build: before_build:
- cmake . -G "%GENERATOR%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_EXE_LINKER_FLAGS="%LINKER_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" # for with_win_header build, inject the inclusion of Windows.h to the single-header library
- ps: if ($env:name -Eq "with_win_header") { $header_path = "single_include\nlohmann\json.hpp" }
- ps: if ($env:name -Eq "with_win_header") { "#include <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") 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")
build_script: build_script:
- cmake --build . --config Release - cmake --build . --config "%configuration%"
test_script: test_script:
- ctest -C Release -V -j - if "%configuration%"=="Release" ctest -C "%configuration%" -V -j
# On Debug builds, skip test-unicode_all
# as it is extremely slow to run and cause
# occasional timeouts on AppVeyor.
# More info: https://github.com/nlohmann/json/pull/1570
- if "%configuration%"=="Debug" ctest --exclude-regex "test-unicode_all" -C "%configuration%" -V -j

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.8)
project(JSON_Benchmarks LANGUAGES CXX) project(JSON_Benchmarks LANGUAGES CXX)
# set compiler flags # set compiler flags

View file

@ -1,11 +1,11 @@
# Doxyfile 1.8.15 # Doxyfile 1.8.16
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Project related configuration options # Project related configuration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "JSON for Modern C++" PROJECT_NAME = "JSON for Modern C++"
PROJECT_NUMBER = 3.5.0 PROJECT_NUMBER = 3.7.1
PROJECT_BRIEF = PROJECT_BRIEF =
PROJECT_LOGO = PROJECT_LOGO =
OUTPUT_DIRECTORY = . OUTPUT_DIRECTORY = .
@ -38,6 +38,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING = EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0 TOC_INCLUDE_HEADINGS = 0
@ -141,7 +142,7 @@ USE_HTAGS = NO
VERBATIM_HEADERS = NO VERBATIM_HEADERS = NO
CLANG_ASSISTED_PARSING = YES CLANG_ASSISTED_PARSING = YES
CLANG_OPTIONS = -std=c++11 CLANG_OPTIONS = -std=c++11
CLANG_COMPILATION_DATABASE_PATH = 0 CLANG_DATABASE_PATH =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index # Configuration options related to the alphabetical class index
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -214,6 +215,7 @@ GENERATE_LATEX = NO
LATEX_OUTPUT = latex LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = \makeindex
COMPACT_LATEX = NO COMPACT_LATEX = NO
PAPER_TYPE = a4 PAPER_TYPE = a4
EXTRA_PACKAGES = EXTRA_PACKAGES =
@ -228,6 +230,7 @@ LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO LATEX_TIMESTAMP = NO
LATEX_EMOJI_DIRECTORY =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the RTF output # Configuration options related to the RTF output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -252,6 +255,7 @@ MAN_LINKS = NO
GENERATE_XML = YES GENERATE_XML = YES
XML_OUTPUT = xml XML_OUTPUT = xml
XML_PROGRAMLISTING = YES XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output # Configuration options related to the DOCBOOK output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------

View file

@ -61,6 +61,8 @@ doxygen: create_output create_links
$(SED) -i 's@template&lt;template&lt; typename U, typename V, typename... Args &gt; class ObjectType = std::map, template&lt; typename U, typename... Args &gt; class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, template&lt; typename U &gt; class AllocatorType = std::allocator, template&lt; typename T, typename SFINAE=void &gt; class JSONSerializer = adl_serializer&gt;@@g' html/*.html $(SED) -i 's@template&lt;template&lt; typename U, typename V, typename... Args &gt; class ObjectType = std::map, template&lt; typename U, typename... Args &gt; class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, template&lt; typename U &gt; class AllocatorType = std::allocator, template&lt; typename T, typename SFINAE=void &gt; class JSONSerializer = adl_serializer&gt;@@g' html/*.html
$(SED) -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer &gt;@@g' html/*.html $(SED) -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer &gt;@@g' html/*.html
$(SED) -i 's@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberUnsignedType,&#160;NumberFloatType,&#160;AllocatorType,&#160;JSONSerializer&#160;&gt;@@g' html/*.html $(SED) -i 's@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberUnsignedType,&#160;NumberFloatType,&#160;AllocatorType,&#160;JSONSerializer&#160;&gt;@@g' html/*.html
$(SED) -i 's@JSON_HEDLEY_RETURNS_NON_NULL@@g' html/*.html
$(SED) -i 's@JSON_HEDLEY_WARN_UNUSED_RESULT@@g' html/*.html
upload: clean doxygen check_output upload: clean doxygen check_output
scripts/git-update-ghpages nlohmann/json html scripts/git-update-ghpages nlohmann/json html

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 KiB

After

Width:  |  Height:  |  Size: 1 MiB

View file

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

17
doc/examples/contains.cpp Normal file
View file

@ -0,0 +1,17 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create some JSON values
json j_object = R"( {"key": "value"} )"_json;
json j_array = R"( [1, 2, 3] )"_json;
// call contains
std::cout << std::boolalpha <<
"j_object contains 'key': " << j_object.contains("key") << '\n' <<
"j_object contains 'another': " << j_object.contains("another") << '\n' <<
"j_array contains 'key': " << j_array.contains("key") << std::endl;
}

View file

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

View file

@ -0,0 +1,3 @@
j_object contains 'key': true
j_object contains 'another': false
j_array contains 'key': false

View file

@ -0,0 +1,45 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON value
json j =
{
{"number", 1}, {"string", "foo"}, {"array", {1, 2}}
};
std::cout << std::boolalpha
<< j.contains("/number"_json_pointer) << '\n'
<< j.contains("/string"_json_pointer) << '\n'
<< j.contains("/string"_json_pointer) << '\n'
<< j.contains("/array"_json_pointer) << '\n'
<< j.contains("/array/1"_json_pointer) << '\n'
<< j.contains("/array/-"_json_pointer) << '\n'
<< j.contains("/array/4"_json_pointer) << '\n'
<< j.contains("/baz"_json_pointer) << std::endl;
// out_of_range.106
try
{
// try to use an array index with leading '0'
j.contains("/array/01"_json_pointer);
}
catch (json::parse_error& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.109
try
{
// try to use an array index that is not a number
j.contains("/array/one"_json_pointer);
}
catch (json::parse_error& e)
{
std::cout << e.what() << '\n';
}
}

View file

@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/3TJ79OzHP4vmN1Nb"><b>online</b></a>

View file

@ -0,0 +1,10 @@
true
true
true
true
true
false
false
false
[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'
[json.exception.parse_error.109] parse error: array index 'one' is not a number

View file

@ -0,0 +1,15 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// different JSON Pointers
json::json_pointer ptr1("/foo");
json::json_pointer ptr2("/foo/0");
// call empty()
std::cout << "last reference token of " << ptr1 << " is " << ptr1.back() << '\n'
<< "last reference token of " << ptr2 << " is " << ptr2.back() << std::endl;
}

View file

@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/2q7gu0ZAQoMeOaAc"><b>online</b></a>

View file

@ -0,0 +1,2 @@
last reference token of "/foo" is foo
last reference token of "/foo/0" is 0

View file

@ -0,0 +1,20 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// different JSON Pointers
json::json_pointer ptr0;
json::json_pointer ptr1("");
json::json_pointer ptr2("/foo");
json::json_pointer ptr3("/foo/0");
// call empty()
std::cout << std::boolalpha
<< ptr0 << ": " << ptr0.empty() << '\n'
<< ptr1 << ": " << ptr1.empty() << '\n'
<< ptr2 << ": " << ptr2.empty() << '\n'
<< ptr3 << ": " << ptr3.empty() << std::endl;
}

View file

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

View file

@ -0,0 +1,4 @@
"": true
"": true
"/foo": false
"/foo/0": false

View file

@ -0,0 +1,23 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON pointer
json::json_pointer ptr("/foo");
std::cout << ptr << '\n';
// append a JSON Pointer
ptr /= json::json_pointer("/bar/baz");
std::cout << ptr << '\n';
// append a string
ptr /= "fob";
std::cout << ptr << '\n';
// append an array index
ptr /= 42;
std::cout << ptr << std::endl;
}

View file

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

View file

@ -0,0 +1,4 @@
"/foo"
"/foo/bar/baz"
"/foo/bar/baz/fob"
"/foo/bar/baz/fob/42"

View file

@ -0,0 +1,19 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON pointer
json::json_pointer ptr("/foo");
// append a JSON Pointer
std::cout << ptr / json::json_pointer("/bar/baz") << '\n';
// append a string
std::cout << ptr / "fob" << '\n';
// append an array index
std::cout << ptr / 42 << std::endl;
}

View file

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

View file

@ -0,0 +1,3 @@
"/foo/bar/baz"
"/foo/fob"
"/foo/42"

View file

@ -0,0 +1,18 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// different JSON Pointers
json::json_pointer ptr1("");
json::json_pointer ptr2("/foo");
json::json_pointer ptr3("/foo/0");
// call parent_pointer()
std::cout << std::boolalpha
<< "parent of " << ptr1 << " is " << ptr1.parent_pointer() << '\n'
<< "parent of " << ptr2 << " is " << ptr2.parent_pointer() << '\n'
<< "parent of " << ptr3 << " is " << ptr3.parent_pointer() << std::endl;
}

View file

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

View file

@ -0,0 +1,3 @@
parent of "" is ""
parent of "/foo" is ""
parent of "/foo/0" is "/foo"

View file

@ -0,0 +1,21 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create empty JSON Pointer
json::json_pointer ptr("/foo/bar/baz");
std::cout << ptr << '\n';
// call pop_back()
ptr.pop_back();
std::cout << ptr << '\n';
ptr.pop_back();
std::cout << ptr << '\n';
ptr.pop_back();
std::cout << ptr << '\n';
}

View file

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

View file

@ -0,0 +1,4 @@
"/foo/bar/baz"
"/foo/bar"
"/foo"
""

View file

@ -0,0 +1,21 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create empty JSON Pointer
json::json_pointer ptr;
std::cout << ptr << '\n';
// call push_back()
ptr.push_back("foo");
std::cout << ptr << '\n';
ptr.push_back("0");
std::cout << ptr << '\n';
ptr.push_back("bar");
std::cout << ptr << '\n';
}

View file

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

View file

@ -0,0 +1,4 @@
""
"/foo"
"/foo/0"
"/foo/0/bar"

View file

@ -2,7 +2,7 @@
"compiler": { "compiler": {
"c++": "201103", "c++": "201103",
"family": "clang", "family": "clang",
"version": "10.0.0 (clang-1000.11.45.5)" "version": "11.0.0 (clang-1100.0.33.8)"
}, },
"copyright": "(C) 2013-2017 Niels Lohmann", "copyright": "(C) 2013-2017 Niels Lohmann",
"name": "JSON for Modern C++", "name": "JSON for Modern C++",
@ -10,8 +10,8 @@
"url": "https://github.com/nlohmann/json", "url": "https://github.com/nlohmann/json",
"version": { "version": {
"major": 3, "major": 3,
"minor": 5, "minor": 7,
"patch": 0, "patch": 1,
"string": "3.5.0" "string": "3.7.1"
} }
} }

View file

@ -4,7 +4,9 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
# Contents # Contents
- @link nlohmann::basic_json `basic_json` class @endlink - Classes
- @link nlohmann::basic_json `basic_json`@endlink -- class template for JSON values
- @link nlohmann::json `json`@endlink -- the default specialization of `basic_json`, defined as `basic_json<>`
- [Functions](functions_func.html) - [Functions](functions_func.html)
- object inspection - object inspection
- @link nlohmann::basic_json::dump dump @endlink -- value serialization - @link nlohmann::basic_json::dump dump @endlink -- value serialization
@ -35,6 +37,12 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
- @link nlohmann::basic_json::out_of_range out_of_range @endlink for exceptions indicating access out of the defined range - @link nlohmann::basic_json::out_of_range out_of_range @endlink for exceptions indicating access out of the defined range
- @link nlohmann::basic_json::other_error other_error @endlink for exceptions indicating other library errors - @link nlohmann::basic_json::other_error other_error @endlink for exceptions indicating other library errors
- lexicographical comparison operators - lexicographical comparison operators
- @link nlohmann::basic_json::operator== operator== @endlink
- @link nlohmann::basic_json::operator!= operator!= @endlink
- @link nlohmann::basic_json::operator< operator<= @endlink
- @link nlohmann::basic_json::operator<= operator< @endlink
- @link nlohmann::basic_json::operator> operator> @endlink
- @link nlohmann::basic_json::operator>= operator>= @endlink
- serialization - serialization
- @link nlohmann::basic_json::dump dump @endlink serialize to string - @link nlohmann::basic_json::dump dump @endlink serialize to string
- @link nlohmann::basic_json::operator<<(std::ostream&, const basic_json &) operator<< @endlink serialize to stream - @link nlohmann::basic_json::operator<<(std::ostream&, const basic_json &) operator<< @endlink serialize to stream
@ -44,10 +52,12 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
- @link nlohmann::basic_json::operator>>(std::istream&, basic_json&) operator>> @endlink parse from stream - @link nlohmann::basic_json::operator>>(std::istream&, basic_json&) operator>> @endlink parse from stream
- @link nlohmann::basic_json::accept accept @endlink check for syntax errors without parsing - @link nlohmann::basic_json::accept accept @endlink check for syntax errors without parsing
- @link nlohmann::json_sax SAX interface @endlink define a user-defined SAX event consumer - @link nlohmann::json_sax SAX interface @endlink define a user-defined SAX event consumer
- @link nlohmann::basic_json::parser_callback_t callback interface @endlink register a callback to the parse function
- [binary formats](binary_formats.md): - [binary formats](binary_formats.md):
- CBOR: @link nlohmann::basic_json::from_cbor from_cbor @endlink / @link nlohmann::basic_json::to_cbor to_cbor @endlink - CBOR: @link nlohmann::basic_json::from_cbor from_cbor @endlink / @link nlohmann::basic_json::to_cbor to_cbor @endlink
- MessagePack: @link nlohmann::basic_json::from_msgpack from_msgpack @endlink / @link nlohmann::basic_json::to_msgpack to_msgpack @endlink - MessagePack: @link nlohmann::basic_json::from_msgpack from_msgpack @endlink / @link nlohmann::basic_json::to_msgpack to_msgpack @endlink
- UBJSON: @link nlohmann::basic_json::from_ubjson from_ubjson @endlink / @link nlohmann::basic_json::to_ubjson to_ubjson @endlink - UBJSON: @link nlohmann::basic_json::from_ubjson from_ubjson @endlink / @link nlohmann::basic_json::to_ubjson to_ubjson @endlink
- BSON: @link nlohmann::basic_json::from_bson from_bson @endlink / @link nlohmann::basic_json::to_bson to_bson @endlink
- Types - Types
- @link nlohmann::basic_json::array_t arrays @endlink - @link nlohmann::basic_json::array_t arrays @endlink
- @link nlohmann::basic_json::object_t objects @endlink - @link nlohmann::basic_json::object_t objects @endlink
@ -57,6 +67,10 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
- @link nlohmann::basic_json::number_integer_t signed integers @endlink - @link nlohmann::basic_json::number_integer_t signed integers @endlink
- @link nlohmann::basic_json::number_unsigned_t unsigned integers @endlink - @link nlohmann::basic_json::number_unsigned_t unsigned integers @endlink
- @link nlohmann::basic_json::number_float_t floating-point @endlink - @link nlohmann::basic_json::number_float_t floating-point @endlink
- further JSON standards
- @link nlohmann::json_pointer JSON Pointer @endlink (REF 6901)
- @link nlohmann::basic_json::patch JSON Patch @endlink (RFC 6902)
- @link nlohmann::basic_json::merge_patch JSON Merge Patch @endlink (RFC 7396)
# Container function overview # Container function overview
@ -281,7 +295,7 @@ Note that this table only lists those exceptions thrown due to the type. For ins
<td class="ok_green">@link nlohmann::basic_json::swap `swap` @endlink</td> <td class="ok_green">@link nlohmann::basic_json::swap `swap` @endlink</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">lookup</td> <td rowspan="3">lookup</td>
<td>`find`</td> <td>`find`</td>
<td class="ok_green">@link nlohmann::basic_json::find `find` @endlink</td> <td class="ok_green">@link nlohmann::basic_json::find `find` @endlink</td>
<td class="ok_green">@link nlohmann::basic_json::find `find` @endlink (returns `end()`)</td> <td class="ok_green">@link nlohmann::basic_json::find `find` @endlink (returns `end()`)</td>
@ -299,11 +313,20 @@ Note that this table only lists those exceptions thrown due to the type. For ins
<td class="ok_green">@link nlohmann::basic_json::count `count` @endlink (returns `0`)</td> <td class="ok_green">@link nlohmann::basic_json::count `count` @endlink (returns `0`)</td>
<td class="ok_green">@link nlohmann::basic_json::count `count` @endlink (returns `0`)</td> <td class="ok_green">@link nlohmann::basic_json::count `count` @endlink (returns `0`)</td>
</tr> </tr>
<tr>
<td>`contains`</td>
<td class="ok_green">@link nlohmann::basic_json::contains `contains` @endlink</td>
<td class="ok_green">@link nlohmann::basic_json::contains `contains` @endlink (returns `false`)</td>
<td class="ok_green">@link nlohmann::basic_json::contains `contains` @endlink (returns `false`)</td>
<td class="ok_green">@link nlohmann::basic_json::contains `contains` @endlink (returns `false`)</td>
<td class="ok_green">@link nlohmann::basic_json::contains `contains` @endlink (returns `false`)</td>
<td class="ok_green">@link nlohmann::basic_json::contains `contains` @endlink (returns `false`)</td>
</tr>
</table> </table>
@copyright Copyright &copy; 2013-2018 Niels Lohmann. The code is licensed under the [MIT License](http://opensource.org/licenses/MIT). @copyright Copyright &copy; 2013-2019 Niels Lohmann. The code is licensed under the [MIT License](http://opensource.org/licenses/MIT).
@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.5.0 @version 3.7.1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -26,7 +26,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_UNLIKELY(not j.is_null())) if (JSON_HEDLEY_UNLIKELY(not 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())));
} }
@ -66,7 +66,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_UNLIKELY(not j.is_boolean())) if (JSON_HEDLEY_UNLIKELY(not 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 +76,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_UNLIKELY(not j.is_string())) if (JSON_HEDLEY_UNLIKELY(not 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())));
} }
@ -92,7 +92,7 @@ template <
int > = 0 > int > = 0 >
void from_json(const BasicJsonType& j, ConstructibleStringType& s) void from_json(const BasicJsonType& j, ConstructibleStringType& s)
{ {
if (JSON_UNLIKELY(not j.is_string())) if (JSON_HEDLEY_UNLIKELY(not 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())));
} }
@ -132,10 +132,11 @@ template<typename BasicJsonType, typename T, typename Allocator,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_convertible<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_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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.clear();
std::transform(j.rbegin(), j.rend(), std::transform(j.rbegin(), j.rend(),
std::front_inserter(l), [](const BasicJsonType & i) std::front_inserter(l), [](const BasicJsonType & i)
{ {
@ -148,12 +149,22 @@ template<typename BasicJsonType, typename T,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_convertible<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_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); std::copy(j.begin(), j.end(), std::begin(l));
}
template <typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N])
-> decltype(j.template get<T>(), void())
{
for (std::size_t i = 0; i < N; ++i)
{
arr[i] = j.at(i).template get<T>();
}
} }
template<typename BasicJsonType> template<typename BasicJsonType>
@ -182,14 +193,16 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
{ {
using std::end; using std::end;
arr.reserve(j.size()); ConstructibleArrayType ret;
ret.reserve(j.size());
std::transform(j.begin(), j.end(), std::transform(j.begin(), j.end(),
std::inserter(arr, end(arr)), [](const BasicJsonType & i) std::inserter(ret, end(ret)), [](const BasicJsonType & i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json // get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename ConstructibleArrayType::value_type>(); return i.template get<typename ConstructibleArrayType::value_type>();
}); });
arr = std::move(ret);
} }
template <typename BasicJsonType, typename ConstructibleArrayType> template <typename BasicJsonType, typename ConstructibleArrayType>
@ -198,14 +211,16 @@ void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
{ {
using std::end; using std::end;
ConstructibleArrayType ret;
std::transform( std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)), j.begin(), j.end(), std::inserter(ret, end(ret)),
[](const BasicJsonType & i) [](const BasicJsonType & i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json // get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename ConstructibleArrayType::value_type>(); return i.template get<typename ConstructibleArrayType::value_type>();
}); });
arr = std::move(ret);
} }
template <typename BasicJsonType, typename ConstructibleArrayType, template <typename BasicJsonType, typename ConstructibleArrayType,
@ -221,7 +236,7 @@ auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
j.template get<typename ConstructibleArrayType::value_type>(), j.template get<typename ConstructibleArrayType::value_type>(),
void()) void())
{ {
if (JSON_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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())));
@ -234,20 +249,22 @@ 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_UNLIKELY(not j.is_object())) if (JSON_HEDLEY_UNLIKELY(not 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())));
} }
ConstructibleObjectType ret;
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>(); auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
using value_type = typename ConstructibleObjectType::value_type; using value_type = typename ConstructibleObjectType::value_type;
std::transform( std::transform(
inner_object->begin(), inner_object->end(), inner_object->begin(), inner_object->end(),
std::inserter(obj, obj.begin()), std::inserter(ret, ret.begin()),
[](typename BasicJsonType::object_t::value_type const & p) [](typename BasicJsonType::object_t::value_type const & p)
{ {
return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>()); return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
}); });
obj = std::move(ret);
} }
// overload for arithmetic types, not chosen for basic_json template arguments // overload for arithmetic types, not chosen for basic_json template arguments
@ -315,13 +332,14 @@ template <typename BasicJsonType, typename Key, typename Value, typename Compare
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_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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();
for (const auto& p : j) for (const auto& p : j)
{ {
if (JSON_UNLIKELY(not p.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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())));
} }
@ -334,13 +352,14 @@ template <typename BasicJsonType, typename Key, typename Value, typename Hash, t
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_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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();
for (const auto& p : j) for (const auto& p : j)
{ {
if (JSON_UNLIKELY(not p.is_array())) if (JSON_HEDLEY_UNLIKELY(not 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())));
} }
@ -367,4 +386,4 @@ namespace
{ {
constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value; constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
} // namespace } // namespace
} // namespace nlohmann } // namespace nlohmann

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <ciso646> // or, and, not #include <ciso646> // or, and, not
#include <cmath> // signbit, isfinite #include <cmath> // signbit, isfinite
@ -7,6 +8,7 @@
#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/macro_scope.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -49,10 +51,10 @@ struct diyfp // f * 2^e
{ {
static constexpr int kPrecision = 64; // = q static constexpr int kPrecision = 64; // = q
uint64_t f = 0; std::uint64_t f = 0;
int e = 0; int e = 0;
constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
/*! /*!
@brief returns x - y @brief returns x - y
@ -97,23 +99,23 @@ struct diyfp // f * 2^e
// //
// = p_lo + 2^64 p_hi // = p_lo + 2^64 p_hi
const uint64_t u_lo = x.f & 0xFFFFFFFF; const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
const uint64_t u_hi = x.f >> 32; const std::uint64_t u_hi = x.f >> 32u;
const uint64_t v_lo = y.f & 0xFFFFFFFF; const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
const uint64_t v_hi = y.f >> 32; const std::uint64_t v_hi = y.f >> 32u;
const uint64_t p0 = u_lo * v_lo; const std::uint64_t p0 = u_lo * v_lo;
const uint64_t p1 = u_lo * v_hi; const std::uint64_t p1 = u_lo * v_hi;
const uint64_t p2 = u_hi * v_lo; const std::uint64_t p2 = u_hi * v_lo;
const uint64_t p3 = u_hi * v_hi; const std::uint64_t p3 = u_hi * v_hi;
const uint64_t p0_hi = p0 >> 32; const std::uint64_t p0_hi = p0 >> 32u;
const uint64_t p1_lo = p1 & 0xFFFFFFFF; const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
const uint64_t p1_hi = p1 >> 32; const std::uint64_t p1_hi = p1 >> 32u;
const uint64_t p2_lo = p2 & 0xFFFFFFFF; const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
const uint64_t p2_hi = p2 >> 32; const std::uint64_t p2_hi = p2 >> 32u;
uint64_t Q = p0_hi + p1_lo + p2_lo; std::uint64_t Q = p0_hi + p1_lo + p2_lo;
// The full product might now be computed as // The full product might now be computed as
// //
@ -124,9 +126,9 @@ struct diyfp // f * 2^e
// Effectively we only need to add the highest bit in p_lo to p_hi (and // Effectively we only need to add the highest bit in p_lo to p_hi (and
// Q_hi + 1 does not overflow). // Q_hi + 1 does not overflow).
Q += uint64_t{1} << (64 - 32 - 1); // round, ties up Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
return {h, x.e + y.e + 64}; return {h, x.e + y.e + 64};
} }
@ -139,9 +141,9 @@ struct diyfp // f * 2^e
{ {
assert(x.f != 0); assert(x.f != 0);
while ((x.f >> 63) == 0) while ((x.f >> 63u) == 0)
{ {
x.f <<= 1; x.f <<= 1u;
x.e--; x.e--;
} }
@ -195,15 +197,15 @@ boundaries compute_boundaries(FloatType value)
constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit) constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1); constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
constexpr int kMinExp = 1 - kBias; constexpr int kMinExp = 1 - kBias;
constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1) constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type; using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
const uint64_t bits = reinterpret_bits<bits_type>(value); const std::uint64_t bits = reinterpret_bits<bits_type>(value);
const uint64_t E = bits >> (kPrecision - 1); const std::uint64_t E = bits >> (kPrecision - 1);
const uint64_t F = bits & (kHiddenBit - 1); const std::uint64_t F = bits & (kHiddenBit - 1);
const bool is_denormal = (E == 0); const bool is_denormal = E == 0;
const diyfp v = is_denormal const diyfp v = is_denormal
? diyfp(F, kMinExp) ? diyfp(F, kMinExp)
: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias); : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
@ -229,7 +231,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 and 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)
@ -304,7 +306,7 @@ constexpr int kGamma = -32;
struct cached_power // c = f * 2^e ~= 10^k struct cached_power // c = f * 2^e ~= 10^k
{ {
uint64_t f; std::uint64_t f;
int e; int e;
int k; int k;
}; };
@ -328,7 +330,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
// ==> 2^(q - 1 + alpha) <= c * 2^(e + q) // ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
// ==> 2^(alpha - e - 1) <= c // ==> 2^(alpha - e - 1) <= c
// //
// If c were an exakt power of ten, i.e. c = 10^k, one may determine k as // If c were an exact power of ten, i.e. c = 10^k, one may determine k as
// //
// k = ceil( log_10( 2^(alpha - e - 1) ) ) // k = ceil( log_10( 2^(alpha - e - 1) ) )
// = ceil( (alpha - e - 1) * log_10(2) ) // = ceil( (alpha - e - 1) * log_10(2) )
@ -368,91 +370,92 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
// NB: // NB:
// Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
constexpr int kCachedPowersSize = 79;
constexpr int kCachedPowersMinDecExp = -300; constexpr int kCachedPowersMinDecExp = -300;
constexpr int kCachedPowersDecStep = 8; constexpr int kCachedPowersDecStep = 8;
static constexpr cached_power kCachedPowers[] = static constexpr std::array<cached_power, 79> kCachedPowers =
{ {
{ 0xAB70FE17C79AC6CA, -1060, -300 }, {
{ 0xFF77B1FCBEBCDC4F, -1034, -292 }, { 0xAB70FE17C79AC6CA, -1060, -300 },
{ 0xBE5691EF416BD60C, -1007, -284 }, { 0xFF77B1FCBEBCDC4F, -1034, -292 },
{ 0x8DD01FAD907FFC3C, -980, -276 }, { 0xBE5691EF416BD60C, -1007, -284 },
{ 0xD3515C2831559A83, -954, -268 }, { 0x8DD01FAD907FFC3C, -980, -276 },
{ 0x9D71AC8FADA6C9B5, -927, -260 }, { 0xD3515C2831559A83, -954, -268 },
{ 0xEA9C227723EE8BCB, -901, -252 }, { 0x9D71AC8FADA6C9B5, -927, -260 },
{ 0xAECC49914078536D, -874, -244 }, { 0xEA9C227723EE8BCB, -901, -252 },
{ 0x823C12795DB6CE57, -847, -236 }, { 0xAECC49914078536D, -874, -244 },
{ 0xC21094364DFB5637, -821, -228 }, { 0x823C12795DB6CE57, -847, -236 },
{ 0x9096EA6F3848984F, -794, -220 }, { 0xC21094364DFB5637, -821, -228 },
{ 0xD77485CB25823AC7, -768, -212 }, { 0x9096EA6F3848984F, -794, -220 },
{ 0xA086CFCD97BF97F4, -741, -204 }, { 0xD77485CB25823AC7, -768, -212 },
{ 0xEF340A98172AACE5, -715, -196 }, { 0xA086CFCD97BF97F4, -741, -204 },
{ 0xB23867FB2A35B28E, -688, -188 }, { 0xEF340A98172AACE5, -715, -196 },
{ 0x84C8D4DFD2C63F3B, -661, -180 }, { 0xB23867FB2A35B28E, -688, -188 },
{ 0xC5DD44271AD3CDBA, -635, -172 }, { 0x84C8D4DFD2C63F3B, -661, -180 },
{ 0x936B9FCEBB25C996, -608, -164 }, { 0xC5DD44271AD3CDBA, -635, -172 },
{ 0xDBAC6C247D62A584, -582, -156 }, { 0x936B9FCEBB25C996, -608, -164 },
{ 0xA3AB66580D5FDAF6, -555, -148 }, { 0xDBAC6C247D62A584, -582, -156 },
{ 0xF3E2F893DEC3F126, -529, -140 }, { 0xA3AB66580D5FDAF6, -555, -148 },
{ 0xB5B5ADA8AAFF80B8, -502, -132 }, { 0xF3E2F893DEC3F126, -529, -140 },
{ 0x87625F056C7C4A8B, -475, -124 }, { 0xB5B5ADA8AAFF80B8, -502, -132 },
{ 0xC9BCFF6034C13053, -449, -116 }, { 0x87625F056C7C4A8B, -475, -124 },
{ 0x964E858C91BA2655, -422, -108 }, { 0xC9BCFF6034C13053, -449, -116 },
{ 0xDFF9772470297EBD, -396, -100 }, { 0x964E858C91BA2655, -422, -108 },
{ 0xA6DFBD9FB8E5B88F, -369, -92 }, { 0xDFF9772470297EBD, -396, -100 },
{ 0xF8A95FCF88747D94, -343, -84 }, { 0xA6DFBD9FB8E5B88F, -369, -92 },
{ 0xB94470938FA89BCF, -316, -76 }, { 0xF8A95FCF88747D94, -343, -84 },
{ 0x8A08F0F8BF0F156B, -289, -68 }, { 0xB94470938FA89BCF, -316, -76 },
{ 0xCDB02555653131B6, -263, -60 }, { 0x8A08F0F8BF0F156B, -289, -68 },
{ 0x993FE2C6D07B7FAC, -236, -52 }, { 0xCDB02555653131B6, -263, -60 },
{ 0xE45C10C42A2B3B06, -210, -44 }, { 0x993FE2C6D07B7FAC, -236, -52 },
{ 0xAA242499697392D3, -183, -36 }, { 0xE45C10C42A2B3B06, -210, -44 },
{ 0xFD87B5F28300CA0E, -157, -28 }, { 0xAA242499697392D3, -183, -36 },
{ 0xBCE5086492111AEB, -130, -20 }, { 0xFD87B5F28300CA0E, -157, -28 },
{ 0x8CBCCC096F5088CC, -103, -12 }, { 0xBCE5086492111AEB, -130, -20 },
{ 0xD1B71758E219652C, -77, -4 }, { 0x8CBCCC096F5088CC, -103, -12 },
{ 0x9C40000000000000, -50, 4 }, { 0xD1B71758E219652C, -77, -4 },
{ 0xE8D4A51000000000, -24, 12 }, { 0x9C40000000000000, -50, 4 },
{ 0xAD78EBC5AC620000, 3, 20 }, { 0xE8D4A51000000000, -24, 12 },
{ 0x813F3978F8940984, 30, 28 }, { 0xAD78EBC5AC620000, 3, 20 },
{ 0xC097CE7BC90715B3, 56, 36 }, { 0x813F3978F8940984, 30, 28 },
{ 0x8F7E32CE7BEA5C70, 83, 44 }, { 0xC097CE7BC90715B3, 56, 36 },
{ 0xD5D238A4ABE98068, 109, 52 }, { 0x8F7E32CE7BEA5C70, 83, 44 },
{ 0x9F4F2726179A2245, 136, 60 }, { 0xD5D238A4ABE98068, 109, 52 },
{ 0xED63A231D4C4FB27, 162, 68 }, { 0x9F4F2726179A2245, 136, 60 },
{ 0xB0DE65388CC8ADA8, 189, 76 }, { 0xED63A231D4C4FB27, 162, 68 },
{ 0x83C7088E1AAB65DB, 216, 84 }, { 0xB0DE65388CC8ADA8, 189, 76 },
{ 0xC45D1DF942711D9A, 242, 92 }, { 0x83C7088E1AAB65DB, 216, 84 },
{ 0x924D692CA61BE758, 269, 100 }, { 0xC45D1DF942711D9A, 242, 92 },
{ 0xDA01EE641A708DEA, 295, 108 }, { 0x924D692CA61BE758, 269, 100 },
{ 0xA26DA3999AEF774A, 322, 116 }, { 0xDA01EE641A708DEA, 295, 108 },
{ 0xF209787BB47D6B85, 348, 124 }, { 0xA26DA3999AEF774A, 322, 116 },
{ 0xB454E4A179DD1877, 375, 132 }, { 0xF209787BB47D6B85, 348, 124 },
{ 0x865B86925B9BC5C2, 402, 140 }, { 0xB454E4A179DD1877, 375, 132 },
{ 0xC83553C5C8965D3D, 428, 148 }, { 0x865B86925B9BC5C2, 402, 140 },
{ 0x952AB45CFA97A0B3, 455, 156 }, { 0xC83553C5C8965D3D, 428, 148 },
{ 0xDE469FBD99A05FE3, 481, 164 }, { 0x952AB45CFA97A0B3, 455, 156 },
{ 0xA59BC234DB398C25, 508, 172 }, { 0xDE469FBD99A05FE3, 481, 164 },
{ 0xF6C69A72A3989F5C, 534, 180 }, { 0xA59BC234DB398C25, 508, 172 },
{ 0xB7DCBF5354E9BECE, 561, 188 }, { 0xF6C69A72A3989F5C, 534, 180 },
{ 0x88FCF317F22241E2, 588, 196 }, { 0xB7DCBF5354E9BECE, 561, 188 },
{ 0xCC20CE9BD35C78A5, 614, 204 }, { 0x88FCF317F22241E2, 588, 196 },
{ 0x98165AF37B2153DF, 641, 212 }, { 0xCC20CE9BD35C78A5, 614, 204 },
{ 0xE2A0B5DC971F303A, 667, 220 }, { 0x98165AF37B2153DF, 641, 212 },
{ 0xA8D9D1535CE3B396, 694, 228 }, { 0xE2A0B5DC971F303A, 667, 220 },
{ 0xFB9B7CD9A4A7443C, 720, 236 }, { 0xA8D9D1535CE3B396, 694, 228 },
{ 0xBB764C4CA7A44410, 747, 244 }, { 0xFB9B7CD9A4A7443C, 720, 236 },
{ 0x8BAB8EEFB6409C1A, 774, 252 }, { 0xBB764C4CA7A44410, 747, 244 },
{ 0xD01FEF10A657842C, 800, 260 }, { 0x8BAB8EEFB6409C1A, 774, 252 },
{ 0x9B10A4E5E9913129, 827, 268 }, { 0xD01FEF10A657842C, 800, 260 },
{ 0xE7109BFBA19C0C9D, 853, 276 }, { 0x9B10A4E5E9913129, 827, 268 },
{ 0xAC2820D9623BF429, 880, 284 }, { 0xE7109BFBA19C0C9D, 853, 276 },
{ 0x80444B5E7AA7CF85, 907, 292 }, { 0xAC2820D9623BF429, 880, 284 },
{ 0xBF21E44003ACDD2D, 933, 300 }, { 0x80444B5E7AA7CF85, 907, 292 },
{ 0x8E679C2F5E44FF8F, 960, 308 }, { 0xBF21E44003ACDD2D, 933, 300 },
{ 0xD433179D9C8CB841, 986, 316 }, { 0x8E679C2F5E44FF8F, 960, 308 },
{ 0x9E19DB92B4E31BA9, 1013, 324 }, { 0xD433179D9C8CB841, 986, 316 },
{ 0x9E19DB92B4E31BA9, 1013, 324 },
}
}; };
// This computation gives exactly the same results for k as // This computation gives exactly the same results for k as
@ -466,10 +469,9 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
assert(index >= 0); assert(index >= 0);
assert(index < kCachedPowersSize); assert(static_cast<std::size_t>(index) < kCachedPowers.size());
static_cast<void>(kCachedPowersSize); // Fix warning.
const cached_power cached = kCachedPowers[index]; const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
assert(kAlpha <= cached.e + e + 64); assert(kAlpha <= cached.e + e + 64);
assert(kGamma >= cached.e + e + 64); assert(kGamma >= cached.e + e + 64);
@ -480,7 +482,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
For n == 0, returns 1 and sets pow10 := 1. For n == 0, returns 1 and sets pow10 := 1.
*/ */
inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
if (n >= 1000000000) if (n >= 1000000000)
@ -536,8 +538,8 @@ inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
} }
} }
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
uint64_t rest, uint64_t ten_k) std::uint64_t rest, std::uint64_t ten_k)
{ {
assert(len >= 1); assert(len >= 1);
assert(dist <= delta); assert(dist <= delta);
@ -598,8 +600,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
assert(M_plus.e >= kAlpha); assert(M_plus.e >= kAlpha);
assert(M_plus.e <= kGamma); assert(M_plus.e <= kGamma);
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)
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)
// Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
// //
@ -608,10 +610,10 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = ((p1 ) * 2^-e + (p2 )) * 2^e // = ((p1 ) * 2^-e + (p2 )) * 2^e
// = p1 + p2 * 2^e // = p1 + p2 * 2^e
const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
auto p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e
// 1) // 1)
// //
@ -619,7 +621,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
assert(p1 > 0); assert(p1 > 0);
uint32_t pow10; std::uint32_t pow10;
const int k = find_largest_pow10(p1, pow10); const int k = find_largest_pow10(p1, pow10);
// 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
@ -647,8 +649,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k)
// pow10 = 10^(n-1) <= p1 < 10^n // pow10 = 10^(n-1) <= p1 < 10^n
// //
const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1)
const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1)
// //
// 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)
@ -673,7 +675,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// Note: // Note:
// Since rest and delta share the same exponent e, it suffices to // Since rest and delta share the same exponent e, it suffices to
// compare the significands. // compare the significands.
const uint64_t rest = (uint64_t{p1} << -one.e) + p2; const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
if (rest <= delta) if (rest <= delta)
{ {
// V = buffer * 10^n, with M- <= V <= M+. // V = buffer * 10^n, with M- <= V <= M+.
@ -689,7 +691,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
// 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
// //
const uint64_t ten_n = uint64_t{pow10} << -one.e; const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
grisu2_round(buffer, length, dist, delta, rest, ten_n); grisu2_round(buffer, length, dist, delta, rest, ten_n);
return; return;
@ -751,10 +753,10 @@ 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 <= UINT64_MAX / 10); assert(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
p2 *= 10; p2 *= 10;
const 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 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
// //
// M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
@ -794,7 +796,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
// 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
// //
const uint64_t ten_m = one.f; const std::uint64_t ten_m = one.f;
grisu2_round(buffer, length, dist, delta, p2, ten_m); grisu2_round(buffer, length, dist, delta, p2, ten_m);
// By construction this algorithm generates the shortest possible decimal // By construction this algorithm generates the shortest possible decimal
@ -817,6 +819,7 @@ v = buf * 10^decimal_exponent
len is the length of the buffer (number of decimal digits) len is the length of the buffer (number of decimal digits)
The buffer must be large enough, i.e. >= max_digits10. The buffer must be large enough, i.e. >= max_digits10.
*/ */
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)
{ {
@ -876,6 +879,7 @@ len is the length of the buffer (number of decimal digits)
The buffer must be large enough, i.e. >= max_digits10. The buffer must be large enough, i.e. >= max_digits10.
*/ */
template <typename FloatType> template <typename FloatType>
JSON_HEDLEY_NON_NULL(1)
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) 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,
@ -914,6 +918,8 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
@return a pointer to the element following the exponent. @return a pointer to the element following the exponent.
@pre -1000 < e < 1000 @pre -1000 < e < 1000
*/ */
JSON_HEDLEY_NON_NULL(1)
JSON_HEDLEY_RETURNS_NON_NULL
inline char* append_exponent(char* buf, int e) inline char* append_exponent(char* buf, int e)
{ {
assert(e > -1000); assert(e > -1000);
@ -929,7 +935,7 @@ inline char* append_exponent(char* buf, int e)
*buf++ = '+'; *buf++ = '+';
} }
auto k = static_cast<uint32_t>(e); auto k = static_cast<std::uint32_t>(e);
if (k < 10) if (k < 10)
{ {
// Always print at least two digits in the exponent. // Always print at least two digits in the exponent.
@ -964,6 +970,8 @@ notation. Otherwise it will be printed in exponential notation.
@pre min_exp < 0 @pre min_exp < 0
@pre max_exp > 0 @pre max_exp > 0
*/ */
JSON_HEDLEY_NON_NULL(1)
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)
{ {
@ -1047,6 +1055,8 @@ format. Returns an iterator pointing past-the-end of the decimal representation.
@note The result is NOT null-terminated. @note The result is NOT null-terminated.
*/ */
template <typename FloatType> template <typename FloatType>
JSON_HEDLEY_NON_NULL(1, 2)
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

View file

@ -1,17 +1,19 @@
#pragma once #pragma once
#include <algorithm> // copy
#include <ciso646> // or, and, not #include <ciso646> // or, and, not
#include <iterator> // begin, end #include <iterator> // begin, end
#include <string> // string
#include <tuple> // tuple, get #include <tuple> // tuple, get
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
#include <utility> // move, forward, declval, pair #include <utility> // move, forward, declval, pair
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
#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>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -152,7 +154,10 @@ struct external_constructor<value_t::array>
j.m_type = value_t::array; j.m_type = value_t::array;
j.m_value = value_t::array; j.m_value = value_t::array;
j.m_value.array->resize(arr.size()); j.m_value.array->resize(arr.size());
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); if (arr.size() > 0)
{
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
}
j.assert_invariant(); j.assert_invariant();
} }
}; };
@ -297,8 +302,8 @@ void to_json(BasicJsonType& j, const T(&arr)[N])
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
} }
template<typename BasicJsonType, typename... Args> template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
void to_json(BasicJsonType& j, const std::pair<Args...>& p) void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
{ {
j = { p.first, p.second }; j = { p.first, p.second };
} }
@ -317,10 +322,10 @@ void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>
j = { std::get<Idx>(t)... }; j = { std::get<Idx>(t)... };
} }
template<typename BasicJsonType, typename... Args> template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
void to_json(BasicJsonType& j, const std::tuple<Args...>& t) void to_json(BasicJsonType& j, const T& t)
{ {
to_json_tuple_impl(j, t, index_sequence_for<Args...> {}); to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
} }
struct to_json_fn struct to_json_fn
@ -339,4 +344,4 @@ namespace
{ {
constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value; constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
} // namespace } // namespace
} // namespace nlohmann } // namespace nlohmann

View file

@ -5,6 +5,7 @@
#include <string> // to_string #include <string> // to_string
#include <nlohmann/detail/input/position_t.hpp> #include <nlohmann/detail/input/position_t.hpp>
#include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -46,6 +47,7 @@ class exception : public std::exception
{ {
public: public:
/// returns the explanatory string /// returns the explanatory string
JSON_HEDLEY_RETURNS_NON_NULL
const char* what() const noexcept override const char* what() const noexcept override
{ {
return m.what(); return m.what();
@ -55,6 +57,7 @@ class exception : public std::exception
const int id; const int id;
protected: protected:
JSON_HEDLEY_NON_NULL(3)
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}
static std::string name(const std::string& ename, int id_) static std::string name(const std::string& ename, int id_)
@ -102,12 +105,12 @@ json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F
@liveexample{The following code shows how a `parse_error` exception can be @liveexample{The following code shows how a `parse_error` exception can be
caught.,parse_error} caught.,parse_error}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -117,7 +120,7 @@ class parse_error : public exception
/*! /*!
@brief create a parse error exception @brief create a parse error exception
@param[in] id_ the id of the exception @param[in] id_ the id of the exception
@param[in] position the position where the error occurred (or with @param[in] pos the position where the error occurred (or with
chars_read_total=0 if the position cannot be chars_read_total=0 if the position cannot be
determined) determined)
@param[in] what_arg the explanatory string @param[in] what_arg the explanatory string
@ -188,12 +191,12 @@ json.exception.invalid_iterator.214 | cannot get value | Cannot get value for it
@liveexample{The following code shows how an `invalid_iterator` exception can be @liveexample{The following code shows how an `invalid_iterator` exception can be
caught.,invalid_iterator} caught.,invalid_iterator}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -207,6 +210,7 @@ class invalid_iterator : public exception
} }
private: private:
JSON_HEDLEY_NON_NULL(3)
invalid_iterator(int id_, const char* what_arg) invalid_iterator(int id_, const char* what_arg)
: exception(id_, what_arg) {} : exception(id_, what_arg) {}
}; };
@ -223,7 +227,7 @@ name / id | example message | description
----------------------------- | --------------- | ------------------------- ----------------------------- | --------------- | -------------------------
json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &.
json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
@ -242,11 +246,11 @@ json.exception.type_error.317 | JSON value cannot be serialized to requested for
@liveexample{The following code shows how a `type_error` exception can be @liveexample{The following code shows how a `type_error` exception can be
caught.,type_error} caught.,type_error}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -260,6 +264,7 @@ class type_error : public exception
} }
private: private:
JSON_HEDLEY_NON_NULL(3)
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
}; };
@ -287,12 +292,12 @@ json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at
@liveexample{The following code shows how an `out_of_range` exception can be @liveexample{The following code shows how an `out_of_range` exception can be
caught.,out_of_range} caught.,out_of_range}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -306,6 +311,7 @@ class out_of_range : public exception
} }
private: private:
JSON_HEDLEY_NON_NULL(3)
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
}; };
@ -321,12 +327,12 @@ name / id | example message | description
------------------------------ | --------------- | ------------------------- ------------------------------ | --------------- | -------------------------
json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@liveexample{The following code shows how an `other_error` exception can be @liveexample{The following code shows how an `other_error` exception can be
caught.,other_error} caught.,other_error}
@ -343,6 +349,7 @@ class other_error : public exception
} }
private: private:
JSON_HEDLEY_NON_NULL(3)
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
}; };
} // namespace detail } // namespace detail

View file

@ -13,9 +13,9 @@
#include <string> // char_traits, string #include <string> // char_traits, string
#include <utility> // make_pair, move #include <utility> // make_pair, move
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/json_sax.hpp> #include <nlohmann/detail/input/json_sax.hpp>
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp> #include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
@ -52,6 +52,13 @@ class binary_reader
assert(ia); assert(ia);
} }
// make class move-only
binary_reader(const binary_reader&) = delete;
binary_reader(binary_reader&&) = default;
binary_reader& operator=(const binary_reader&) = delete;
binary_reader& operator=(binary_reader&&) = default;
~binary_reader() = default;
/*! /*!
@param[in] format the binary format to parse @param[in] format the binary format to parse
@param[in] sax_ a SAX event processor @param[in] sax_ a SAX event processor
@ -59,6 +66,7 @@ class binary_reader
@return @return
*/ */
JSON_HEDLEY_NON_NULL(3)
bool sax_parse(const input_format_t format, bool sax_parse(const input_format_t format,
json_sax_t* sax_, json_sax_t* sax_,
const bool strict = true) const bool strict = true)
@ -84,10 +92,8 @@ class binary_reader
result = parse_ubjson_internal(); result = parse_ubjson_internal();
break; break;
// LCOV_EXCL_START default: // LCOV_EXCL_LINE
default: assert(false); // LCOV_EXCL_LINE
assert(false);
// LCOV_EXCL_STOP
} }
// strict mode: next byte must be EOF // strict mode: next byte must be EOF
@ -102,7 +108,7 @@ class binary_reader
get(); get();
} }
if (JSON_UNLIKELY(current != std::char_traits<char>::eof())) if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char>::eof()))
{ {
return sax->parse_error(chars_read, get_token_string(), return sax->parse_error(chars_read, get_token_string(),
parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"))); parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
@ -121,7 +127,7 @@ class binary_reader
*/ */
static constexpr bool little_endianess(int num = 1) noexcept static constexpr bool little_endianess(int num = 1) noexcept
{ {
return (*reinterpret_cast<char*>(&num) == 1); return *reinterpret_cast<char*>(&num) == 1;
} }
private: private:
@ -138,12 +144,12 @@ class binary_reader
std::int32_t document_size; std::int32_t document_size;
get_number<std::int32_t, true>(input_format_t::bson, document_size); get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/false))) if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/false)))
{ {
return false; return false;
} }
@ -164,7 +170,7 @@ class binary_reader
while (true) while (true)
{ {
get(); get();
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring")))
{ {
return false; return false;
} }
@ -192,7 +198,7 @@ class binary_reader
template<typename NumberType> template<typename NumberType>
bool get_bson_string(const NumberType len, string_t& result) bool get_bson_string(const NumberType len, string_t& result)
{ {
if (JSON_UNLIKELY(len < 1)) if (JSON_HEDLEY_UNLIKELY(len < 1))
{ {
auto last_token = get_token_string(); auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"))); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string")));
@ -263,9 +269,9 @@ class binary_reader
default: // anything else not supported (yet) default: // anything else not supported (yet)
{ {
char cr[3]; std::array<char, 3> cr{{}};
(std::snprintf)(cr, sizeof(cr), "%.2hhX", static_cast<unsigned char>(element_type)); (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type));
return sax->parse_error(element_type_parse_position, std::string(cr), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr))); return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data())));
} }
} }
} }
@ -287,26 +293,23 @@ class binary_reader
string_t key; string_t key;
while (int element_type = get()) while (int element_type = get())
{ {
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list")))
{ {
return false; return false;
} }
const std::size_t element_type_parse_position = chars_read; const std::size_t element_type_parse_position = chars_read;
if (JSON_UNLIKELY(not get_bson_cstr(key))) if (JSON_HEDLEY_UNLIKELY(not get_bson_cstr(key)))
{ {
return false; return false;
} }
if (not is_array) if (not is_array and not sax->key(key))
{ {
if (not sax->key(key)) return false;
{
return false;
}
} }
if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position))) if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))
{ {
return false; return false;
} }
@ -327,12 +330,12 @@ class binary_reader
std::int32_t document_size; std::int32_t document_size;
get_number<std::int32_t, true>(input_format_t::bson, document_size); get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/true))) if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/true)))
{ {
return false; return false;
} }
@ -388,25 +391,25 @@ class binary_reader
case 0x18: // Unsigned integer (one-byte uint8_t follows) case 0x18: // Unsigned integer (one-byte uint8_t follows)
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
case 0x19: // Unsigned integer (two-byte uint16_t follows) case 0x19: // Unsigned integer (two-byte uint16_t follows)
{ {
uint16_t number; std::uint16_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
case 0x1A: // Unsigned integer (four-byte uint32_t follows) case 0x1A: // Unsigned integer (four-byte uint32_t follows)
{ {
uint32_t number; std::uint32_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
case 0x1B: // Unsigned integer (eight-byte uint64_t follows) case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
{ {
uint64_t number; std::uint64_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
@ -435,29 +438,29 @@ class binary_reader
case 0x35: case 0x35:
case 0x36: case 0x36:
case 0x37: case 0x37:
return sax->number_integer(static_cast<int8_t>(0x20 - 1 - current)); return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
case 0x38: // Negative integer (one-byte uint8_t follows) case 0x38: // Negative integer (one-byte uint8_t follows)
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number); return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
} }
case 0x39: // Negative integer -1-n (two-byte uint16_t follows) case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
{ {
uint16_t number; std::uint16_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number); return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
} }
case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
{ {
uint32_t number; std::uint32_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number); return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
} }
case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
{ {
uint64_t number; std::uint64_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)
- static_cast<number_integer_t>(number)); - static_cast<number_integer_t>(number));
} }
@ -522,29 +525,29 @@ class binary_reader
case 0x95: case 0x95:
case 0x96: case 0x96:
case 0x97: case 0x97:
return get_cbor_array(static_cast<std::size_t>(current & 0x1F)); return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
case 0x98: // array (one-byte uint8_t for n follows) case 0x98: // array (one-byte uint8_t for n follows)
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
case 0x99: // array (two-byte uint16_t for n follow) case 0x99: // array (two-byte uint16_t for n follow)
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
case 0x9A: // array (four-byte uint32_t for n follow) case 0x9A: // array (four-byte uint32_t for n follow)
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
case 0x9B: // array (eight-byte uint64_t for n follow) case 0x9B: // array (eight-byte uint64_t for n follow)
{ {
uint64_t len; std::uint64_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
@ -576,29 +579,29 @@ class binary_reader
case 0xB5: case 0xB5:
case 0xB6: case 0xB6:
case 0xB7: case 0xB7:
return get_cbor_object(static_cast<std::size_t>(current & 0x1F)); return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
case 0xB8: // map (one-byte uint8_t for n follows) case 0xB8: // map (one-byte uint8_t for n follows)
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
case 0xB9: // map (two-byte uint16_t for n follow) case 0xB9: // map (two-byte uint16_t for n follow)
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
case 0xBA: // map (four-byte uint32_t for n follow) case 0xBA: // map (four-byte uint32_t for n follow)
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
case 0xBB: // map (eight-byte uint64_t for n follow) case 0xBB: // map (eight-byte uint64_t for n follow)
{ {
uint64_t len; std::uint64_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
@ -617,12 +620,12 @@ class binary_reader
case 0xF9: // Half-Precision Float (two-byte IEEE 754) case 0xF9: // Half-Precision Float (two-byte IEEE 754)
{ {
const int byte1_raw = get(); const int byte1_raw = get();
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
{ {
return false; return false;
} }
const int byte2_raw = get(); const int byte2_raw = get();
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
{ {
return false; return false;
} }
@ -638,13 +641,13 @@ class binary_reader
// without such support. An example of a small decoder for // without such support. An example of a small decoder for
// half-precision floating-point numbers in the C language // half-precision floating-point numbers in the C language
// is shown in Fig. 3. // is shown in Fig. 3.
const int half = (byte1 << 8) + byte2; const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
const double val = [&half] const double val = [&half]
{ {
const int exp = (half >> 10) & 0x1F; const int exp = (half >> 10u) & 0x1Fu;
const int mant = half & 0x3FF; const unsigned int mant = half & 0x3FFu;
assert(0 <= exp and exp <= 32); assert(0 <= exp and exp <= 32);
assert(0 <= mant and mant <= 1024); assert(mant <= 1024);
switch (exp) switch (exp)
{ {
case 0: case 0:
@ -657,7 +660,7 @@ class binary_reader
return std::ldexp(mant + 1024, exp - 25); return std::ldexp(mant + 1024, exp - 25);
} }
}(); }();
return sax->number_float((half & 0x8000) != 0 return sax->number_float((half & 0x8000u) != 0
? static_cast<number_float_t>(-val) ? static_cast<number_float_t>(-val)
: static_cast<number_float_t>(val), ""); : static_cast<number_float_t>(val), "");
} }
@ -695,7 +698,7 @@ class binary_reader
*/ */
bool get_cbor_string(string_t& result) bool get_cbor_string(string_t& result)
{ {
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string")))
{ {
return false; return false;
} }
@ -728,30 +731,30 @@ class binary_reader
case 0x76: case 0x76:
case 0x77: case 0x77:
{ {
return get_string(input_format_t::cbor, current & 0x1F, result); return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
} }
case 0x78: // UTF-8 string (one-byte uint8_t for n follows) case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
case 0x79: // UTF-8 string (two-byte uint16_t for n follow) case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
{ {
uint64_t len; std::uint64_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
@ -784,7 +787,7 @@ class binary_reader
*/ */
bool get_cbor_array(const std::size_t len) bool get_cbor_array(const std::size_t len)
{ {
if (JSON_UNLIKELY(not sax->start_array(len))) if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len)))
{ {
return false; return false;
} }
@ -793,7 +796,7 @@ class binary_reader
{ {
for (std::size_t i = 0; i < len; ++i) for (std::size_t i = 0; i < len; ++i)
{ {
if (JSON_UNLIKELY(not parse_cbor_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
{ {
return false; return false;
} }
@ -803,7 +806,7 @@ class binary_reader
{ {
while (get() != 0xFF) while (get() != 0xFF)
{ {
if (JSON_UNLIKELY(not parse_cbor_internal(false))) if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal(false)))
{ {
return false; return false;
} }
@ -820,7 +823,7 @@ class binary_reader
*/ */
bool get_cbor_object(const std::size_t len) bool get_cbor_object(const std::size_t len)
{ {
if (JSON_UNLIKELY(not sax->start_object(len))) if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len)))
{ {
return false; return false;
} }
@ -831,12 +834,12 @@ class binary_reader
for (std::size_t i = 0; i < len; ++i) for (std::size_t i = 0; i < len; ++i)
{ {
get(); get();
if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key))) if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_cbor_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
{ {
return false; return false;
} }
@ -847,12 +850,12 @@ class binary_reader
{ {
while (get() != 0xFF) while (get() != 0xFF)
{ {
if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key))) if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_cbor_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
{ {
return false; return false;
} }
@ -1026,7 +1029,7 @@ class binary_reader
case 0x8D: case 0x8D:
case 0x8E: case 0x8E:
case 0x8F: case 0x8F:
return get_msgpack_object(static_cast<std::size_t>(current & 0x0F)); return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
// fixarray // fixarray
case 0x90: case 0x90:
@ -1045,7 +1048,7 @@ class binary_reader
case 0x9D: case 0x9D:
case 0x9E: case 0x9E:
case 0x9F: case 0x9F:
return get_msgpack_array(static_cast<std::size_t>(current & 0x0F)); return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
// fixstr // fixstr
case 0xA0: case 0xA0:
@ -1080,6 +1083,9 @@ class binary_reader
case 0xBD: case 0xBD:
case 0xBE: case 0xBE:
case 0xBF: case 0xBF:
case 0xD9: // str 8
case 0xDA: // str 16
case 0xDB: // str 32
{ {
string_t s; string_t s;
return get_msgpack_string(s) and sax->string(s); return get_msgpack_string(s) and sax->string(s);
@ -1108,81 +1114,73 @@ class binary_reader
case 0xCC: // uint 8 case 0xCC: // uint 8
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xCD: // uint 16 case 0xCD: // uint 16
{ {
uint16_t number; std::uint16_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xCE: // uint 32 case 0xCE: // uint 32
{ {
uint32_t number; std::uint32_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xCF: // uint 64 case 0xCF: // uint 64
{ {
uint64_t number; std::uint64_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xD0: // int 8 case 0xD0: // int 8
{ {
int8_t number; std::int8_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD1: // int 16 case 0xD1: // int 16
{ {
int16_t number; std::int16_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD2: // int 32 case 0xD2: // int 32
{ {
int32_t number; std::int32_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD3: // int 64 case 0xD3: // int 64
{ {
int64_t number; std::int64_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD9: // str 8
case 0xDA: // str 16
case 0xDB: // str 32
{
string_t s;
return get_msgpack_string(s) and sax->string(s);
}
case 0xDC: // array 16 case 0xDC: // array 16
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
} }
case 0xDD: // array 32 case 0xDD: // array 32
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
} }
case 0xDE: // map 16 case 0xDE: // map 16
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
} }
case 0xDF: // map 32 case 0xDF: // map 32
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
} }
@ -1219,7 +1217,7 @@ class binary_reader
case 0xFD: case 0xFD:
case 0xFE: case 0xFE:
case 0xFF: case 0xFF:
return sax->number_integer(static_cast<int8_t>(current)); return sax->number_integer(static_cast<std::int8_t>(current));
default: // anything else default: // anything else
{ {
@ -1241,7 +1239,7 @@ class binary_reader
*/ */
bool get_msgpack_string(string_t& result) bool get_msgpack_string(string_t& result)
{ {
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string")))
{ {
return false; return false;
} }
@ -1282,24 +1280,24 @@ class binary_reader
case 0xBE: case 0xBE:
case 0xBF: case 0xBF:
{ {
return get_string(input_format_t::msgpack, current & 0x1F, result); return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
} }
case 0xD9: // str 8 case 0xD9: // str 8
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
} }
case 0xDA: // str 16 case 0xDA: // str 16
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
} }
case 0xDB: // str 32 case 0xDB: // str 32
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
} }
@ -1317,14 +1315,14 @@ class binary_reader
*/ */
bool get_msgpack_array(const std::size_t len) bool get_msgpack_array(const std::size_t len)
{ {
if (JSON_UNLIKELY(not sax->start_array(len))) if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len)))
{ {
return false; return false;
} }
for (std::size_t i = 0; i < len; ++i) for (std::size_t i = 0; i < len; ++i)
{ {
if (JSON_UNLIKELY(not parse_msgpack_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal()))
{ {
return false; return false;
} }
@ -1339,7 +1337,7 @@ class binary_reader
*/ */
bool get_msgpack_object(const std::size_t len) bool get_msgpack_object(const std::size_t len)
{ {
if (JSON_UNLIKELY(not sax->start_object(len))) if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len)))
{ {
return false; return false;
} }
@ -1348,12 +1346,12 @@ class binary_reader
for (std::size_t i = 0; i < len; ++i) for (std::size_t i = 0; i < len; ++i)
{ {
get(); get();
if (JSON_UNLIKELY(not get_msgpack_string(key) or not sax->key(key))) if (JSON_HEDLEY_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_msgpack_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal()))
{ {
return false; return false;
} }
@ -1397,10 +1395,10 @@ class binary_reader
{ {
if (get_char) if (get_char)
{ {
get(); // TODO: may we ignore N here? get(); // TODO(niels): may we ignore N here?
} }
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
{ {
return false; return false;
} }
@ -1409,31 +1407,31 @@ class binary_reader
{ {
case 'U': case 'U':
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'i': case 'i':
{ {
int8_t len; std::int8_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'I': case 'I':
{ {
int16_t len; std::int16_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'l': case 'l':
{ {
int32_t len; std::int32_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'L': case 'L':
{ {
int64_t len; std::int64_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
@ -1453,8 +1451,8 @@ class binary_reader
{ {
case 'U': case 'U':
{ {
uint8_t number; std::uint8_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
} }
@ -1464,8 +1462,8 @@ class binary_reader
case 'i': case 'i':
{ {
int8_t number; std::int8_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
} }
@ -1475,8 +1473,8 @@ class binary_reader
case 'I': case 'I':
{ {
int16_t number; std::int16_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
} }
@ -1486,8 +1484,8 @@ class binary_reader
case 'l': case 'l':
{ {
int32_t number; std::int32_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
} }
@ -1497,8 +1495,8 @@ class binary_reader
case 'L': case 'L':
{ {
int64_t number; std::int64_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
} }
@ -1534,15 +1532,15 @@ class binary_reader
if (current == '$') if (current == '$')
{ {
result.second = get(); // must not ignore 'N', because 'N' maybe the type result.second = get(); // must not ignore 'N', because 'N' maybe the type
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type")))
{ {
return false; return false;
} }
get_ignore_noop(); get_ignore_noop();
if (JSON_UNLIKELY(current != '#')) if (JSON_HEDLEY_UNLIKELY(current != '#'))
{ {
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
{ {
return false; return false;
} }
@ -1552,10 +1550,12 @@ class binary_reader
return get_ubjson_size_value(result.first); return get_ubjson_size_value(result.first);
} }
else if (current == '#')
if (current == '#')
{ {
return get_ubjson_size_value(result.first); return get_ubjson_size_value(result.first);
} }
return true; return true;
} }
@ -1580,31 +1580,31 @@ class binary_reader
case 'U': case 'U':
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number); return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);
} }
case 'i': case 'i':
{ {
int8_t number; std::int8_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
case 'I': case 'I':
{ {
int16_t number; std::int16_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
case 'l': case 'l':
{ {
int32_t number; std::int32_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
case 'L': case 'L':
{ {
int64_t number; std::int64_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
@ -1623,11 +1623,11 @@ class binary_reader
case 'C': // char case 'C': // char
{ {
get(); get();
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char")))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(current > 127)) if (JSON_HEDLEY_UNLIKELY(current > 127))
{ {
auto last_token = get_token_string(); auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"))); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char")));
@ -1662,14 +1662,14 @@ class binary_reader
bool get_ubjson_array() bool get_ubjson_array()
{ {
std::pair<std::size_t, int> size_and_type; std::pair<std::size_t, int> size_and_type;
if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type)))
{ {
return false; return false;
} }
if (size_and_type.first != string_t::npos) if (size_and_type.first != string_t::npos)
{ {
if (JSON_UNLIKELY(not sax->start_array(size_and_type.first))) if (JSON_HEDLEY_UNLIKELY(not sax->start_array(size_and_type.first)))
{ {
return false; return false;
} }
@ -1680,7 +1680,7 @@ class binary_reader
{ {
for (std::size_t i = 0; i < size_and_type.first; ++i) for (std::size_t i = 0; i < size_and_type.first; ++i)
{ {
if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second)))
{ {
return false; return false;
} }
@ -1691,7 +1691,7 @@ class binary_reader
{ {
for (std::size_t i = 0; i < size_and_type.first; ++i) for (std::size_t i = 0; i < size_and_type.first; ++i)
{ {
if (JSON_UNLIKELY(not parse_ubjson_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
{ {
return false; return false;
} }
@ -1700,14 +1700,14 @@ class binary_reader
} }
else else
{ {
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
{ {
return false; return false;
} }
while (current != ']') while (current != ']')
{ {
if (JSON_UNLIKELY(not parse_ubjson_internal(false))) if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal(false)))
{ {
return false; return false;
} }
@ -1724,7 +1724,7 @@ class binary_reader
bool get_ubjson_object() bool get_ubjson_object()
{ {
std::pair<std::size_t, int> size_and_type; std::pair<std::size_t, int> size_and_type;
if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type)))
{ {
return false; return false;
} }
@ -1732,7 +1732,7 @@ class binary_reader
string_t key; string_t key;
if (size_and_type.first != string_t::npos) if (size_and_type.first != string_t::npos)
{ {
if (JSON_UNLIKELY(not sax->start_object(size_and_type.first))) if (JSON_HEDLEY_UNLIKELY(not sax->start_object(size_and_type.first)))
{ {
return false; return false;
} }
@ -1741,11 +1741,11 @@ class binary_reader
{ {
for (std::size_t i = 0; i < size_and_type.first; ++i) for (std::size_t i = 0; i < size_and_type.first; ++i)
{ {
if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second)))
{ {
return false; return false;
} }
@ -1756,11 +1756,11 @@ class binary_reader
{ {
for (std::size_t i = 0; i < size_and_type.first; ++i) for (std::size_t i = 0; i < size_and_type.first; ++i)
{ {
if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_ubjson_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
{ {
return false; return false;
} }
@ -1770,18 +1770,18 @@ class binary_reader
} }
else else
{ {
if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
{ {
return false; return false;
} }
while (current != '}') while (current != '}')
{ {
if (JSON_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key))) if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))
{ {
return false; return false;
} }
if (JSON_UNLIKELY(not parse_ubjson_internal())) if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
{ {
return false; return false;
} }
@ -1809,7 +1809,7 @@ class binary_reader
int get() int get()
{ {
++chars_read; ++chars_read;
return (current = ia->get_character()); return current = ia->get_character();
} }
/*! /*!
@ -1843,23 +1843,23 @@ class binary_reader
bool get_number(const input_format_t format, NumberType& result) bool get_number(const input_format_t format, NumberType& result)
{ {
// step 1: read input into array with system's byte order // step 1: read input into array with system's byte order
std::array<uint8_t, sizeof(NumberType)> vec; std::array<std::uint8_t, sizeof(NumberType)> vec;
for (std::size_t i = 0; i < sizeof(NumberType); ++i) for (std::size_t i = 0; i < sizeof(NumberType); ++i)
{ {
get(); get();
if (JSON_UNLIKELY(not unexpect_eof(format, "number"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "number")))
{ {
return false; return false;
} }
// reverse byte order prior to conversion if necessary // reverse byte order prior to conversion if necessary
if (is_little_endian && !InputIsLittleEndian) if (is_little_endian != InputIsLittleEndian)
{ {
vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current); vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
} }
else else
{ {
vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
} }
} }
@ -1891,7 +1891,7 @@ class binary_reader
std::generate_n(std::back_inserter(result), len, [this, &success, &format]() std::generate_n(std::back_inserter(result), len, [this, &success, &format]()
{ {
get(); get();
if (JSON_UNLIKELY(not unexpect_eof(format, "string"))) if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "string")))
{ {
success = false; success = false;
} }
@ -1905,9 +1905,10 @@ class binary_reader
@param[in] context further context information (for diagnostics) @param[in] context further context information (for diagnostics)
@return whether the last read character is not EOF @return whether the last read character is not EOF
*/ */
JSON_HEDLEY_NON_NULL(3)
bool unexpect_eof(const input_format_t format, const char* context) const bool unexpect_eof(const input_format_t format, const char* context) const
{ {
if (JSON_UNLIKELY(current == std::char_traits<char>::eof())) if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char>::eof()))
{ {
return sax->parse_error(chars_read, "<end of file>", return sax->parse_error(chars_read, "<end of file>",
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context))); parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context)));
@ -1920,15 +1921,15 @@ class binary_reader
*/ */
std::string get_token_string() const std::string get_token_string() const
{ {
char cr[3]; std::array<char, 3> cr{{}};
(std::snprintf)(cr, 3, "%.2hhX", static_cast<unsigned char>(current)); (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current));
return std::string{cr}; return std::string{cr.data()};
} }
/*! /*!
@param[in] format the current format @param[in] format the current format
@param[in] detail a detailed error message @param[in] detail a detailed error message
@param[in] context further contect information @param[in] context further context information
@return a message string to use in the parse_error exceptions @return a message string to use in the parse_error exceptions
*/ */
std::string exception_message(const input_format_t format, std::string exception_message(const input_format_t format,
@ -1955,10 +1956,8 @@ class binary_reader
error_msg += "BSON"; error_msg += "BSON";
break; break;
// LCOV_EXCL_START default: // LCOV_EXCL_LINE
default: assert(false); // LCOV_EXCL_LINE
assert(false);
// LCOV_EXCL_STOP
} }
return error_msg + " " + context + ": " + detail; return error_msg + " " + context + ": " + detail;

View file

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdio> //FILE *
#include <cstring> // strlen #include <cstring> // strlen
#include <istream> // istream #include <istream> // istream
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
@ -10,7 +12,6 @@
#include <string> // string, char_traits #include <string> // string, char_traits
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
#include <utility> // pair, declval #include <utility> // pair, declval
#include <cstdio> //FILE *
#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>
@ -54,14 +55,23 @@ Input adapter for stdio file access. This adapter read only 1 byte and do not us
class file_input_adapter : public input_adapter_protocol class file_input_adapter : public input_adapter_protocol
{ {
public: public:
JSON_HEDLEY_NON_NULL(2)
explicit file_input_adapter(std::FILE* f) noexcept explicit file_input_adapter(std::FILE* f) noexcept
: m_file(f) : m_file(f)
{} {}
// make class move-only
file_input_adapter(const file_input_adapter&) = delete;
file_input_adapter(file_input_adapter&&) = default;
file_input_adapter& operator=(const file_input_adapter&) = delete;
file_input_adapter& operator=(file_input_adapter&&) = default;
~file_input_adapter() override = default;
std::char_traits<char>::int_type get_character() noexcept override std::char_traits<char>::int_type get_character() noexcept override
{ {
return std::fgetc(m_file); return std::fgetc(m_file);
} }
private: private:
/// the file pointer to read from /// the file pointer to read from
std::FILE* m_file; std::FILE* m_file;
@ -122,7 +132,7 @@ class input_buffer_adapter : public input_adapter_protocol
{ {
public: public:
input_buffer_adapter(const char* b, const std::size_t l) noexcept input_buffer_adapter(const char* b, const std::size_t l) noexcept
: cursor(b), limit(b + l) : cursor(b), limit(b == nullptr ? nullptr : (b + l))
{} {}
// delete because of pointer members // delete because of pointer members
@ -134,8 +144,9 @@ class input_buffer_adapter : public input_adapter_protocol
std::char_traits<char>::int_type get_character() noexcept override std::char_traits<char>::int_type get_character() noexcept override
{ {
if (JSON_LIKELY(cursor < limit)) if (JSON_HEDLEY_LIKELY(cursor < limit))
{ {
assert(cursor != nullptr and limit != nullptr);
return std::char_traits<char>::to_int_type(*(cursor++)); return std::char_traits<char>::to_int_type(*(cursor++));
} }
@ -153,7 +164,11 @@ template<typename WideStringType, size_t T>
struct wide_string_input_helper struct wide_string_input_helper
{ {
// UTF-32 // UTF-32
static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) static void fill_buffer(const WideStringType& str,
size_t& current_wchar,
std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
size_t& utf8_bytes_index,
size_t& utf8_bytes_filled)
{ {
utf8_bytes_index = 0; utf8_bytes_index = 0;
@ -165,39 +180,39 @@ struct wide_string_input_helper
else else
{ {
// get the current character // get the current character
const auto wc = static_cast<int>(str[current_wchar++]); const auto wc = static_cast<unsigned int>(str[current_wchar++]);
// UTF-32 to UTF-8 encoding // UTF-32 to UTF-8 encoding
if (wc < 0x80) if (wc < 0x80)
{ {
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else if (wc <= 0x7FF) else if (wc <= 0x7FF)
{ {
utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u) & 0x1Fu));
utf8_bytes[1] = 0x80 | (wc & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 2; utf8_bytes_filled = 2;
} }
else if (wc <= 0xFFFF) else if (wc <= 0xFFFF)
{ {
utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u) & 0x0Fu));
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
utf8_bytes[2] = 0x80 | (wc & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 3; utf8_bytes_filled = 3;
} }
else if (wc <= 0x10FFFF) else if (wc <= 0x10FFFF)
{ {
utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((wc >> 18u) & 0x07u));
utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 12u) & 0x3Fu));
utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
utf8_bytes[3] = 0x80 | (wc & 0x3F); utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 4; utf8_bytes_filled = 4;
} }
else else
{ {
// unknown character // unknown character
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
} }
@ -208,7 +223,11 @@ template<typename WideStringType>
struct wide_string_input_helper<WideStringType, 2> struct wide_string_input_helper<WideStringType, 2>
{ {
// UTF-16 // UTF-16
static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) static void fill_buffer(const WideStringType& str,
size_t& current_wchar,
std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
size_t& utf8_bytes_index,
size_t& utf8_bytes_filled)
{ {
utf8_bytes_index = 0; utf8_bytes_index = 0;
@ -220,44 +239,44 @@ struct wide_string_input_helper<WideStringType, 2>
else else
{ {
// get the current character // get the current character
const auto wc = static_cast<int>(str[current_wchar++]); const auto wc = static_cast<unsigned int>(str[current_wchar++]);
// UTF-16 to UTF-8 encoding // UTF-16 to UTF-8 encoding
if (wc < 0x80) if (wc < 0x80)
{ {
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else if (wc <= 0x7FF) else if (wc <= 0x7FF)
{ {
utf8_bytes[0] = 0xC0 | ((wc >> 6)); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u)));
utf8_bytes[1] = 0x80 | (wc & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 2; utf8_bytes_filled = 2;
} }
else if (0xD800 > wc or wc >= 0xE000) else if (0xD800 > wc or wc >= 0xE000)
{ {
utf8_bytes[0] = 0xE0 | ((wc >> 12)); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u)));
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
utf8_bytes[2] = 0x80 | (wc & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 3; utf8_bytes_filled = 3;
} }
else else
{ {
if (current_wchar < str.size()) if (current_wchar < str.size())
{ {
const auto wc2 = static_cast<int>(str[current_wchar++]); const auto wc2 = static_cast<unsigned int>(str[current_wchar++]);
const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
utf8_bytes[0] = 0xf0 | (charcode >> 18); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
utf8_bytes[3] = 0x80 | (charcode & 0x3F); utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
utf8_bytes_filled = 4; utf8_bytes_filled = 4;
} }
else else
{ {
// unknown character // unknown character
++current_wchar; ++current_wchar;
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
} }
@ -269,7 +288,7 @@ template<typename WideStringType>
class wide_string_input_adapter : public input_adapter_protocol class wide_string_input_adapter : public input_adapter_protocol
{ {
public: public:
explicit wide_string_input_adapter(const WideStringType& w) noexcept explicit wide_string_input_adapter(const WideStringType& w) noexcept
: str(w) : str(w)
{} {}
@ -316,6 +335,7 @@ class input_adapter
{ {
public: public:
// native support // native support
JSON_HEDLEY_NON_NULL(2)
input_adapter(std::FILE* file) input_adapter(std::FILE* file)
: ia(std::make_shared<file_input_adapter>(file)) {} : ia(std::make_shared<file_input_adapter>(file)) {}
/// input adapter for input stream /// input adapter for input stream
@ -384,7 +404,7 @@ class input_adapter
"each element in the iterator range must have the size of 1 byte"); "each element in the iterator range must have the size of 1 byte");
const auto len = static_cast<size_t>(std::distance(first, last)); const auto len = static_cast<size_t>(std::distance(first, last));
if (JSON_LIKELY(len > 0)) if (JSON_HEDLEY_LIKELY(len > 0))
{ {
// there is at least one element: use the address of first // there is at least one element: use the address of first
ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len); ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);

View file

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <cassert> #include <cassert> // assert
#include <cstddef> #include <cstddef>
#include <string> #include <string> // string
#include <vector> #include <utility> // move
#include <vector> // vector
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@ -158,6 +159,13 @@ class json_sax_dom_parser
: root(r), allow_exceptions(allow_exceptions_) : root(r), allow_exceptions(allow_exceptions_)
{} {}
// make class move-only
json_sax_dom_parser(const json_sax_dom_parser&) = delete;
json_sax_dom_parser(json_sax_dom_parser&&) = default;
json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;
~json_sax_dom_parser() = default;
bool null() bool null()
{ {
handle_value(nullptr); handle_value(nullptr);
@ -198,7 +206,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_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and 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)));
@ -224,7 +232,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_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and 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)));
@ -249,16 +257,16 @@ class json_sax_dom_parser
switch ((ex.id / 100) % 100) switch ((ex.id / 100) % 100)
{ {
case 1: case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex)); JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
case 4: case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START // LCOV_EXCL_START
case 2: case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex)); JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
case 3: case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex)); JSON_THROW(*static_cast<const detail::type_error*>(&ex));
case 5: case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); JSON_THROW(*static_cast<const detail::other_error*>(&ex));
default: default:
assert(false); assert(false);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -280,6 +288,7 @@ class json_sax_dom_parser
object to which we can add elements object to which we can add elements
*/ */
template<typename Value> template<typename Value>
JSON_HEDLEY_RETURNS_NON_NULL
BasicJsonType* handle_value(Value&& v) BasicJsonType* handle_value(Value&& v)
{ {
if (ref_stack.empty()) if (ref_stack.empty())
@ -295,18 +304,17 @@ class json_sax_dom_parser
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v)); ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
return &(ref_stack.back()->m_value.array->back()); return &(ref_stack.back()->m_value.array->back());
} }
else
{ assert(ref_stack.back()->is_object());
assert(object_element); assert(object_element);
*object_element = BasicJsonType(std::forward<Value>(v)); *object_element = BasicJsonType(std::forward<Value>(v));
return object_element; return object_element;
}
} }
/// the parsed JSON value /// the parsed JSON value
BasicJsonType& root; BasicJsonType& root;
/// stack to model hierarchy of values /// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack; std::vector<BasicJsonType*> ref_stack {};
/// helper to hold the reference for the next object element /// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr; BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred /// whether a syntax error occurred
@ -334,6 +342,13 @@ class json_sax_dom_callback_parser
keep_stack.push_back(true); keep_stack.push_back(true);
} }
// make class move-only
json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;
json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default;
~json_sax_dom_callback_parser() = default;
bool null() bool null()
{ {
handle_value(nullptr); handle_value(nullptr);
@ -380,13 +395,9 @@ 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()) if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
{ {
if (JSON_UNLIKELY(len != std::size_t(-1) and 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)));
}
} }
return true; return true;
@ -411,13 +422,10 @@ class json_sax_dom_callback_parser
bool end_object() bool end_object()
{ {
if (ref_stack.back()) if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{ {
if (not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) // discard object
{ *ref_stack.back() = discarded;
// discard object
*ref_stack.back() = discarded;
}
} }
assert(not ref_stack.empty()); assert(not ref_stack.empty());
@ -425,18 +433,15 @@ class json_sax_dom_callback_parser
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()) if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_object())
{ {
// remove discarded value // remove discarded value
if (ref_stack.back()->is_object()) 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) if (it->is_discarded())
{ {
if (it->is_discarded()) ref_stack.back()->erase(it);
{ break;
ref_stack.back()->erase(it);
break;
}
} }
} }
} }
@ -453,13 +458,9 @@ 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()) if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
{ {
if (JSON_UNLIKELY(len != std::size_t(-1) and 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)));
}
} }
return true; return true;
@ -485,12 +486,9 @@ class json_sax_dom_callback_parser
keep_stack.pop_back(); keep_stack.pop_back();
// remove discarded value // remove discarded value
if (not keep and not ref_stack.empty()) if (not keep and not ref_stack.empty() and ref_stack.back()->is_array())
{ {
if (ref_stack.back()->is_array()) ref_stack.back()->m_value.array->pop_back();
{
ref_stack.back()->m_value.array->pop_back();
}
} }
return true; return true;
@ -506,16 +504,16 @@ class json_sax_dom_callback_parser
switch ((ex.id / 100) % 100) switch ((ex.id / 100) % 100)
{ {
case 1: case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex)); JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
case 4: case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START // LCOV_EXCL_START
case 2: case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex)); JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
case 3: case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex)); JSON_THROW(*static_cast<const detail::type_error*>(&ex));
case 5: case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); JSON_THROW(*static_cast<const detail::other_error*>(&ex));
default: default:
assert(false); assert(false);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -585,37 +583,38 @@ class json_sax_dom_callback_parser
// 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()); assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
// array
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
{ {
ref_stack.back()->m_value.array->push_back(std::move(value)); ref_stack.back()->m_value.array->push_back(std::move(value));
return {true, &(ref_stack.back()->m_value.array->back())}; return {true, &(ref_stack.back()->m_value.array->back())};
} }
else
// object
assert(ref_stack.back()->is_object());
// check if we should store an element for the current key
assert(not key_keep_stack.empty());
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
if (not store_element)
{ {
// check if we should store an element for the current key return {false, nullptr};
assert(not key_keep_stack.empty());
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
if (not store_element)
{
return {false, nullptr};
}
assert(object_element);
*object_element = std::move(value);
return {true, object_element};
} }
assert(object_element);
*object_element = std::move(value);
return {true, object_element};
} }
/// the parsed JSON value /// the parsed JSON value
BasicJsonType& root; BasicJsonType& root;
/// stack to model hierarchy of values /// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack; std::vector<BasicJsonType*> ref_stack {};
/// stack to manage which values to keep /// stack to manage which values to keep
std::vector<bool> keep_stack; std::vector<bool> keep_stack {};
/// stack to manage which object keys to keep /// stack to manage which object keys to keep
std::vector<bool> key_keep_stack; std::vector<bool> key_keep_stack {};
/// helper to hold the reference for the next object element /// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr; BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred /// whether a syntax error occurred

View file

@ -1,16 +1,18 @@
#pragma once #pragma once
#include <array> // array
#include <clocale> // localeconv #include <clocale> // localeconv
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <string> // char_traits, string #include <string> // char_traits, string
#include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/position_t.hpp> #include <nlohmann/detail/input/position_t.hpp>
#include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -57,6 +59,8 @@ class lexer
}; };
/// return name of values of type token_type (only used for errors) /// return name of values of type token_type (only used for errors)
JSON_HEDLEY_RETURNS_NON_NULL
JSON_HEDLEY_CONST
static const char* token_type_name(const token_type t) noexcept static const char* token_type_name(const token_type t) noexcept
{ {
switch (t) switch (t)
@ -116,6 +120,7 @@ class lexer
///////////////////// /////////////////////
/// return the locale-dependent decimal point /// return the locale-dependent decimal point
JSON_HEDLEY_PURE
static char get_decimal_point() noexcept static char get_decimal_point() noexcept
{ {
const auto loc = localeconv(); const auto loc = localeconv();
@ -148,22 +153,22 @@ class lexer
assert(current == 'u'); assert(current == 'u');
int codepoint = 0; int codepoint = 0;
const auto factors = { 12, 8, 4, 0 }; const auto factors = { 12u, 8u, 4u, 0u };
for (const auto factor : factors) for (const auto factor : factors)
{ {
get(); get();
if (current >= '0' and current <= '9') if (current >= '0' and current <= '9')
{ {
codepoint += ((current - 0x30) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
} }
else if (current >= 'A' and current <= 'F') else if (current >= 'A' and current <= 'F')
{ {
codepoint += ((current - 0x37) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
} }
else if (current >= 'a' and current <= 'f') else if (current >= 'a' and current <= 'f')
{ {
codepoint += ((current - 0x57) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
} }
else else
{ {
@ -198,7 +203,7 @@ class lexer
for (auto range = ranges.begin(); range != ranges.end(); ++range) for (auto range = ranges.begin(); range != ranges.end(); ++range)
{ {
get(); get();
if (JSON_LIKELY(*range <= current and current <= *(++range))) if (JSON_HEDLEY_LIKELY(*range <= current and current <= *(++range)))
{ {
add(current); add(current);
} }
@ -297,7 +302,7 @@ class lexer
const int codepoint1 = get_codepoint(); const int codepoint1 = get_codepoint();
int codepoint = codepoint1; // start with codepoint1 int codepoint = codepoint1; // start with codepoint1
if (JSON_UNLIKELY(codepoint1 == -1)) if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
{ {
error_message = "invalid string: '\\u' must be followed by 4 hex digits"; error_message = "invalid string: '\\u' must be followed by 4 hex digits";
return token_type::parse_error; return token_type::parse_error;
@ -307,29 +312,29 @@ class lexer
if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
{ {
// expect next \uxxxx entry // expect next \uxxxx entry
if (JSON_LIKELY(get() == '\\' and get() == 'u')) if (JSON_HEDLEY_LIKELY(get() == '\\' and get() == 'u'))
{ {
const int codepoint2 = get_codepoint(); const int codepoint2 = get_codepoint();
if (JSON_UNLIKELY(codepoint2 == -1)) if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))
{ {
error_message = "invalid string: '\\u' must be followed by 4 hex digits"; error_message = "invalid string: '\\u' must be followed by 4 hex digits";
return token_type::parse_error; return token_type::parse_error;
} }
// check if codepoint2 is a low surrogate // check if codepoint2 is a low surrogate
if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
{ {
// overwrite codepoint // overwrite codepoint
codepoint = codepoint = static_cast<int>(
// high surrogate occupies the most significant 22 bits // high surrogate occupies the most significant 22 bits
(codepoint1 << 10) (static_cast<unsigned int>(codepoint1) << 10u)
// low surrogate occupies the least significant 15 bits // low surrogate occupies the least significant 15 bits
+ codepoint2 + static_cast<unsigned int>(codepoint2)
// there is still the 0xD800, 0xDC00 and 0x10000 noise // there is still the 0xD800, 0xDC00 and 0x10000 noise
// in the result so we have to subtract with: // in the result so we have to subtract with:
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
- 0x35FDC00; - 0x35FDC00u);
} }
else else
{ {
@ -345,7 +350,7 @@ class lexer
} }
else else
{ {
if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 and 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;
@ -364,23 +369,23 @@ class lexer
else if (codepoint <= 0x7FF) else if (codepoint <= 0x7FF)
{ {
// 2-byte characters: 110xxxxx 10xxxxxx // 2-byte characters: 110xxxxx 10xxxxxx
add(0xC0 | (codepoint >> 6)); add(static_cast<int>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
add(0x80 | (codepoint & 0x3F)); add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
} }
else if (codepoint <= 0xFFFF) else if (codepoint <= 0xFFFF)
{ {
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
add(0xE0 | (codepoint >> 12)); add(static_cast<int>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
add(0x80 | ((codepoint >> 6) & 0x3F)); add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
add(0x80 | (codepoint & 0x3F)); add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
} }
else else
{ {
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
add(0xF0 | (codepoint >> 18)); add(static_cast<int>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
add(0x80 | ((codepoint >> 12) & 0x3F)); add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
add(0x80 | ((codepoint >> 6) & 0x3F)); add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
add(0x80 | (codepoint & 0x3F)); add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
} }
break; break;
@ -720,7 +725,7 @@ class lexer
case 0xDE: case 0xDE:
case 0xDF: case 0xDF:
{ {
if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) if (JSON_HEDLEY_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -730,7 +735,7 @@ class lexer
// 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_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -754,7 +759,7 @@ class lexer
case 0xEE: case 0xEE:
case 0xEF: case 0xEF:
{ {
if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -764,7 +769,7 @@ class lexer
// 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_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -774,7 +779,7 @@ class lexer
// 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_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -786,7 +791,7 @@ class lexer
case 0xF2: case 0xF2:
case 0xF3: case 0xF3:
{ {
if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -796,7 +801,7 @@ class lexer
// 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_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@ -813,16 +818,19 @@ class lexer
} }
} }
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
{ {
f = std::strtof(str, endptr); f = std::strtof(str, endptr);
} }
JSON_HEDLEY_NON_NULL(2)
static void strtof(double& f, const char* str, char** endptr) noexcept static void strtof(double& f, const char* str, char** endptr) noexcept
{ {
f = std::strtod(str, endptr); f = std::strtod(str, endptr);
} }
JSON_HEDLEY_NON_NULL(2)
static void strtof(long double& f, const char* str, char** endptr) noexcept static void strtof(long double& f, const char* str, char** endptr) noexcept
{ {
f = std::strtold(str, endptr); f = std::strtold(str, endptr);
@ -906,13 +914,9 @@ class lexer
goto scan_number_any1; goto scan_number_any1;
} }
// LCOV_EXCL_START // all other characters are rejected outside scan_number()
default: default: // LCOV_EXCL_LINE
{ assert(false); // LCOV_EXCL_LINE
// all other characters are rejected outside scan_number()
assert(false);
}
// LCOV_EXCL_STOP
} }
scan_number_minus: scan_number_minus:
@ -1202,13 +1206,14 @@ scan_number_done:
@param[in] length the length of the passed literal text @param[in] length the length of the passed literal text
@param[in] return_type the token type to return on success @param[in] return_type the token type to return on success
*/ */
JSON_HEDLEY_NON_NULL(2)
token_type scan_literal(const char* literal_text, const std::size_t length, token_type scan_literal(const char* literal_text, const std::size_t length,
token_type return_type) token_type return_type)
{ {
assert(current == literal_text[0]); assert(current == literal_text[0]);
for (std::size_t i = 1; i < length; ++i) for (std::size_t i = 1; i < length; ++i)
{ {
if (JSON_UNLIKELY(get() != literal_text[i])) if (JSON_HEDLEY_UNLIKELY(get() != literal_text[i]))
{ {
error_message = "invalid literal"; error_message = "invalid literal";
return token_type::parse_error; return token_type::parse_error;
@ -1254,7 +1259,7 @@ scan_number_done:
current = ia->get_character(); current = ia->get_character();
} }
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_HEDLEY_LIKELY(current != std::char_traits<char>::eof()))
{ {
token_string.push_back(std::char_traits<char>::to_char_type(current)); token_string.push_back(std::char_traits<char>::to_char_type(current));
} }
@ -1295,9 +1300,9 @@ scan_number_done:
--position.chars_read_current_line; --position.chars_read_current_line;
} }
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_HEDLEY_LIKELY(current != std::char_traits<char>::eof()))
{ {
assert(token_string.size() != 0); assert(not token_string.empty());
token_string.pop_back(); token_string.pop_back();
} }
} }
@ -1359,9 +1364,9 @@ scan_number_done:
if ('\x00' <= c and c <= '\x1F') if ('\x00' <= c and c <= '\x1F')
{ {
// escape control characters // escape control characters
char cs[9]; std::array<char, 9> cs{{}};
(std::snprintf)(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c)); (std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c));
result += cs; result += cs.data();
} }
else else
{ {
@ -1374,6 +1379,7 @@ scan_number_done:
} }
/// return syntax error message /// return syntax error message
JSON_HEDLEY_RETURNS_NON_NULL
constexpr const char* get_error_message() const noexcept constexpr const char* get_error_message() const noexcept
{ {
return error_message; return error_message;
@ -1483,7 +1489,7 @@ scan_number_done:
bool next_unget = false; bool next_unget = false;
/// the start position of the current token /// the start position of the current token
position_t position; position_t position {};
/// raw input token string (for error messages) /// raw input token string (for error messages)
std::vector<char> token_string {}; std::vector<char> token_string {};

View file

@ -6,13 +6,14 @@
#include <functional> // function #include <functional> // function
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/json_sax.hpp> #include <nlohmann/detail/input/json_sax.hpp>
#include <nlohmann/detail/input/lexer.hpp> #include <nlohmann/detail/input/lexer.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
@ -146,6 +147,7 @@ class parser
} }
template <typename SAX> template <typename SAX>
JSON_HEDLEY_NON_NULL(2)
bool sax_parse(SAX* sax, const bool strict = true) bool sax_parse(SAX* sax, const bool strict = true)
{ {
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
@ -165,6 +167,7 @@ class parser
private: private:
template <typename SAX> template <typename SAX>
JSON_HEDLEY_NON_NULL(2)
bool sax_parse_internal(SAX* sax) bool sax_parse_internal(SAX* sax)
{ {
// stack to remember the hierarchy of structured values we are parsing // stack to remember the hierarchy of structured values we are parsing
@ -182,7 +185,7 @@ class parser
{ {
case token_type::begin_object: case token_type::begin_object:
{ {
if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
{ {
return false; return false;
} }
@ -190,7 +193,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_UNLIKELY(not sax->end_object())) if (JSON_HEDLEY_UNLIKELY(not sax->end_object()))
{ {
return false; return false;
} }
@ -198,20 +201,20 @@ class parser
} }
// parse key // parse key
if (JSON_UNLIKELY(last_token != token_type::value_string)) if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
{ {
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(),
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_UNLIKELY(not sax->key(m_lexer.get_string()))) if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string())))
{ {
return false; return false;
} }
// parse separator (:) // parse separator (:)
if (JSON_UNLIKELY(get_token() != token_type::name_separator)) if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
{ {
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(),
@ -229,7 +232,7 @@ class parser
case token_type::begin_array: case token_type::begin_array:
{ {
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
{ {
return false; return false;
} }
@ -237,7 +240,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_UNLIKELY(not sax->end_array())) if (JSON_HEDLEY_UNLIKELY(not sax->end_array()))
{ {
return false; return false;
} }
@ -255,25 +258,24 @@ class parser
{ {
const auto res = m_lexer.get_number_float(); const auto res = m_lexer.get_number_float();
if (JSON_UNLIKELY(not std::isfinite(res))) if (JSON_HEDLEY_UNLIKELY(not 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() + "'"));
} }
else
if (JSON_HEDLEY_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
{ {
if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string()))) return false;
{
return false;
}
break;
} }
break;
} }
case token_type::literal_false: case token_type::literal_false:
{ {
if (JSON_UNLIKELY(not sax->boolean(false))) if (JSON_HEDLEY_UNLIKELY(not sax->boolean(false)))
{ {
return false; return false;
} }
@ -282,7 +284,7 @@ class parser
case token_type::literal_null: case token_type::literal_null:
{ {
if (JSON_UNLIKELY(not sax->null())) if (JSON_HEDLEY_UNLIKELY(not sax->null()))
{ {
return false; return false;
} }
@ -291,7 +293,7 @@ class parser
case token_type::literal_true: case token_type::literal_true:
{ {
if (JSON_UNLIKELY(not sax->boolean(true))) if (JSON_HEDLEY_UNLIKELY(not sax->boolean(true)))
{ {
return false; return false;
} }
@ -300,7 +302,7 @@ class parser
case token_type::value_integer: case token_type::value_integer:
{ {
if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer()))) if (JSON_HEDLEY_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
{ {
return false; return false;
} }
@ -309,7 +311,7 @@ class parser
case token_type::value_string: case token_type::value_string:
{ {
if (JSON_UNLIKELY(not sax->string(m_lexer.get_string()))) if (JSON_HEDLEY_UNLIKELY(not sax->string(m_lexer.get_string())))
{ {
return false; return false;
} }
@ -318,7 +320,7 @@ class parser
case token_type::value_unsigned: case token_type::value_unsigned:
{ {
if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned()))) if (JSON_HEDLEY_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
{ {
return false; return false;
} }
@ -354,103 +356,95 @@ class parser
// empty stack: we reached the end of the hierarchy: done // empty stack: we reached the end of the hierarchy: done
return true; return true;
} }
else
if (states.back()) // array
{ {
if (states.back()) // array // comma -> next value
if (get_token() == token_type::value_separator)
{ {
// comma -> next value // parse a new value
if (get_token() == token_type::value_separator) get_token();
continue;
}
// closing ]
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
{
if (JSON_HEDLEY_UNLIKELY(not sax->end_array()))
{ {
// parse a new value return false;
get_token();
continue;
} }
// closing ] // We are done with this array. Before we can parse a
if (JSON_LIKELY(last_token == token_type::end_array)) // new value, we need to evaluate the new state first.
{ // By setting skip_to_state_evaluation to false, we
if (JSON_UNLIKELY(not sax->end_array())) // are effectively jumping to the beginning of this if.
{ assert(not states.empty());
return false; states.pop_back();
} skip_to_state_evaluation = true;
continue;
}
// We are done with this array. Before we can parse a return sax->parse_error(m_lexer.get_position(),
// new value, we need to evaluate the new state first. m_lexer.get_token_string(),
// By setting skip_to_state_evaluation to false, we parse_error::create(101, m_lexer.get_position(),
// are effectively jumping to the beginning of this if. exception_message(token_type::end_array, "array")));
assert(not states.empty()); }
states.pop_back(); else // object
skip_to_state_evaluation = true; {
continue; // comma -> next value
} if (get_token() == token_type::value_separator)
else {
// parse key
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
{ {
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(),
parse_error::create(101, m_lexer.get_position(), parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_array, "array"))); exception_message(token_type::value_string, "object key")));
} }
}
else // object if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string())))
{
// comma -> next value
if (get_token() == token_type::value_separator)
{ {
// parse key return false;
if (JSON_UNLIKELY(get_token() != token_type::value_string))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::value_string, "object key")));
}
else
{
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
{
return false;
}
}
// parse separator (:)
if (JSON_UNLIKELY(get_token() != token_type::name_separator))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::name_separator, "object separator")));
}
// parse values
get_token();
continue;
} }
// closing } // parse separator (:)
if (JSON_LIKELY(last_token == token_type::end_object)) if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
{
if (JSON_UNLIKELY(not sax->end_object()))
{
return false;
}
// We are done with this object. Before we can parse a
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
assert(not states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
}
else
{ {
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(),
parse_error::create(101, m_lexer.get_position(), parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_object, "object"))); exception_message(token_type::name_separator, "object separator")));
} }
// parse values
get_token();
continue;
} }
// closing }
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
{
if (JSON_HEDLEY_UNLIKELY(not sax->end_object()))
{
return false;
}
// We are done with this object. Before we can parse a
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
assert(not states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
}
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_object, "object")));
} }
} }
} }
@ -458,7 +452,7 @@ class parser
/// get next token from lexer /// get next token from lexer
token_type get_token() token_type get_token()
{ {
return (last_token = m_lexer.scan()); return last_token = m_lexer.scan();
} }
std::string exception_message(const token_type expected, const std::string& context) std::string exception_message(const token_type expected, const std::string& context)

View file

@ -23,5 +23,5 @@ struct position_t
} }
}; };
} } // namespace detail
} } // namespace nlohmann

View file

@ -118,17 +118,42 @@ class iter_impl
to iterator is not defined. to iterator is not defined.
*/ */
/*!
@brief const copy constructor
@param[in] other const iterator to copy from
@note This copy constructor had to be defined explicitly to circumvent a bug
occurring on msvc v19.0 compiler (VS 2015) debug build. For more
information refer to: https://github.com/nlohmann/json/issues/1608
*/
iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
: m_object(other.m_object), m_it(other.m_it)
{}
/*!
@brief converting assignment
@param[in] other const iterator to copy from
@return const/non-const iterator
@note It is not checked whether @a other is initialized.
*/
iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
{
m_object = other.m_object;
m_it = other.m_it;
return *this;
}
/*! /*!
@brief converting constructor @brief converting constructor
@param[in] other non-const iterator to copy from @param[in] other non-const iterator to copy from
@note It is not checked whether @a other is initialized. @note It is not checked whether @a other is initialized.
*/ */
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
: m_object(other.m_object), m_it(other.m_it) {} : m_object(other.m_object), m_it(other.m_it)
{}
/*! /*!
@brief converting assignment @brief converting assignment
@param[in,out] other non-const iterator to copy from @param[in] other non-const iterator to copy from
@return const/non-const iterator @return const/non-const iterator
@note It is not checked whether @a other is initialized. @note It is not checked whether @a other is initialized.
*/ */
@ -235,7 +260,7 @@ class iter_impl
default: default:
{ {
if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
{ {
return *m_object; return *m_object;
} }
@ -269,7 +294,7 @@ class iter_impl
default: default:
{ {
if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
{ {
return m_object; return m_object;
} }
@ -372,7 +397,7 @@ class iter_impl
bool operator==(const iter_impl& other) const bool operator==(const iter_impl& other) const
{ {
// if objects are not the same, the comparison is undefined // if objects are not the same, the comparison is undefined
if (JSON_UNLIKELY(m_object != other.m_object)) if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
{ {
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
} }
@ -408,7 +433,7 @@ class iter_impl
bool operator<(const iter_impl& other) const bool operator<(const iter_impl& other) const
{ {
// if objects are not the same, the comparison is undefined // if objects are not the same, the comparison is undefined
if (JSON_UNLIKELY(m_object != other.m_object)) if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
{ {
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
} }
@ -568,7 +593,7 @@ class iter_impl
default: default:
{ {
if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
{ {
return *m_object; return *m_object;
} }
@ -586,7 +611,7 @@ class iter_impl
{ {
assert(m_object != nullptr); assert(m_object != nullptr);
if (JSON_LIKELY(m_object->is_object())) if (JSON_HEDLEY_LIKELY(m_object->is_object()))
{ {
return m_it.object_iterator->first; return m_it.object_iterator->first;
} }
@ -607,7 +632,7 @@ class iter_impl
/// associated JSON instance /// associated JSON instance
pointer m_object = nullptr; pointer m_object = nullptr;
/// the actual iterator of the associated instance /// the actual iterator of the associated instance
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it; internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

View file

@ -1,17 +1,22 @@
#pragma once #pragma once
#include <cstddef> // size_t #include <cstddef> // size_t
#include <string> // string, to_string
#include <iterator> // input_iterator_tag #include <iterator> // input_iterator_tag
#include <string> // string, to_string
#include <tuple> // tuple_size, get, tuple_element #include <tuple> // tuple_size, get, tuple_element
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
{ {
template<typename string_type>
void int_to_string( string_type& target, std::size_t value )
{
target = std::to_string(value);
}
template <typename IteratorType> class iteration_proxy_value template <typename IteratorType> class iteration_proxy_value
{ {
public: public:
@ -20,6 +25,7 @@ template <typename IteratorType> class iteration_proxy_value
using pointer = value_type * ; using pointer = value_type * ;
using reference = value_type & ; using reference = value_type & ;
using iterator_category = std::input_iterator_tag; using iterator_category = std::input_iterator_tag;
using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
private: private:
/// the iterator /// the iterator
@ -29,9 +35,9 @@ template <typename IteratorType> class iteration_proxy_value
/// last stringified array index /// last stringified array index
mutable std::size_t array_index_last = 0; mutable std::size_t array_index_last = 0;
/// a string representation of the array index /// a string representation of the array index
mutable std::string array_index_str = "0"; mutable string_type array_index_str = "0";
/// an empty string (to return a reference for primitive values) /// an empty string (to return a reference for primitive values)
const std::string empty_str = ""; const string_type empty_str = "";
public: public:
explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
@ -64,7 +70,7 @@ template <typename IteratorType> class iteration_proxy_value
} }
/// return key of the iterator /// return key of the iterator
const std::string& key() const const string_type& key() const
{ {
assert(anchor.m_object != nullptr); assert(anchor.m_object != nullptr);
@ -75,7 +81,7 @@ template <typename IteratorType> class iteration_proxy_value
{ {
if (array_index != array_index_last) if (array_index != array_index_last)
{ {
array_index_str = std::to_string(array_index); int_to_string( array_index_str, array_index );
array_index_last = array_index; array_index_last = array_index;
} }
return array_index_str; return array_index_str;
@ -147,6 +153,11 @@ auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decl
// And see https://github.com/nlohmann/json/pull/1391 // And see https://github.com/nlohmann/json/pull/1391
namespace std namespace std
{ {
#if defined(__clang__)
// Fix: https://github.com/nlohmann/json/issues/1401
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
template <typename IteratorType> template <typename IteratorType>
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
: public std::integral_constant<std::size_t, 2> {}; : public std::integral_constant<std::size_t, 2> {};
@ -159,4 +170,7 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
get<N>(std::declval < get<N>(std::declval <
::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
}; };
} #if defined(__clang__)
#pragma clang diagnostic pop
#endif
} // namespace std

View file

@ -13,15 +13,16 @@ template <typename It, typename = void>
struct iterator_types {}; struct iterator_types {};
template <typename It> template <typename It>
struct iterator_types< struct iterator_types <
It, It,
void_t<typename It::difference_type, typename It::value_type, typename It::pointer, void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
typename It::reference, typename It::iterator_category>> { typename It::reference, typename It::iterator_category >>
using difference_type = typename It::difference_type; {
using value_type = typename It::value_type; using difference_type = typename It::difference_type;
using pointer = typename It::pointer; using value_type = typename It::value_type;
using reference = typename It::reference; using pointer = typename It::pointer;
using iterator_category = typename It::iterator_category; using reference = typename It::reference;
using iterator_category = typename It::iterator_category;
}; };
// This is required as some compilers implement std::iterator_traits in a way that // This is required as some compilers implement std::iterator_traits in a way that
@ -32,18 +33,19 @@ struct iterator_traits
}; };
template <typename T> template <typename T>
struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>> struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
: iterator_types<T> : iterator_types<T>
{ {
}; };
template <typename T> template <typename T>
struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> { struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
using iterator_category = std::random_access_iterator_tag; {
using value_type = T; using iterator_category = std::random_access_iterator_tag;
using difference_type = ptrdiff_t; using value_type = T;
using pointer = T*; using difference_type = ptrdiff_t;
using reference = T&; using pointer = T*;
using reference = T&;
}; };
} } // namespace detail
} } // namespace nlohmann

View file

@ -2,12 +2,14 @@
#include <algorithm> // all_of #include <algorithm> // all_of
#include <cassert> // assert #include <cassert> // assert
#include <cctype> // isdigit
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string #include <string> // string
#include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
@ -55,8 +57,7 @@ class json_pointer
@return a string representation of the JSON pointer @return a string representation of the JSON pointer
@liveexample{The example shows the result of `to_string`., @liveexample{The example shows the result of `to_string`.,json_pointer__to_string}
json_pointer__to_string}
@since version 2.0.0 @since version 2.0.0
*/ */
@ -76,6 +77,249 @@ class json_pointer
return to_string(); return to_string();
} }
/*!
@brief append another JSON pointer at the end of this JSON pointer
@param[in] ptr JSON pointer to append
@return JSON pointer with @a ptr appended
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
@complexity Linear in the length of @a ptr.
@sa @ref operator/=(std::string) to append a reference token
@sa @ref operator/=(std::size_t) to append an array index
@sa @ref operator/(const json_pointer&, const json_pointer&) for a binary operator
@since version 3.6.0
*/
json_pointer& operator/=(const json_pointer& ptr)
{
reference_tokens.insert(reference_tokens.end(),
ptr.reference_tokens.begin(),
ptr.reference_tokens.end());
return *this;
}
/*!
@brief append an unescaped reference token at the end of this JSON pointer
@param[in] token reference token to append
@return JSON pointer with @a token appended without escaping @a token
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
@complexity Amortized constant.
@sa @ref operator/=(const json_pointer&) to append a JSON pointer
@sa @ref operator/=(std::size_t) to append an array index
@sa @ref operator/(const json_pointer&, std::size_t) for a binary operator
@since version 3.6.0
*/
json_pointer& operator/=(std::string token)
{
push_back(std::move(token));
return *this;
}
/*!
@brief append an array index at the end of this JSON pointer
@param[in] array_index array index to append
@return JSON pointer with @a array_index appended
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
@complexity Amortized constant.
@sa @ref operator/=(const json_pointer&) to append a JSON pointer
@sa @ref operator/=(std::string) to append a reference token
@sa @ref operator/(const json_pointer&, std::string) for a binary operator
@since version 3.6.0
*/
json_pointer& operator/=(std::size_t array_index)
{
return *this /= std::to_string(array_index);
}
/*!
@brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
@param[in] lhs JSON pointer
@param[in] rhs JSON pointer
@return a new JSON pointer with @a rhs appended to @a lhs
@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
@complexity Linear in the length of @a lhs and @a rhs.
@sa @ref operator/=(const json_pointer&) to append a JSON pointer
@since version 3.6.0
*/
friend json_pointer operator/(const json_pointer& lhs,
const json_pointer& rhs)
{
return json_pointer(lhs) /= rhs;
}
/*!
@brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
@param[in] ptr JSON pointer
@param[in] token reference token
@return a new JSON pointer with unescaped @a token appended to @a ptr
@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
@complexity Linear in the length of @a ptr.
@sa @ref operator/=(std::string) to append a reference token
@since version 3.6.0
*/
friend json_pointer operator/(const json_pointer& ptr, std::string token)
{
return json_pointer(ptr) /= std::move(token);
}
/*!
@brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
@param[in] ptr JSON pointer
@param[in] array_index array index
@return a new JSON pointer with @a array_index appended to @a ptr
@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
@complexity Linear in the length of @a ptr.
@sa @ref operator/=(std::size_t) to append an array index
@since version 3.6.0
*/
friend json_pointer operator/(const json_pointer& ptr, std::size_t array_index)
{
return json_pointer(ptr) /= array_index;
}
/*!
@brief returns the parent of this JSON pointer
@return parent of this JSON pointer; in case this JSON pointer is the root,
the root itself is returned
@complexity Linear in the length of the JSON pointer.
@liveexample{The example shows the result of `parent_pointer` for different
JSON Pointers.,json_pointer__parent_pointer}
@since version 3.6.0
*/
json_pointer parent_pointer() const
{
if (empty())
{
return *this;
}
json_pointer res = *this;
res.pop_back();
return res;
}
/*!
@brief remove last reference token
@pre not `empty()`
@liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back}
@complexity Constant.
@throw out_of_range.405 if JSON pointer has no parent
@since version 3.6.0
*/
void pop_back()
{
if (JSON_HEDLEY_UNLIKELY(empty()))
{
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
}
reference_tokens.pop_back();
}
/*!
@brief return last reference token
@pre not `empty()`
@return last reference token
@liveexample{The example shows the usage of `back`.,json_pointer__back}
@complexity Constant.
@throw out_of_range.405 if JSON pointer has no parent
@since version 3.6.0
*/
const std::string& back() const
{
if (JSON_HEDLEY_UNLIKELY(empty()))
{
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
}
return reference_tokens.back();
}
/*!
@brief append an unescaped token at the end of the reference pointer
@param[in] token token to add
@complexity Amortized constant.
@liveexample{The example shows the result of `push_back` for different
JSON Pointers.,json_pointer__push_back}
@since version 3.6.0
*/
void push_back(const std::string& token)
{
reference_tokens.push_back(token);
}
/// @copydoc push_back(const std::string&)
void push_back(std::string&& token)
{
reference_tokens.push_back(std::move(token));
}
/*!
@brief return whether pointer points to the root document
@return true iff the JSON pointer points to the root document
@complexity Constant.
@exceptionsafety No-throw guarantee: this function never throws exceptions.
@liveexample{The example shows the result of `empty` for different JSON
Pointers.,json_pointer__empty}
@since version 3.6.0
*/
bool empty() const noexcept
{
return reference_tokens.empty();
}
private:
/*! /*!
@param[in] s reference token to be converted into an array index @param[in] s reference token to be converted into an array index
@ -89,7 +333,7 @@ class json_pointer
const int res = std::stoi(s, &processed_chars); const int res = std::stoi(s, &processed_chars);
// check if the string was completely read // check if the string was completely read
if (JSON_UNLIKELY(processed_chars != s.size())) if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))
{ {
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'"));
} }
@ -97,41 +341,9 @@ class json_pointer
return res; return res;
} }
/*!
@brief remove and return last reference pointer
@throw out_of_range.405 if JSON pointer has no parent
*/
std::string pop_back()
{
if (JSON_UNLIKELY(is_root()))
{
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
}
auto last = reference_tokens.back();
reference_tokens.pop_back();
return last;
}
/*!
@brief remove and return last reference pointer
@throw out_of_range.405 if JSON pointer has no parent
*/
void push_back(const std::string& tok)
{
reference_tokens.push_back(tok);
}
private:
/// return whether pointer points to the root document
bool is_root() const noexcept
{
return reference_tokens.empty();
}
json_pointer top() const json_pointer top() const
{ {
if (JSON_UNLIKELY(is_root())) if (JSON_HEDLEY_UNLIKELY(empty()))
{ {
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
} }
@ -158,7 +370,7 @@ class json_pointer
// j which will be overwritten by a primitive value // j which will be overwritten by a primitive value
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (result->m_type) switch (result->type())
{ {
case detail::value_t::null: case detail::value_t::null:
{ {
@ -235,14 +447,14 @@ class json_pointer
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
if (ptr->m_type == detail::value_t::null) if (ptr->is_null())
{ {
// check if reference token is a number // check if reference token is a number
const bool nums = const bool nums =
std::all_of(reference_token.begin(), reference_token.end(), std::all_of(reference_token.begin(), reference_token.end(),
[](const char x) [](const unsigned char x)
{ {
return (x >= '0' and x <= '9'); return std::isdigit(x);
}); });
// change value to array for numbers or "-" or to object otherwise // change value to array for numbers or "-" or to object otherwise
@ -251,7 +463,7 @@ class json_pointer
: detail::value_t::object; : detail::value_t::object;
} }
switch (ptr->m_type) switch (ptr->type())
{ {
case detail::value_t::object: case detail::value_t::object:
{ {
@ -263,7 +475,7 @@ class json_pointer
case detail::value_t::array: case detail::value_t::array:
{ {
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
{ {
JSON_THROW(detail::parse_error::create(106, 0, JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + reference_token + "array index '" + reference_token +
@ -310,7 +522,7 @@ class json_pointer
using size_type = typename BasicJsonType::size_type; using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->m_type) switch (ptr->type())
{ {
case detail::value_t::object: case detail::value_t::object:
{ {
@ -321,7 +533,7 @@ class json_pointer
case detail::value_t::array: case detail::value_t::array:
{ {
if (JSON_UNLIKELY(reference_token == "-")) if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{ {
// "-" always fails the range check // "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, JSON_THROW(detail::out_of_range::create(402,
@ -330,7 +542,7 @@ class json_pointer
} }
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
{ {
JSON_THROW(detail::parse_error::create(106, 0, JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + reference_token + "array index '" + reference_token +
@ -375,7 +587,7 @@ class json_pointer
using size_type = typename BasicJsonType::size_type; using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->m_type) switch (ptr->type())
{ {
case detail::value_t::object: case detail::value_t::object:
{ {
@ -386,7 +598,7 @@ class json_pointer
case detail::value_t::array: case detail::value_t::array:
{ {
if (JSON_UNLIKELY(reference_token == "-")) if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{ {
// "-" cannot be used for const access // "-" cannot be used for const access
JSON_THROW(detail::out_of_range::create(402, JSON_THROW(detail::out_of_range::create(402,
@ -395,7 +607,7 @@ class json_pointer
} }
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
{ {
JSON_THROW(detail::parse_error::create(106, 0, JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + reference_token + "array index '" + reference_token +
@ -434,7 +646,7 @@ class json_pointer
using size_type = typename BasicJsonType::size_type; using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->m_type) switch (ptr->type())
{ {
case detail::value_t::object: case detail::value_t::object:
{ {
@ -445,7 +657,7 @@ class json_pointer
case detail::value_t::array: case detail::value_t::array:
{ {
if (JSON_UNLIKELY(reference_token == "-")) if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{ {
// "-" always fails the range check // "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, JSON_THROW(detail::out_of_range::create(402,
@ -454,7 +666,7 @@ class json_pointer
} }
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
{ {
JSON_THROW(detail::parse_error::create(106, 0, JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + reference_token + "array index '" + reference_token +
@ -481,6 +693,77 @@ class json_pointer
return *ptr; return *ptr;
} }
/*!
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
*/
bool contains(const BasicJsonType* ptr) const
{
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
if (not ptr->contains(reference_token))
{
// we did not find the key in the object
return false;
}
ptr = &ptr->operator[](reference_token);
break;
}
case detail::value_t::array:
{
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" always fails the range check
return false;
}
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
{
JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + reference_token +
"' must not begin with '0'"));
}
JSON_TRY
{
const auto idx = static_cast<size_type>(array_index(reference_token));
if (idx >= ptr->size())
{
// index out of range
return false;
}
ptr = &ptr->operator[](idx);
break;
}
JSON_CATCH(std::invalid_argument&)
{
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
}
break;
}
default:
{
// we do not expect primitive values if there is still a
// reference token to process
return false;
}
}
}
// no reference token left means we found a primitive value
return true;
}
/*! /*!
@brief split the string input to reference tokens @brief split the string input to reference tokens
@ -501,7 +784,7 @@ class json_pointer
} }
// check if nonempty reference string begins with slash // check if nonempty reference string begins with slash
if (JSON_UNLIKELY(reference_string[0] != '/')) if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
{ {
JSON_THROW(detail::parse_error::create(107, 1, JSON_THROW(detail::parse_error::create(107, 1,
"JSON pointer must be empty or begin with '/' - was: '" + "JSON pointer must be empty or begin with '/' - was: '" +
@ -536,9 +819,9 @@ class json_pointer
assert(reference_token[pos] == '~'); assert(reference_token[pos] == '~');
// ~ must be followed by 0 or 1 // ~ must be followed by 0 or 1
if (JSON_UNLIKELY(pos == reference_token.size() - 1 or if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or
(reference_token[pos + 1] != '0' and (reference_token[pos + 1] != '0' and
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'"));
} }
@ -602,7 +885,7 @@ class json_pointer
const BasicJsonType& value, const BasicJsonType& value,
BasicJsonType& result) BasicJsonType& result)
{ {
switch (value.m_type) switch (value.type())
{ {
case detail::value_t::array: case detail::value_t::array:
{ {
@ -663,7 +946,7 @@ class json_pointer
static BasicJsonType static BasicJsonType
unflatten(const BasicJsonType& value) unflatten(const BasicJsonType& value)
{ {
if (JSON_UNLIKELY(not value.is_object())) if (JSON_HEDLEY_UNLIKELY(not 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"));
} }
@ -673,7 +956,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_UNLIKELY(not element.second.is_primitive())) if (JSON_HEDLEY_UNLIKELY(not 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"));
} }
@ -688,12 +971,34 @@ class json_pointer
return result; return result;
} }
/*!
@brief compares two JSON pointers for equality
@param[in] lhs JSON pointer to compare
@param[in] rhs JSON pointer to compare
@return whether @a lhs is equal to @a rhs
@complexity Linear in the length of the JSON pointer
@exceptionsafety No-throw guarantee: this function never throws exceptions.
*/
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 (lhs.reference_tokens == rhs.reference_tokens); return lhs.reference_tokens == rhs.reference_tokens;
} }
/*!
@brief compares two JSON pointers for inequality
@param[in] lhs JSON pointer to compare
@param[in] rhs JSON pointer to compare
@return whether @a lhs is not equal @a rhs
@complexity Linear in the length of the JSON pointer
@exceptionsafety No-throw guarantee: this function never throws exceptions.
*/
friend bool operator!=(json_pointer const& lhs, friend bool operator!=(json_pointer const& lhs,
json_pointer const& rhs) noexcept json_pointer const& rhs) noexcept
{ {

View file

@ -1,5 +1,8 @@
#pragma once #pragma once
#include <utility> // pair
#include <nlohmann/thirdparty/hedley/hedley.hpp>
// This file contains all internal macro definitions // This file contains all internal macro definitions
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
@ -16,6 +19,14 @@
#endif #endif
#endif #endif
// C++ language standard detection
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
#define JSON_HAS_CPP_14
#endif
// disable float-equal warnings on GCC/clang // disable float-equal warnings on GCC/clang
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -28,28 +39,6 @@
#pragma GCC diagnostic ignored "-Wdocumentation" #pragma GCC diagnostic ignored "-Wdocumentation"
#endif #endif
// allow for portable deprecation warnings
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#define JSON_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define JSON_DEPRECATED __declspec(deprecated)
#else
#define JSON_DEPRECATED
#endif
// allow for portable nodiscard warnings
#if defined(__has_cpp_attribute)
#if __has_cpp_attribute(nodiscard)
#define JSON_NODISCARD [[nodiscard]]
#elif __has_cpp_attribute(gnu::warn_unused_result)
#define JSON_NODISCARD [[gnu::warn_unused_result]]
#else
#define JSON_NODISCARD
#endif
#else
#define JSON_NODISCARD
#endif
// allow to disable exceptions // allow to disable exceptions
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
#define JSON_THROW(exception) throw exception #define JSON_THROW(exception) throw exception
@ -57,6 +46,7 @@
#define JSON_CATCH(exception) catch(exception) #define JSON_CATCH(exception) catch(exception)
#define JSON_INTERNAL_CATCH(exception) catch(exception) #define JSON_INTERNAL_CATCH(exception) catch(exception)
#else #else
#include <cstdlib>
#define JSON_THROW(exception) std::abort() #define JSON_THROW(exception) std::abort()
#define JSON_TRY if(true) #define JSON_TRY if(true)
#define JSON_CATCH(exception) if(false) #define JSON_CATCH(exception) if(false)
@ -83,52 +73,35 @@
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
#endif #endif
// manual branch prediction
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#define JSON_LIKELY(x) __builtin_expect(!!(x), 1)
#define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define JSON_LIKELY(x) x
#define JSON_UNLIKELY(x) x
#endif
// C++ language standard detection
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
#define JSON_HAS_CPP_14
#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
@since version 3.4.0 @since version 3.4.0
*/ */
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ #define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
template<typename BasicJsonType> \ template<typename BasicJsonType> \
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
{ \ { \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \ auto it = std::find_if(std::begin(m), std::end(m), \
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
{ \ { \
return ej_pair.first == e; \ return ej_pair.first == e; \
}); \ }); \
j = ((it != std::end(m)) ? it : std::begin(m))->second; \ j = ((it != std::end(m)) ? it : std::begin(m))->second; \
} \ } \
template<typename BasicJsonType> \ template<typename BasicJsonType> \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
{ \ { \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \ auto it = std::find_if(std::begin(m), std::end(m), \
[j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
{ \ { \
return ej_pair.second == j; \ return ej_pair.second == j; \
}); \ }); \
e = ((it != std::end(m)) ? it : std::begin(m))->first; \ e = ((it != std::end(m)) ? it : std::begin(m))->first; \
} }
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They // Ugly macros to avoid uglier copy-paste when specializing basic_json. They

View file

@ -13,11 +13,9 @@
#undef JSON_CATCH #undef JSON_CATCH
#undef JSON_THROW #undef JSON_THROW
#undef JSON_TRY #undef JSON_TRY
#undef JSON_LIKELY
#undef JSON_UNLIKELY
#undef JSON_DEPRECATED
#undef JSON_NODISCARD
#undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_14
#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
#include <nlohmann/thirdparty/hedley/hedley_undef.hpp>

View file

@ -14,7 +14,9 @@ struct nonesuch
nonesuch() = delete; nonesuch() = delete;
~nonesuch() = delete; ~nonesuch() = delete;
nonesuch(nonesuch const&) = delete; nonesuch(nonesuch const&) = delete;
nonesuch(nonesuch const&&) = delete;
void operator=(nonesuch const&) = delete; void operator=(nonesuch const&) = delete;
void operator=(nonesuch&&) = delete;
}; };
template <class Default, template <class Default,

View file

@ -2,6 +2,7 @@
#include <cstdint> // size_t #include <cstdint> // size_t
#include <utility> // declval #include <utility> // declval
#include <string> // string
#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
@ -23,119 +24,119 @@ using number_integer_function_t =
template <typename T, typename Unsigned> template <typename T, typename Unsigned>
using number_unsigned_function_t = using number_unsigned_function_t =
decltype(std::declval<T &>().number_unsigned(std::declval<Unsigned>())); decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
template <typename T, typename Float, typename String> template <typename T, typename Float, typename String>
using number_float_function_t = decltype(std::declval<T &>().number_float( using number_float_function_t = decltype(std::declval<T&>().number_float(
std::declval<Float>(), std::declval<const String &>())); std::declval<Float>(), std::declval<const String&>()));
template <typename T, typename String> 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> 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>()));
template <typename T, typename String> template <typename T, typename String>
using key_function_t = using key_function_t =
decltype(std::declval<T &>().key(std::declval<String &>())); decltype(std::declval<T&>().key(std::declval<String&>()));
template <typename T> template <typename T>
using end_object_function_t = decltype(std::declval<T &>().end_object()); using end_object_function_t = decltype(std::declval<T&>().end_object());
template <typename T> template <typename T>
using start_array_function_t = using start_array_function_t =
decltype(std::declval<T &>().start_array(std::declval<std::size_t>())); decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
template <typename T> template <typename T>
using end_array_function_t = decltype(std::declval<T &>().end_array()); using end_array_function_t = decltype(std::declval<T&>().end_array());
template <typename T, typename Exception> template <typename T, typename Exception>
using parse_error_function_t = decltype(std::declval<T &>().parse_error( using parse_error_function_t = decltype(std::declval<T&>().parse_error(
std::declval<std::size_t>(), std::declval<const std::string &>(), std::declval<std::size_t>(), std::declval<const std::string&>(),
std::declval<const Exception &>())); std::declval<const Exception&>()));
template <typename SAX, typename BasicJsonType> template <typename SAX, typename BasicJsonType>
struct is_sax struct is_sax
{ {
private: private:
static_assert(is_basic_json<BasicJsonType>::value, static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>"); "BasicJsonType must be of type basic_json<...>");
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
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 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, is_detected_exact<bool, number_unsigned_function_t, SAX,
number_unsigned_t>::value && number_unsigned_t>::value &&
is_detected_exact<bool, number_float_function_t, SAX, number_float_t, is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
string_t>::value && 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, 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 &&
is_detected_exact<bool, start_array_function_t, SAX>::value && is_detected_exact<bool, start_array_function_t, SAX>::value &&
is_detected_exact<bool, end_array_function_t, SAX>::value && is_detected_exact<bool, end_array_function_t, SAX>::value &&
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value; is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
}; };
template <typename SAX, typename BasicJsonType> template <typename SAX, typename BasicJsonType>
struct is_sax_static_asserts struct is_sax_static_asserts
{ {
private: private:
static_assert(is_basic_json<BasicJsonType>::value, static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>"); "BasicJsonType must be of type basic_json<...>");
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
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 exception_t = typename BasicJsonType::exception; using exception_t = typename BasicJsonType::exception;
public: public:
static_assert(is_detected_exact<bool, null_function_t, SAX>::value, static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
"Missing/invalid function: bool null()"); "Missing/invalid function: bool null()");
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)"); "Missing/invalid function: bool boolean(bool)");
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)"); "Missing/invalid function: bool boolean(bool)");
static_assert( static_assert(
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,
"Missing/invalid function: bool number_integer(number_integer_t)"); "Missing/invalid function: bool number_integer(number_integer_t)");
static_assert( static_assert(
is_detected_exact<bool, number_unsigned_function_t, SAX, is_detected_exact<bool, number_unsigned_function_t, SAX,
number_unsigned_t>::value, number_unsigned_t>::value,
"Missing/invalid function: bool number_unsigned(number_unsigned_t)"); "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
static_assert(is_detected_exact<bool, number_float_function_t, SAX, static_assert(is_detected_exact<bool, number_float_function_t, SAX,
number_float_t, string_t>::value, number_float_t, string_t>::value,
"Missing/invalid function: bool number_float(number_float_t, const string_t&)"); "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
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, 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,
"Missing/invalid function: bool key(string_t&)"); "Missing/invalid function: bool key(string_t&)");
static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value, static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
"Missing/invalid function: bool end_object()"); "Missing/invalid function: bool end_object()");
static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value, static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
"Missing/invalid function: bool start_array(std::size_t)"); "Missing/invalid function: bool start_array(std::size_t)");
static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value, static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
"Missing/invalid function: bool end_array()"); "Missing/invalid function: bool end_array()");
static_assert( static_assert(
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value, is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
"Missing/invalid function: bool parse_error(std::size_t, const " "Missing/invalid function: bool parse_error(std::size_t, const "
"std::string&, const exception&)"); "std::string&, const exception&)");
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

View file

@ -5,11 +5,11 @@
#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/json_fwd.hpp>
#include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/json_fwd.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -192,10 +192,19 @@ struct is_constructible_object_type_impl <
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
static constexpr bool value = static constexpr bool value =
(std::is_constructible<typename ConstructibleObjectType::key_type, typename object_t::key_type>::value and (std::is_default_constructible<ConstructibleObjectType>::value and
std::is_same<typename object_t::mapped_type, typename ConstructibleObjectType::mapped_type>::value) or (std::is_move_assignable<ConstructibleObjectType>::value or
(has_from_json<BasicJsonType, typename ConstructibleObjectType::mapped_type>::value or std::is_copy_assignable<ConstructibleObjectType>::value) and
has_non_default_from_json<BasicJsonType, typename ConstructibleObjectType::mapped_type >::value); (std::is_constructible<typename ConstructibleObjectType::key_type,
typename object_t::key_type>::value and
std::is_same <
typename object_t::mapped_type,
typename ConstructibleObjectType::mapped_type >::value)) or
(has_from_json<BasicJsonType,
typename ConstructibleObjectType::mapped_type>::value or
has_non_default_from_json <
BasicJsonType,
typename ConstructibleObjectType::mapped_type >::value);
}; };
template <typename BasicJsonType, typename ConstructibleObjectType> template <typename BasicJsonType, typename ConstructibleObjectType>
@ -278,20 +287,24 @@ struct is_constructible_array_type_impl <
BasicJsonType, ConstructibleArrayType, BasicJsonType, ConstructibleArrayType,
enable_if_t<not std::is_same<ConstructibleArrayType, enable_if_t<not std::is_same<ConstructibleArrayType,
typename BasicJsonType::value_type>::value and typename BasicJsonType::value_type>::value and
is_detected<value_type_t, ConstructibleArrayType>::value and std::is_default_constructible<ConstructibleArrayType>::value and
is_detected<iterator_t, ConstructibleArrayType>::value and (std::is_move_assignable<ConstructibleArrayType>::value or
is_complete_type< std::is_copy_assignable<ConstructibleArrayType>::value) and
detected_t<value_type_t, ConstructibleArrayType>>::value >> is_detected<value_type_t, ConstructibleArrayType>::value and
is_detected<iterator_t, ConstructibleArrayType>::value and
is_complete_type<
detected_t<value_type_t, ConstructibleArrayType>>::value >>
{ {
static constexpr bool value = static constexpr bool value =
// This is needed because json_reverse_iterator has a ::iterator type, // This is needed because json_reverse_iterator has a ::iterator type,
// furthermore, std::back_insert_iterator (and other iterators) have a base class `iterator`... // furthermore, std::back_insert_iterator (and other iterators) have a
// Therefore it is detected as a ConstructibleArrayType. // base class `iterator`... Therefore it is detected as a
// The real fix would be to have an Iterable concept. // ConstructibleArrayType. The real fix would be to have an Iterable
not is_iterator_traits < // concept.
iterator_traits<ConstructibleArrayType >>::value and not is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value and
(std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or (std::is_same<typename ConstructibleArrayType::value_type,
typename BasicJsonType::array_t::value_type>::value or
has_from_json<BasicJsonType, has_from_json<BasicJsonType,
typename ConstructibleArrayType::value_type>::value or typename ConstructibleArrayType::value_type>::value or
has_non_default_from_json < has_non_default_from_json <
@ -344,5 +357,18 @@ struct is_compatible_type_impl <
template <typename BasicJsonType, typename CompatibleType> template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type struct is_compatible_type
: is_compatible_type_impl<BasicJsonType, CompatibleType> {}; : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
// https://en.cppreference.com/w/cpp/types/conjunction
template<class...> struct conjunction : std::true_type { };
template<class B1> struct conjunction<B1> : B1 { };
template<class B1, class... Bn>
struct conjunction<B1, Bn...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template <typename T1, typename T2>
struct is_constructible_tuple : std::false_type {};
template <typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {};
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

View file

@ -5,8 +5,10 @@
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <cstring> // memcpy #include <cstring> // memcpy
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string
#include <nlohmann/detail/input/binary_reader.hpp> #include <nlohmann/detail/input/binary_reader.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/output/output_adapters.hpp> #include <nlohmann/detail/output/output_adapters.hpp>
namespace nlohmann namespace nlohmann
@ -87,27 +89,27 @@ class binary_writer
// code from the value_t::number_unsigned case here. // code from the value_t::number_unsigned case here.
if (j.m_value.number_integer <= 0x17) if (j.m_value.number_integer <= 0x17)
{ {
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x18)); oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x19)); oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x1A)); oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else else
{ {
oa->write_character(to_char_type(0x1B)); oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
} }
else else
@ -117,27 +119,27 @@ class binary_writer
const auto positive_number = -1 - j.m_value.number_integer; const auto positive_number = -1 - j.m_value.number_integer;
if (j.m_value.number_integer >= -24) if (j.m_value.number_integer >= -24)
{ {
write_number(static_cast<uint8_t>(0x20 + positive_number)); write_number(static_cast<std::uint8_t>(0x20 + positive_number));
} }
else if (positive_number <= (std::numeric_limits<uint8_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x38)); oa->write_character(to_char_type(0x38));
write_number(static_cast<uint8_t>(positive_number)); write_number(static_cast<std::uint8_t>(positive_number));
} }
else if (positive_number <= (std::numeric_limits<uint16_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x39)); oa->write_character(to_char_type(0x39));
write_number(static_cast<uint16_t>(positive_number)); write_number(static_cast<std::uint16_t>(positive_number));
} }
else if (positive_number <= (std::numeric_limits<uint32_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x3A)); oa->write_character(to_char_type(0x3A));
write_number(static_cast<uint32_t>(positive_number)); write_number(static_cast<std::uint32_t>(positive_number));
} }
else else
{ {
oa->write_character(to_char_type(0x3B)); oa->write_character(to_char_type(0x3B));
write_number(static_cast<uint64_t>(positive_number)); write_number(static_cast<std::uint64_t>(positive_number));
} }
} }
break; break;
@ -147,27 +149,27 @@ class binary_writer
{ {
if (j.m_value.number_unsigned <= 0x17) if (j.m_value.number_unsigned <= 0x17)
{ {
write_number(static_cast<uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x18)); oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x19)); oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x1A)); oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
} }
else else
{ {
oa->write_character(to_char_type(0x1B)); oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
} }
break; break;
} }
@ -185,28 +187,28 @@ class binary_writer
const auto N = j.m_value.string->size(); const auto N = j.m_value.string->size();
if (N <= 0x17) if (N <= 0x17)
{ {
write_number(static_cast<uint8_t>(0x60 + N)); write_number(static_cast<std::uint8_t>(0x60 + N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x78)); oa->write_character(to_char_type(0x78));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x79)); oa->write_character(to_char_type(0x79));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x7A)); oa->write_character(to_char_type(0x7A));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x7B)); oa->write_character(to_char_type(0x7B));
write_number(static_cast<uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -223,28 +225,28 @@ class binary_writer
const auto N = j.m_value.array->size(); const auto N = j.m_value.array->size();
if (N <= 0x17) if (N <= 0x17)
{ {
write_number(static_cast<uint8_t>(0x80 + N)); write_number(static_cast<std::uint8_t>(0x80 + N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x98)); oa->write_character(to_char_type(0x98));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x99)); oa->write_character(to_char_type(0x99));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x9A)); oa->write_character(to_char_type(0x9A));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x9B)); oa->write_character(to_char_type(0x9B));
write_number(static_cast<uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -262,28 +264,28 @@ class binary_writer
const auto N = j.m_value.object->size(); const auto N = j.m_value.object->size();
if (N <= 0x17) if (N <= 0x17)
{ {
write_number(static_cast<uint8_t>(0xA0 + N)); write_number(static_cast<std::uint8_t>(0xA0 + N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0xB8)); oa->write_character(to_char_type(0xB8));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0xB9)); oa->write_character(to_char_type(0xB9));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0xBA)); oa->write_character(to_char_type(0xBA));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0xBB)); oa->write_character(to_char_type(0xBB));
write_number(static_cast<uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -332,31 +334,31 @@ class binary_writer
if (j.m_value.number_unsigned < 128) if (j.m_value.number_unsigned < 128)
{ {
// positive fixnum // positive fixnum
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(to_char_type(0xCC)); oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(to_char_type(0xCD)); oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(to_char_type(0xCE)); oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(to_char_type(0xCF)); oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
} }
else else
@ -364,35 +366,35 @@ class binary_writer
if (j.m_value.number_integer >= -32) if (j.m_value.number_integer >= -32)
{ {
// negative fixnum // negative fixnum
write_number(static_cast<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<int8_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<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<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<int16_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<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<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<int32_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<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<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<int64_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{ {
// int 64 // int 64
oa->write_character(to_char_type(0xD3)); oa->write_character(to_char_type(0xD3));
write_number(static_cast<int64_t>(j.m_value.number_integer)); write_number(static_cast<std::int64_t>(j.m_value.number_integer));
} }
} }
break; break;
@ -403,31 +405,31 @@ class binary_writer
if (j.m_value.number_unsigned < 128) if (j.m_value.number_unsigned < 128)
{ {
// positive fixnum // positive fixnum
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(to_char_type(0xCC)); oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(to_char_type(0xCD)); oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(to_char_type(0xCE)); oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(to_char_type(0xCF)); oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
break; break;
} }
@ -446,25 +448,25 @@ class binary_writer
if (N <= 31) if (N <= 31)
{ {
// fixstr // fixstr
write_number(static_cast<uint8_t>(0xA0 | N)); write_number(static_cast<std::uint8_t>(0xA0 | N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// str 8 // str 8
oa->write_character(to_char_type(0xD9)); oa->write_character(to_char_type(0xD9));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// str 16 // str 16
oa->write_character(to_char_type(0xDA)); oa->write_character(to_char_type(0xDA));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// str 32 // str 32
oa->write_character(to_char_type(0xDB)); oa->write_character(to_char_type(0xDB));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write the string // step 2: write the string
@ -481,19 +483,19 @@ class binary_writer
if (N <= 15) if (N <= 15)
{ {
// fixarray // fixarray
write_number(static_cast<uint8_t>(0x90 | N)); write_number(static_cast<std::uint8_t>(0x90 | N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// array 16 // array 16
oa->write_character(to_char_type(0xDC)); oa->write_character(to_char_type(0xDC));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// array 32 // array 32
oa->write_character(to_char_type(0xDD)); oa->write_character(to_char_type(0xDD));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write each element // step 2: write each element
@ -511,19 +513,19 @@ class binary_writer
if (N <= 15) if (N <= 15)
{ {
// fixmap // fixmap
write_number(static_cast<uint8_t>(0x80 | (N & 0xF))); write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// map 16 // map 16
oa->write_character(to_char_type(0xDE)); oa->write_character(to_char_type(0xDE));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// map 32 // map 32
oa->write_character(to_char_type(0xDF)); oa->write_character(to_char_type(0xDF));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write each element // step 2: write each element
@ -713,7 +715,7 @@ class binary_writer
static std::size_t calc_bson_entry_header_size(const string_t& name) static std::size_t calc_bson_entry_header_size(const string_t& name)
{ {
const auto it = name.find(static_cast<typename string_t::value_type>(0)); const auto it = name.find(static_cast<typename string_t::value_type>(0));
if (JSON_UNLIKELY(it != BasicJsonType::string_t::npos)) if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
{ {
JSON_THROW(out_of_range::create(409, JSON_THROW(out_of_range::create(409,
"BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")")); "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")"));
@ -789,14 +791,9 @@ 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)
{ {
if ((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 and value <= (std::numeric_limits<std::int32_t>::max)()
{ ? sizeof(std::int32_t)
return sizeof(std::int32_t); : sizeof(std::int64_t);
}
else
{
return sizeof(std::int64_t);
}
} }
/*! /*!
@ -864,13 +861,12 @@ class binary_writer
*/ */
static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
{ {
std::size_t embedded_document_size = 0ul;
std::size_t array_index = 0ul; std::size_t array_index = 0ul;
for (const auto& el : value) const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), 0ul, [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
{ {
embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el); return result + calc_bson_element_size(std::to_string(array_index++), el);
} });
return sizeof(std::int32_t) + embedded_document_size + 1ul; return sizeof(std::int32_t) + embedded_document_size + 1ul;
} }
@ -1064,45 +1060,45 @@ class binary_writer
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 (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)())) if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('i')); // int8 oa->write_character(to_char_type('i')); // int8
} }
write_number(static_cast<uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if (n <= (std::numeric_limits<uint8_t>::max)()) else if (n <= (std::numeric_limits<std::uint8_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('U')); // uint8 oa->write_character(to_char_type('U')); // uint8
} }
write_number(static_cast<uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)())) else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('I')); // int16 oa->write_character(to_char_type('I')); // int16
} }
write_number(static_cast<int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)())) else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('l')); // int32 oa->write_character(to_char_type('l')); // int32
} }
write_number(static_cast<int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('L')); // int64 oa->write_character(to_char_type('L')); // int64
} }
write_number(static_cast<int64_t>(n)); write_number(static_cast<std::int64_t>(n));
} }
else else
{ {
@ -1117,45 +1113,45 @@ class binary_writer
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<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('i')); // int8 oa->write_character(to_char_type('i')); // int8
} }
write_number(static_cast<int8_t>(n)); write_number(static_cast<std::int8_t>(n));
} }
else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)())) 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)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('U')); // uint8 oa->write_character(to_char_type('U')); // uint8
} }
write_number(static_cast<uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)()) else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('I')); // int16 oa->write_character(to_char_type('I')); // int16
} }
write_number(static_cast<int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)()) else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('l')); // int32 oa->write_character(to_char_type('l')); // int32
} }
write_number(static_cast<int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)()) else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('L')); // int64 oa->write_character(to_char_type('L')); // int64
} }
write_number(static_cast<int64_t>(n)); write_number(static_cast<std::int64_t>(n));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else else
@ -1186,19 +1182,19 @@ class binary_writer
case value_t::number_integer: case value_t::number_integer:
{ {
if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)()) 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)())
{ {
return 'i'; return 'i';
} }
if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)()) 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)())
{ {
return 'U'; return 'U';
} }
if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)()) 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)())
{ {
return 'I'; return 'I';
} }
if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)()) 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)())
{ {
return 'l'; return 'l';
} }
@ -1208,19 +1204,19 @@ class binary_writer
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)()) if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
{ {
return 'i'; return 'i';
} }
if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
{ {
return 'U'; return 'U';
} }
if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)()) if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
{ {
return 'I'; return 'I';
} }
if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)()) if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{ {
return 'l'; return 'l';
} }
@ -1278,7 +1274,7 @@ class binary_writer
std::memcpy(vec.data(), &n, sizeof(NumberType)); std::memcpy(vec.data(), &n, sizeof(NumberType));
// step 2: write array to output (with possible reordering) // step 2: write array to output (with possible reordering)
if (is_little_endian and not OutputIsLittleEndian) if (is_little_endian != OutputIsLittleEndian)
{ {
// reverse byte order prior to conversion if necessary // reverse byte order prior to conversion if necessary
std::reverse(vec.begin(), vec.end()); std::reverse(vec.begin(), vec.end());

View file

@ -8,6 +8,7 @@
#include <ostream> // basic_ostream #include <ostream> // basic_ostream
#include <string> // basic_string #include <string> // basic_string
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -39,6 +40,7 @@ class output_vector_adapter : public output_adapter_protocol<CharType>
v.push_back(c); v.push_back(c);
} }
JSON_HEDLEY_NON_NULL(2)
void write_characters(const CharType* s, std::size_t length) override void write_characters(const CharType* s, std::size_t length) override
{ {
std::copy(s, s + length, std::back_inserter(v)); std::copy(s, s + length, std::back_inserter(v));
@ -62,6 +64,7 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
stream.put(c); stream.put(c);
} }
JSON_HEDLEY_NON_NULL(2)
void write_characters(const CharType* s, std::size_t length) override void write_characters(const CharType* s, std::size_t length) override
{ {
stream.write(s, static_cast<std::streamsize>(length)); stream.write(s, static_cast<std::streamsize>(length));
@ -85,6 +88,7 @@ class output_string_adapter : public output_adapter_protocol<CharType>
str.push_back(c); str.push_back(c);
} }
JSON_HEDLEY_NON_NULL(2)
void write_characters(const CharType* s, std::size_t length) override void write_characters(const CharType* s, std::size_t length) override
{ {
str.append(s, length); str.append(s, length);

View file

@ -12,9 +12,10 @@
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string #include <string> // string
#include <type_traits> // is_same #include <type_traits> // is_same
#include <utility> // move
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/conversions/to_chars.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>
#include <nlohmann/detail/output/binary_writer.hpp> #include <nlohmann/detail/output/binary_writer.hpp>
@ -44,8 +45,8 @@ class serializer
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
static constexpr uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_ACCEPT = 0;
static constexpr uint8_t UTF8_REJECT = 1; static constexpr std::uint8_t UTF8_REJECT = 1;
public: public:
/*! /*!
@ -109,7 +110,7 @@ class serializer
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + indent_step;
if (JSON_UNLIKELY(indent_string.size() < new_indent)) if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
{ {
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
} }
@ -182,7 +183,7 @@ class serializer
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + indent_step;
if (JSON_UNLIKELY(indent_string.size() < new_indent)) if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
{ {
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
} }
@ -277,6 +278,9 @@ class serializer
o->write_characters("null", 4); o->write_characters("null", 4);
return; return;
} }
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
} }
@ -297,8 +301,8 @@ class serializer
*/ */
void dump_escaped(const string_t& s, const bool ensure_ascii) void dump_escaped(const string_t& s, const bool ensure_ascii)
{ {
uint32_t codepoint; std::uint32_t codepoint;
uint8_t state = UTF8_ACCEPT; std::uint8_t state = UTF8_ACCEPT;
std::size_t bytes = 0; // number of bytes written to string_buffer std::size_t bytes = 0; // number of bytes written to string_buffer
// number of bytes written at the point of the last valid byte // number of bytes written at the point of the last valid byte
@ -373,14 +377,14 @@ class serializer
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
(std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<uint16_t>(codepoint)); static_cast<std::uint16_t>(codepoint));
bytes += 6; bytes += 6;
} }
else else
{ {
(std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)), static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF))); static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
bytes += 12; bytes += 12;
} }
} }
@ -473,6 +477,9 @@ class serializer
state = UTF8_ACCEPT; state = UTF8_ACCEPT;
break; break;
} }
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
break; break;
} }
@ -491,7 +498,7 @@ class serializer
} }
// we finished processing the string // we finished processing the string
if (JSON_LIKELY(state == UTF8_ACCEPT)) if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
{ {
// write buffer // write buffer
if (bytes > 0) if (bytes > 0)
@ -507,7 +514,7 @@ class serializer
case error_handler_t::strict: case error_handler_t::strict:
{ {
std::string sn(3, '\0'); std::string sn(3, '\0');
(std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back())); (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<std::uint8_t>(s.back()));
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
} }
@ -533,6 +540,9 @@ class serializer
} }
break; break;
} }
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
} }
} }
@ -589,16 +599,16 @@ class serializer
static constexpr std::array<std::array<char, 2>, 100> digits_to_99 static constexpr std::array<std::array<char, 2>, 100> digits_to_99
{ {
{ {
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
{'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'}, {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
{'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
{'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
{'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'}, {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
{'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
{'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
{'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'}, {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
{'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}, {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
} }
}; };
@ -610,7 +620,7 @@ class serializer
} }
// use a pointer to fill the buffer // use a pointer to fill the buffer
auto buffer_ptr = begin(number_buffer); 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 and not(x >= 0); // see issue #755
number_unsigned_t abs_value; number_unsigned_t abs_value;
@ -620,7 +630,7 @@ class serializer
if (is_negative) if (is_negative)
{ {
*buffer_ptr = '-'; *buffer_ptr = '-';
abs_value = static_cast<number_unsigned_t>(-1 - x) + 1; abs_value = remove_sign(x);
// account one more byte for the minus sign // account one more byte for the minus sign
n_chars = 1 + count_digits(abs_value); n_chars = 1 + count_digits(abs_value);
@ -739,7 +749,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 == '.' or c == 'e';
}); });
if (value_is_int_like) if (value_is_int_like)
@ -769,9 +779,9 @@ class serializer
@copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
@sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
*/ */
static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
{ {
static const std::array<uint8_t, 400> utf8d = static const std::array<std::uint8_t, 400> utf8d =
{ {
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
@ -791,16 +801,42 @@ class serializer
} }
}; };
const uint8_t type = utf8d[byte]; const std::uint8_t type = utf8d[byte];
codep = (state != UTF8_ACCEPT) codep = (state != UTF8_ACCEPT)
? (byte & 0x3fu) | (codep << 6) ? (byte & 0x3fu) | (codep << 6u)
: static_cast<uint32_t>(0xff >> type) & (byte); : (0xFFu >> type) & (byte);
state = utf8d[256u + state * 16u + type]; state = utf8d[256u + state * 16u + type];
return state; return state;
} }
/*
* Overload to make the compiler happy while it is instantiating
* dump_integer for number_unsigned_t.
* Must never be called.
*/
number_unsigned_t remove_sign(number_unsigned_t x)
{
assert(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE
}
/*
* Helper function for dump_integer
*
* This function takes a negative signed integer and returns its absolute
* value as unsigned integer. The plus/minus shuffling is necessary as we can
* not directly remove the sign of an arbitrary signed integer as the
* absolute values of INT_MIN and INT_MAX are usually not the same. See
* #1708 for details.
*/
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
}
private: private:
/// the output of the serializer /// the output of the serializer
output_adapter_t<char> o = nullptr; output_adapter_t<char> o = nullptr;

View file

@ -4,6 +4,7 @@
#include <ciso646> // and #include <ciso646> // and
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <string> // string
namespace nlohmann namespace nlohmann
{ {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
#ifndef NLOHMANN_JSON_FWD_HPP #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
#define NLOHMANN_JSON_FWD_HPP #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
#include <cstdint> // int64_t, uint64_t #include <cstdint> // int64_t, uint64_t
#include <map> // map #include <map> // map
@ -61,4 +61,4 @@ uses the standard template types.
using json = basic_json<>; using json = basic_json<>;
} // namespace nlohmann } // namespace nlohmann
#endif #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
#undef JSON_HEDLEY_ALWAYS_INLINE
#undef JSON_HEDLEY_ARM_VERSION
#undef JSON_HEDLEY_ARM_VERSION_CHECK
#undef JSON_HEDLEY_ARRAY_PARAM
#undef JSON_HEDLEY_ASSUME
#undef JSON_HEDLEY_BEGIN_C_DECLS
#undef JSON_HEDLEY_C_DECL
#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
#undef JSON_HEDLEY_CLANG_HAS_FEATURE
#undef JSON_HEDLEY_CLANG_HAS_WARNING
#undef JSON_HEDLEY_COMPCERT_VERSION
#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
#undef JSON_HEDLEY_CONCAT
#undef JSON_HEDLEY_CONCAT_EX
#undef JSON_HEDLEY_CONST
#undef JSON_HEDLEY_CONST_CAST
#undef JSON_HEDLEY_CONSTEXPR
#undef JSON_HEDLEY_CPP_CAST
#undef JSON_HEDLEY_CRAY_VERSION
#undef JSON_HEDLEY_CRAY_VERSION_CHECK
#undef JSON_HEDLEY_DEPRECATED
#undef JSON_HEDLEY_DEPRECATED_FOR
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
#undef JSON_HEDLEY_DIAGNOSTIC_POP
#undef JSON_HEDLEY_DIAGNOSTIC_PUSH
#undef JSON_HEDLEY_DMC_VERSION
#undef JSON_HEDLEY_DMC_VERSION_CHECK
#undef JSON_HEDLEY_EMPTY_BASES
#undef JSON_HEDLEY_EMSCRIPTEN_VERSION
#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
#undef JSON_HEDLEY_END_C_DECLS
#undef JSON_HEDLEY_FALL_THROUGH
#undef JSON_HEDLEY_FLAGS
#undef JSON_HEDLEY_FLAGS_CAST
#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
#undef JSON_HEDLEY_GCC_HAS_BUILTIN
#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
#undef JSON_HEDLEY_GCC_HAS_EXTENSION
#undef JSON_HEDLEY_GCC_HAS_FEATURE
#undef JSON_HEDLEY_GCC_HAS_WARNING
#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
#undef JSON_HEDLEY_GCC_VERSION
#undef JSON_HEDLEY_GCC_VERSION_CHECK
#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
#undef JSON_HEDLEY_GNUC_HAS_BUILTIN
#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
#undef JSON_HEDLEY_GNUC_HAS_EXTENSION
#undef JSON_HEDLEY_GNUC_HAS_FEATURE
#undef JSON_HEDLEY_GNUC_HAS_WARNING
#undef JSON_HEDLEY_GNUC_VERSION
#undef JSON_HEDLEY_GNUC_VERSION_CHECK
#undef JSON_HEDLEY_HAS_ATTRIBUTE
#undef JSON_HEDLEY_HAS_BUILTIN
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
#undef JSON_HEDLEY_HAS_EXTENSION
#undef JSON_HEDLEY_HAS_FEATURE
#undef JSON_HEDLEY_HAS_WARNING
#undef JSON_HEDLEY_IAR_VERSION
#undef JSON_HEDLEY_IAR_VERSION_CHECK
#undef JSON_HEDLEY_IBM_VERSION
#undef JSON_HEDLEY_IBM_VERSION_CHECK
#undef JSON_HEDLEY_IMPORT
#undef JSON_HEDLEY_INLINE
#undef JSON_HEDLEY_INTEL_VERSION
#undef JSON_HEDLEY_INTEL_VERSION_CHECK
#undef JSON_HEDLEY_IS_CONSTANT
#undef JSON_HEDLEY_IS_CONSTEXPR_
#undef JSON_HEDLEY_LIKELY
#undef JSON_HEDLEY_MALLOC
#undef JSON_HEDLEY_MESSAGE
#undef JSON_HEDLEY_MSVC_VERSION
#undef JSON_HEDLEY_MSVC_VERSION_CHECK
#undef JSON_HEDLEY_NEVER_INLINE
#undef JSON_HEDLEY_NO_ESCAPE
#undef JSON_HEDLEY_NON_NULL
#undef JSON_HEDLEY_NO_RETURN
#undef JSON_HEDLEY_NO_THROW
#undef JSON_HEDLEY_NULL
#undef JSON_HEDLEY_PELLES_VERSION
#undef JSON_HEDLEY_PELLES_VERSION_CHECK
#undef JSON_HEDLEY_PGI_VERSION
#undef JSON_HEDLEY_PGI_VERSION_CHECK
#undef JSON_HEDLEY_PREDICT
#undef JSON_HEDLEY_PRINTF_FORMAT
#undef JSON_HEDLEY_PRIVATE
#undef JSON_HEDLEY_PUBLIC
#undef JSON_HEDLEY_PURE
#undef JSON_HEDLEY_REINTERPRET_CAST
#undef JSON_HEDLEY_REQUIRE
#undef JSON_HEDLEY_REQUIRE_CONSTEXPR
#undef JSON_HEDLEY_REQUIRE_MSG
#undef JSON_HEDLEY_RESTRICT
#undef JSON_HEDLEY_RETURNS_NON_NULL
#undef JSON_HEDLEY_SENTINEL
#undef JSON_HEDLEY_STATIC_ASSERT
#undef JSON_HEDLEY_STATIC_CAST
#undef JSON_HEDLEY_STRINGIFY
#undef JSON_HEDLEY_STRINGIFY_EX
#undef JSON_HEDLEY_SUNPRO_VERSION
#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
#undef JSON_HEDLEY_TINYC_VERSION
#undef JSON_HEDLEY_TINYC_VERSION_CHECK
#undef JSON_HEDLEY_TI_VERSION
#undef JSON_HEDLEY_TI_VERSION_CHECK
#undef JSON_HEDLEY_UNAVAILABLE
#undef JSON_HEDLEY_UNLIKELY
#undef JSON_HEDLEY_UNPREDICTABLE
#undef JSON_HEDLEY_UNREACHABLE
#undef JSON_HEDLEY_UNREACHABLE_RETURN
#undef JSON_HEDLEY_VERSION
#undef JSON_HEDLEY_VERSION_DECODE_MAJOR
#undef JSON_HEDLEY_VERSION_DECODE_MINOR
#undef JSON_HEDLEY_VERSION_DECODE_REVISION
#undef JSON_HEDLEY_VERSION_ENCODE
#undef JSON_HEDLEY_WARNING
#undef JSON_HEDLEY_WARN_UNUSED_RESULT

View file

@ -1,6 +1,6 @@
project('nlohmann_json', project('nlohmann_json',
'cpp', 'cpp',
version : '3.5.0', version : '3.7.1',
license : 'MIT', license : 'MIT',
) )
@ -12,6 +12,7 @@ nlohmann_json_multiple_headers = declare_dependency(
include_directories: include_directories('include') include_directories: include_directories('include')
) )
if not meson.is_subproject()
install_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann') install_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann')
pkgc = import('pkgconfig') pkgc = import('pkgconfig')
@ -19,3 +20,4 @@ pkgc.generate(name: 'nlohmann_json',
version: meson.project_version(), version: meson.project_version(),
description: 'JSON for Modern C++' description: 'JSON for Modern C++'
) )
endif

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ option(JSON_Coverage "Build test suite with coverage information" OFF)
if(JSON_Sanitizer) if(JSON_Sanitizer)
message(STATUS "Building test suite with Clang sanitizer") message(STATUS "Building test suite with Clang sanitizer")
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS "-g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer") set(CMAKE_CXX_FLAGS "-g -O0 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fsanitize-recover=unsigned-integer-overflow")
endif() endif()
endif() endif()
@ -22,7 +22,7 @@ if(JSON_NoExceptions)
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DJSON_NOEXCEPTION") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DJSON_NOEXCEPTION")
endif() endif()
set(CATCH_TEST_FILTER -e) set(DOCTEST_TEST_FILTER --no-throw)
endif() endif()
if(JSON_Coverage) if(JSON_Coverage)
@ -45,27 +45,38 @@ if(JSON_Coverage)
# add target to collect coverage information and generate HTML file # add target to collect coverage information and generate HTML file
# (filter script from https://stackoverflow.com/a/43726240/266378) # (filter script from https://stackoverflow.com/a/43726240/266378)
add_custom_target(lcov_html add_custom_target(lcov_html
COMMAND lcov --directory . --capture --output-file json.info --gcov-tool ${GCOV_BIN} --rc lcov_branch_coverage=1 COMMAND lcov --directory . --capture --output-file json.info --rc lcov_branch_coverage=1
COMMAND lcov -e json.info ${SOURCE_FILES} --output-file json.info.filtered --rc lcov_branch_coverage=1 COMMAND lcov -e json.info ${SOURCE_FILES} --output-file json.info.filtered --gcov-tool ${GCOV_BIN} --rc lcov_branch_coverage=1
COMMAND ${CMAKE_SOURCE_DIR}/test/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept COMMAND ${CMAKE_SOURCE_DIR}/test/thirdparty/imapdl/filterbr.py json.info.filtered > json.info.filtered.noexcept
COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.filtered.noexcept
COMMENT "Generating HTML report test/html/index.html" COMMENT "Generating HTML report test/html/index.html"
) )
add_custom_target(fastcov_html
COMMAND ${CMAKE_SOURCE_DIR}/test/thirdparty/fastcov/fastcov.py --branch-coverage --lcov -o json.info --gcov ${GCOV_BIN} --compiler-directory ${CMAKE_BINARY_DIR} --source-files ${SOURCE_FILES}
COMMAND ${CMAKE_SOURCE_DIR}/test/thirdparty/imapdl/filterbr.py json.info > json.info.noexcept
COMMAND genhtml --title "JSON for Modern C++" --legend --demangle-cpp --output-directory html --show-details --branch-coverage json.info.noexcept
COMMENT "Generating HTML report test/html/index.html"
)
endif() endif()
############################################################################# #############################################################################
# Catch library with the main function to speed up build # doctest library with the main function to speed up build
############################################################################# #############################################################################
add_library(catch_main OBJECT add_library(doctest_main OBJECT
"src/unit.cpp" "src/unit.cpp"
) )
set_target_properties(catch_main PROPERTIES set_target_properties(doctest_main PROPERTIES
COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>" COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>"
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>" COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>"
) )
target_compile_features(catch_main PUBLIC cxx_std_11) if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
target_include_directories(catch_main PRIVATE "thirdparty/catch") target_compile_features(doctest_main PUBLIC cxx_range_for)
else()
target_compile_features(doctest_main PUBLIC cxx_std_11)
endif()
target_include_directories(doctest_main PRIVATE "thirdparty/doctest")
# https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake # https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake
if(MSVC) if(MSVC)
@ -81,7 +92,7 @@ if(MSVC)
# Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252) # Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252)
# Disable warning C4996: 'nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::operator <<': was declared deprecated # Disable warning C4996: 'nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::operator <<': was declared deprecated
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996")
# https://github.com/nlohmann/json/issues/1114 # https://github.com/nlohmann/json/issues/1114
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
endif() endif()
@ -90,15 +101,56 @@ endif()
# one executable for each unit test file # one executable for each unit test file
############################################################################# #############################################################################
file(GLOB files "src/unit-*.cpp") set(files
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-json_patch.cpp
src/unit-json_pointer.cpp
src/unit-merge_patch.cpp
src/unit-meta.cpp
src/unit-modifiers.cpp
src/unit-msgpack.cpp
src/unit-noexcept.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-to_chars.cpp
src/unit-ubjson.cpp
src/unit-udt.cpp
src/unit-unicode.cpp
src/unit-wstring.cpp)
foreach(file ${files}) foreach(file ${files})
get_filename_component(file_basename ${file} NAME_WE) get_filename_component(file_basename ${file} NAME_WE)
string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename}) string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename})
add_executable(${testcase} $<TARGET_OBJECTS:catch_main> ${file}) add_executable(${testcase} $<TARGET_OBJECTS:doctest_main> ${file})
target_compile_definitions(${testcase} PRIVATE target_compile_definitions(${testcase} PRIVATE
CATCH_CONFIG_FAST_COMPILE DOCTEST_CONFIG_SUPER_FAST_ASSERTS
$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>
) )
target_compile_options(${testcase} PRIVATE target_compile_options(${testcase} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>> $<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>
@ -106,26 +158,26 @@ foreach(file ${files})
$<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations> $<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
) )
target_include_directories(${testcase} PRIVATE target_include_directories(${testcase} PRIVATE
thirdparty/catch thirdparty/doctest
thirdparty/fifo_map thirdparty/fifo_map
) )
target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME}) target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME})
add_test(NAME "${testcase}_default" add_test(NAME "${testcase}_default"
COMMAND ${testcase} ${CATCH_TEST_FILTER} COMMAND ${testcase} ${DOCTEST_TEST_FILTER}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
set_tests_properties("${testcase}_default" PROPERTIES LABELS "default") set_tests_properties("${testcase}_default" PROPERTIES LABELS "default")
add_test(NAME "${testcase}_all" add_test(NAME "${testcase}_all"
COMMAND ${testcase} ${CATCH_TEST_FILTER} "*" COMMAND ${testcase} ${DOCTEST_TEST_FILTER} --no-skip
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
set_tests_properties("${testcase}_all" PROPERTIES LABELS "all") set_tests_properties("${testcase}_all" PROPERTIES LABELS "all")
if(JSON_Valgrind) if(JSON_Valgrind)
add_test(NAME "${testcase}_valgrind" add_test(NAME "${testcase}_valgrind"
COMMAND ${memcheck_command} ${CMAKE_CURRENT_BINARY_DIR}/${testcase} ${CATCH_TEST_FILTER} COMMAND ${memcheck_command} ${CMAKE_CURRENT_BINARY_DIR}/${testcase} ${DOCTEST_TEST_FILTER}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
set_tests_properties("${testcase}_valgrind" PROPERTIES LABELS "valgrind") set_tests_properties("${testcase}_valgrind" PROPERTIES LABELS "valgrind")

View file

@ -4,7 +4,7 @@
# 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 -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
CPPFLAGS += -I ../single_include -I . -I thirdparty/catch -I thirdparty/fifo_map -DCATCH_CONFIG_FAST_COMPILE CPPFLAGS += -I ../single_include -I . -I thirdparty/doctest -I thirdparty/fifo_map -DDOCTEST_CONFIG_SUPER_FAST_ASSERTS
SOURCES = src/unit.cpp \ SOURCES = src/unit.cpp \
src/unit-algorithms.cpp \ src/unit-algorithms.cpp \
@ -63,11 +63,11 @@ clean:
# single test file # single test file
############################################################################## ##############################################################################
json_unit: $(OBJECTS) ../single_include/nlohmann/json.hpp thirdparty/catch/catch.hpp json_unit: $(OBJECTS) ../single_include/nlohmann/json.hpp thirdparty/doctest/doctest.h
@echo "[CXXLD] $@" @echo "[CXXLD] $@"
@$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@ @$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@
%.o: %.cpp ../single_include/nlohmann/json.hpp thirdparty/catch/catch.hpp %.o: %.cpp ../single_include/nlohmann/json.hpp thirdparty/doctest/doctest.h
@echo "[CXX] $@" @echo "[CXX] $@"
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@ @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
@ -76,7 +76,7 @@ json_unit: $(OBJECTS) ../single_include/nlohmann/json.hpp thirdparty/catch/catch
# individual test cases # individual test cases
############################################################################## ##############################################################################
test-%: src/unit-%.o src/unit.o ../single_include/nlohmann/json.hpp thirdparty/catch/catch.hpp test-%: src/unit-%.o src/unit.o ../single_include/nlohmann/json.hpp thirdparty/doctest/doctest.h
@echo "[CXXLD] $@" @echo "[CXXLD] $@"
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $< src/unit.o -o $@ @$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $< src/unit.o -o $@

View file

@ -1,6 +1,7 @@
add_test(NAME cmake_import_configure add_test(NAME cmake_import_configure
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}" -G "${CMAKE_GENERATOR}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-Dnlohmann_json_DIR=${PROJECT_BINARY_DIR} -Dnlohmann_json_DIR=${PROJECT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/project ${CMAKE_CURRENT_SOURCE_DIR}/project
) )

View file

@ -1,6 +1,7 @@
add_test(NAME cmake_import_minver_configure add_test(NAME cmake_import_minver_configure
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}" -G "${CMAKE_GENERATOR}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-Dnlohmann_json_DIR=${PROJECT_BINARY_DIR} -Dnlohmann_json_DIR=${PROJECT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/project ${CMAKE_CURRENT_SOURCE_DIR}/project
) )

1
test/src/UBSAN.supp Normal file
View file

@ -0,0 +1 @@
unsigned-integer-overflow:stl_bvector.h

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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,12 +1,12 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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>.
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>. Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,7 +27,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "catch.hpp" #include "doctest_compatibility.h"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;

View file

@ -1,12 +1,12 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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>.
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>. Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,14 +27,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "catch.hpp" #include "doctest_compatibility.h"
#define private public #define private public
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#undef private
namespace
{
// special test case to check if memory is leaked if constructor throws // special test case to check if memory is leaked if constructor throws
template<class T> template<class T>
struct bad_allocator : std::allocator<T> struct bad_allocator : std::allocator<T>
{ {
@ -44,6 +46,7 @@ struct bad_allocator : std::allocator<T>
throw std::bad_alloc(); throw std::bad_alloc();
} }
}; };
}
TEST_CASE("bad_alloc") TEST_CASE("bad_alloc")
{ {
@ -64,13 +67,17 @@ TEST_CASE("bad_alloc")
} }
} }
static bool next_construct_fails = false; namespace
static bool next_destroy_fails = false; {
static bool next_deallocate_fails = false; bool next_construct_fails = false;
bool next_destroy_fails = false;
bool next_deallocate_fails = false;
template<class T> template<class T>
struct my_allocator : std::allocator<T> struct my_allocator : std::allocator<T>
{ {
using std::allocator<T>::allocator;
template<class... Args> template<class... Args>
void construct(T* p, Args&& ... args) void construct(T* p, Args&& ... args)
{ {
@ -110,6 +117,12 @@ struct my_allocator : std::allocator<T>
p->~T(); p->~T();
} }
} }
template <class U>
struct rebind
{
using other = my_allocator<U>;
};
}; };
// allows deletion of raw pointer, usually hold by json_value // allows deletion of raw pointer, usually hold by json_value
@ -121,6 +134,7 @@ void my_allocator_clean_up(T* p)
alloc.destroy(p); alloc.destroy(p);
alloc.deallocate(p, 1); alloc.deallocate(p, 1);
} }
}
TEST_CASE("controlled bad_alloc") TEST_CASE("controlled bad_alloc")
{ {

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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>.
@ -27,9 +27,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "catch.hpp" #include "doctest_compatibility.h"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <string> #include <string>
#include <utility> #include <utility>
@ -37,7 +38,7 @@ SOFTWARE.
/* forward declarations */ /* forward declarations */
class alt_string; class alt_string;
bool operator<(const char* op1, const alt_string& op2); bool operator<(const char* op1, const alt_string& op2);
void int_to_string(alt_string& target, std::size_t value);
/* /*
* This is virtually a string class. * This is virtually a string class.
@ -149,11 +150,15 @@ class alt_string
} }
private: private:
std::string str_impl; std::string str_impl {};
friend bool ::operator<(const char*, const alt_string&); friend bool ::operator<(const char*, const alt_string&);
}; };
void int_to_string(alt_string& target, std::size_t value)
{
target = std::to_string(value).c_str();
}
using alt_json = nlohmann::basic_json < using alt_json = nlohmann::basic_json <
std::map, std::map,
@ -172,8 +177,6 @@ bool operator<(const char* op1, const alt_string& op2)
return op1 < op2.str_impl; return op1 < op2.str_impl;
} }
TEST_CASE("alternative string type") TEST_CASE("alternative string type")
{ {
SECTION("dump") SECTION("dump")
@ -235,6 +238,35 @@ TEST_CASE("alternative string type")
CHECK(dump == R"({"foo":"bar"})"); CHECK(dump == R"({"foo":"bar"})");
} }
SECTION("items")
{
auto doc = alt_json::parse("{\"foo\": \"bar\"}");
for ( auto item : doc.items() )
{
CHECK( item.key() == "foo" );
CHECK( item.value() == "bar" );
}
auto doc_array = alt_json::parse("[\"foo\", \"bar\"]");
for ( auto item : doc_array.items() )
{
if (item.key() == "0" )
{
CHECK( item.value() == "foo" );
}
else if (item.key() == "1" )
{
CHECK( item.value() == "bar" );
}
else
{
CHECK( false );
}
}
}
SECTION("equality") SECTION("equality")
{ {
alt_json doc; alt_json doc;

View file

@ -1,12 +1,12 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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>.
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>. Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,11 +27,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "catch.hpp" #include "doctest_compatibility.h"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#include <fstream> #include <fstream>
#include <sstream>
TEST_CASE("BSON") TEST_CASE("BSON")
{ {
@ -110,8 +112,9 @@ TEST_CASE("BSON")
0x00, 0x00,
0x00, 0x00, 0x00, 0x80 0x00, 0x00, 0x00, 0x80
}; };
CHECK_THROWS_AS(json::from_bson(v), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 10: syntax error while parsing BSON string: string length must be at least 1, is -2147483648"); CHECK_THROWS_AS(_ = json::from_bson(v), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 10: syntax error while parsing BSON string: string length must be at least 1, is -2147483648");
} }
SECTION("objects") SECTION("objects")
@ -581,10 +584,9 @@ TEST_CASE("BSON input/output_adapters")
{ {
SECTION("std::ostringstream") SECTION("std::ostringstream")
{ {
std::ostringstream ss; std::basic_ostringstream<std::uint8_t> ss;
json::to_bson(json_representation, ss); json::to_bson(json_representation, ss);
std::istringstream iss(ss.str()); json j3 = json::from_bson(ss.str());
json j3 = json::from_bson(iss);
CHECK(json_representation == j3); CHECK(json_representation == j3);
} }
@ -606,6 +608,8 @@ TEST_CASE("BSON input/output_adapters")
} }
} }
namespace
{
class SaxCountdown class SaxCountdown
{ {
public: public:
@ -675,6 +679,7 @@ class SaxCountdown
private: private:
int events_left = 0; int events_left = 0;
}; };
}
TEST_CASE("Incomplete BSON Input") TEST_CASE("Incomplete BSON Input")
{ {
@ -687,8 +692,9 @@ TEST_CASE("Incomplete BSON Input")
'e', 'n', 't' // unexpected EOF 'e', 'n', 't' // unexpected EOF
}; };
CHECK_THROWS_AS(json::from_bson(incomplete_bson), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_bson(incomplete_bson), CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
"[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input");
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
@ -705,8 +711,9 @@ TEST_CASE("Incomplete BSON Input")
0x08, // entry: boolean, unexpected EOF 0x08, // entry: boolean, unexpected EOF
}; };
CHECK_THROWS_AS(json::from_bson(incomplete_bson), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_bson(incomplete_bson), CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
"[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input");
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
@ -728,8 +735,9 @@ TEST_CASE("Incomplete BSON Input")
// missing input data... // missing input data...
}; };
CHECK_THROWS_AS(json::from_bson(incomplete_bson), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_bson(incomplete_bson), CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
"[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input");
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
@ -744,8 +752,9 @@ TEST_CASE("Incomplete BSON Input")
0x0D, 0x00, // size (incomplete), unexpected EOF 0x0D, 0x00, // size (incomplete), unexpected EOF
}; };
CHECK_THROWS_AS(json::from_bson(incomplete_bson), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_bson(incomplete_bson), CHECK_THROWS_AS(_ = json::from_bson(incomplete_bson), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_bson(incomplete_bson),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input");
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
@ -786,8 +795,9 @@ TEST_CASE("Unsupported BSON input")
0x00 // end marker 0x00 // end marker
}; };
CHECK_THROWS_AS(json::from_bson(bson), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_bson(bson), CHECK_THROWS_AS(_ = json::from_bson(bson), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_bson(bson),
"[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");
CHECK(json::from_bson(bson, true, false).is_discarded()); CHECK(json::from_bson(bson, true, false).is_discarded());
@ -1138,7 +1148,7 @@ TEST_CASE("BSON numerical data")
}; };
CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&); CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64"); CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64");
} }
} }
@ -1146,7 +1156,7 @@ TEST_CASE("BSON numerical data")
} }
} }
TEST_CASE("BSON roundtrips", "[hide]") TEST_CASE("BSON roundtrips" * doctest::skip())
{ {
SECTION("reference files") SECTION("reference files")
{ {
@ -1161,8 +1171,8 @@ TEST_CASE("BSON roundtrips", "[hide]")
{ {
CAPTURE(filename) CAPTURE(filename)
SECTION(filename + ": std::vector<uint8_t>")
{ {
INFO_WITH_TEMP(filename + ": std::vector<uint8_t>");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1179,8 +1189,8 @@ TEST_CASE("BSON roundtrips", "[hide]")
CHECK(j1 == j2); CHECK(j1 == j2);
} }
SECTION(filename + ": std::ifstream")
{ {
INFO_WITH_TEMP(filename + ": std::ifstream");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1194,8 +1204,8 @@ TEST_CASE("BSON roundtrips", "[hide]")
CHECK(j1 == j2); CHECK(j1 == j2);
} }
SECTION(filename + ": uint8_t* and size")
{ {
INFO_WITH_TEMP(filename + ": uint8_t* and size");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1212,8 +1222,8 @@ TEST_CASE("BSON roundtrips", "[hide]")
CHECK(j1 == j2); CHECK(j1 == j2);
} }
SECTION(filename + ": output to output adapters")
{ {
INFO_WITH_TEMP(filename + ": output to output adapters");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1224,8 +1234,8 @@ TEST_CASE("BSON roundtrips", "[hide]")
(std::istreambuf_iterator<char>(f_bson)), (std::istreambuf_iterator<char>(f_bson)),
std::istreambuf_iterator<char>()); std::istreambuf_iterator<char>());
SECTION(filename + ": output adapters: std::vector<uint8_t>")
{ {
INFO_WITH_TEMP(filename + ": output adapters: std::vector<uint8_t>");
std::vector<uint8_t> vec; std::vector<uint8_t> vec;
json::to_bson(j1, vec); json::to_bson(j1, vec);

View file

@ -1,12 +1,12 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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>.
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>. Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,7 +27,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "catch.hpp" #include "doctest_compatibility.h"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;

View file

@ -1,12 +1,12 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.5.0 | | |__ | | | | | | version 3.7.1
|_____|_____|_____|_|___| 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>.
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>. Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,13 +27,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "catch.hpp" #include "doctest_compatibility.h"
DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal")
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#include <fstream> #include <fstream>
#include <sstream>
#include <iomanip>
#include <set>
namespace
{
class SaxCountdown class SaxCountdown
{ {
public: public:
@ -103,6 +109,7 @@ class SaxCountdown
private: private:
int events_left = 0; int events_left = 0;
}; };
}
TEST_CASE("CBOR") TEST_CASE("CBOR")
{ {
@ -829,15 +836,17 @@ TEST_CASE("CBOR")
{ {
SECTION("no byte follows") SECTION("no byte follows")
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xf9})), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xf9})), CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xf9})), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xf9})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input");
CHECK(json::from_cbor(std::vector<uint8_t>({0xf9}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({0xf9}), true, false).is_discarded());
} }
SECTION("only one byte follows") SECTION("only one byte follows")
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c})), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c})), CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c})), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input");
CHECK(json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c}), true, false).is_discarded());
} }
@ -1278,7 +1287,7 @@ TEST_CASE("CBOR")
} }
} }
SECTION("additonal deserialization") SECTION("additional deserialization")
{ {
SECTION("0x7b (string)") SECTION("0x7b (string)")
{ {
@ -1312,86 +1321,88 @@ TEST_CASE("CBOR")
{ {
SECTION("empty byte vector") SECTION("empty byte vector")
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>()), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>()), CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>()), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>()),
"[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing CBOR value: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing CBOR value: unexpected end of input");
CHECK(json::from_cbor(std::vector<uint8_t>(), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>(), true, false).is_discarded());
} }
SECTION("too short byte vector") SECTION("too short byte vector")
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x18})), json::parse_error&); json _;
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x19})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x18})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x19, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x19})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1a})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x19, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1a})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1a, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x62})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x62, 0x60})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x62})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x7F})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x62, 0x60})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x7F, 0x60})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x7F})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x82, 0x01})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x7F, 0x60})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x9F, 0x01})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x82, 0x01})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0x61, 0xF5})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x9F, 0x01})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xA1, 0x61, 0X61})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0x61, 0xF5})), json::parse_error&);
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0X61})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xA1, 0x61, 0X61})), json::parse_error&);
CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0X61})), json::parse_error&);
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x18})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x18})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x19})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x19})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x19, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x19, 0x00})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1a})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1a, 0x00})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing CBOR number: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing CBOR number: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x62})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x62})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x62, 0x60})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x62, 0x60})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR string: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR string: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x7F})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x7F})),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x7F, 0x60})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x7F, 0x60})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR string: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR string: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x82, 0x01})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x82, 0x01})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x9F, 0x01})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x9F, 0x01})),
"[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0x61, 0xF5})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0x61, 0xF5})),
"[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR string: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR string: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xA1, 0x61, 0x61})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xA1, 0x61, 0x61})),
"[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0x61})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xBF, 0x61, 0x61})),
"[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input"); "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input");
CHECK(json::from_cbor(std::vector<uint8_t>({0x18}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({0x18}), true, false).is_discarded());
@ -1424,13 +1435,14 @@ TEST_CASE("CBOR")
{ {
SECTION("concrete examples") SECTION("concrete examples")
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1c})), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1c})), CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0x1c})), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0x1c})),
"[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0x1C"); "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0x1C");
CHECK(json::from_cbor(std::vector<uint8_t>({0x1c}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({0x1c}), true, false).is_discarded());
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xf8})), json::parse_error&); CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xf8})), json::parse_error&);
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xf8})), CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xf8})),
"[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0xF8"); "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0xF8");
CHECK(json::from_cbor(std::vector<uint8_t>({0xf8}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({0xf8}), true, false).is_discarded());
} }
@ -1481,7 +1493,8 @@ TEST_CASE("CBOR")
0xf8 0xf8
}) })
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({static_cast<uint8_t>(byte)})), json::parse_error&); json _;
CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({static_cast<uint8_t>(byte)})), json::parse_error&);
CHECK(json::from_cbor(std::vector<uint8_t>({static_cast<uint8_t>(byte)}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({static_cast<uint8_t>(byte)}), true, false).is_discarded());
} }
} }
@ -1489,8 +1502,9 @@ TEST_CASE("CBOR")
SECTION("invalid string in map") SECTION("invalid string in map")
{ {
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0xa1, 0xff, 0x01})), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0xa1, 0xff, 0x01})), CHECK_THROWS_AS(_ = json::from_cbor(std::vector<uint8_t>({0xa1, 0xff, 0x01})), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_cbor(std::vector<uint8_t>({0xa1, 0xff, 0x01})),
"[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xFF"); "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xFF");
CHECK(json::from_cbor(std::vector<uint8_t>({0xa1, 0xff, 0x01}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector<uint8_t>({0xa1, 0xff, 0x01}), true, false).is_discarded());
} }
@ -1507,8 +1521,9 @@ TEST_CASE("CBOR")
SECTION("strict mode") SECTION("strict mode")
{ {
CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); json _;
CHECK_THROWS_WITH(json::from_cbor(vec), CHECK_THROWS_AS(_ = json::from_cbor(vec), json::parse_error&);
CHECK_THROWS_WITH(_ = json::from_cbor(vec),
"[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR value: expected end of input; last byte: 0xF6"); "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR value: expected end of input; last byte: 0xF6");
CHECK(json::from_cbor(vec, true, false).is_discarded()); CHECK(json::from_cbor(vec, true, false).is_discarded());
} }
@ -1565,7 +1580,7 @@ TEST_CASE("single CBOR roundtrip")
{ {
SECTION("std::ostringstream") SECTION("std::ostringstream")
{ {
std::ostringstream ss; std::basic_ostringstream<std::uint8_t> ss;
json::to_cbor(j1, ss); json::to_cbor(j1, ss);
json j3 = json::from_cbor(ss.str()); json j3 = json::from_cbor(ss.str());
CHECK(j1 == j3); CHECK(j1 == j3);
@ -1586,7 +1601,8 @@ TEST_CASE("single CBOR roundtrip")
} }
} }
TEST_CASE("CBOR regressions", "[!throws]") #if not defined(JSON_NOEXCEPTION)
TEST_CASE("CBOR regressions")
{ {
SECTION("fuzz test results") SECTION("fuzz test results")
{ {
@ -1655,12 +1671,13 @@ TEST_CASE("CBOR regressions", "[!throws]")
} }
} }
} }
#endif
TEST_CASE("CBOR roundtrips", "[hide]") TEST_CASE("CBOR roundtrips" * doctest::skip())
{ {
SECTION("input from flynn") SECTION("input from flynn")
{ {
// most of these are exluded due to differences in key order (not a real problem) // most of these are excluded due to differences in key order (not a real problem)
auto exclude_packed = std::set<std::string> auto exclude_packed = std::set<std::string>
{ {
"test/data/json.org/1.json", "test/data/json.org/1.json",
@ -1827,8 +1844,8 @@ TEST_CASE("CBOR roundtrips", "[hide]")
{ {
CAPTURE(filename) CAPTURE(filename)
SECTION(filename + ": std::vector<uint8_t>")
{ {
INFO_WITH_TEMP(filename + ": std::vector<uint8_t>");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1845,8 +1862,8 @@ TEST_CASE("CBOR roundtrips", "[hide]")
CHECK(j1 == j2); CHECK(j1 == j2);
} }
SECTION(filename + ": std::ifstream")
{ {
INFO_WITH_TEMP(filename + ": std::ifstream");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1860,8 +1877,8 @@ TEST_CASE("CBOR roundtrips", "[hide]")
CHECK(j1 == j2); CHECK(j1 == j2);
} }
SECTION(filename + ": uint8_t* and size")
{ {
INFO_WITH_TEMP(filename + ": uint8_t* and size");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1878,8 +1895,8 @@ TEST_CASE("CBOR roundtrips", "[hide]")
CHECK(j1 == j2); CHECK(j1 == j2);
} }
SECTION(filename + ": output to output adapters")
{ {
INFO_WITH_TEMP(filename + ": output to output adapters");
// parse JSON file // parse JSON file
std::ifstream f_json(filename); std::ifstream f_json(filename);
json j1 = json::parse(f_json); json j1 = json::parse(f_json);
@ -1892,8 +1909,8 @@ TEST_CASE("CBOR roundtrips", "[hide]")
if (!exclude_packed.count(filename)) if (!exclude_packed.count(filename))
{ {
SECTION(filename + ": output adapters: std::vector<uint8_t>")
{ {
INFO_WITH_TEMP(filename + ": output adapters: std::vector<uint8_t>");
std::vector<uint8_t> vec; std::vector<uint8_t> vec;
json::to_cbor(j1, vec); json::to_cbor(j1, vec);
CHECK(vec == packed); CHECK(vec == packed);
@ -1904,7 +1921,8 @@ TEST_CASE("CBOR roundtrips", "[hide]")
} }
} }
TEST_CASE("all CBOR first bytes", "[!throws]") #if not defined(JSON_NOEXCEPTION)
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
std::set<uint8_t> unsupported = std::set<uint8_t> unsupported =
@ -1968,7 +1986,7 @@ TEST_CASE("all CBOR first bytes", "[!throws]")
{ {
// check that parse_error.112 is only thrown if the // check that parse_error.112 is only thrown if the
// first byte is in the unsupported set // first byte is in the unsupported set
CAPTURE(e.what()) INFO_WITH_TEMP(e.what());
if (std::find(unsupported.begin(), unsupported.end(), byte) != unsupported.end()) if (std::find(unsupported.begin(), unsupported.end(), byte) != unsupported.end())
{ {
CHECK(e.id == 112); CHECK(e.id == 112);
@ -1980,6 +1998,7 @@ TEST_CASE("all CBOR first bytes", "[!throws]")
} }
} }
} }
#endif
TEST_CASE("examples from RFC 7049 Appendix A") TEST_CASE("examples from RFC 7049 Appendix A")
{ {

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