mirror of
https://github.com/nlohmann/json.git
synced 2026-02-17 17:14:00 +00:00
Compare commits
271 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1768a540a | ||
|
|
cdfe6ceda6 | ||
|
|
b968faa882 | ||
|
|
cd518fbbab | ||
|
|
b911654857 | ||
|
|
bb55885215 | ||
|
|
5c7d27c338 | ||
|
|
b6fdad9acd | ||
|
|
7c385a4844 | ||
|
|
9ba3f79667 | ||
|
|
8d1585f065 | ||
|
|
ad3c216bb5 | ||
|
|
0231059290 | ||
|
|
9f18e17063 | ||
|
|
53ec0a16f3 | ||
|
|
4c617611e2 | ||
|
|
829571ab5c | ||
|
|
c8231eff75 | ||
|
|
02e653bdf7 | ||
|
|
564506a885 | ||
|
|
1729db85c1 | ||
|
|
910a895027 | ||
|
|
1fae82b7a7 | ||
|
|
22e55349a6 | ||
|
|
70e587c3da | ||
|
|
d26f39466e | ||
|
|
c61a9071ae | ||
|
|
b59a58406e | ||
|
|
4e54c9a13d | ||
|
|
95432c34f9 | ||
|
|
8c1387cfb3 | ||
|
|
521fe49fec | ||
|
|
680a4ab672 | ||
|
|
7a37ba0c02 | ||
|
|
99b7c7c8ef | ||
|
|
e184b6ecf2 | ||
|
|
88b055c2df | ||
|
|
8799759b85 | ||
|
|
4e52277b70 | ||
|
|
e4bc98d036 | ||
|
|
4d780b091b | ||
|
|
3b1a5cafad | ||
|
|
99939d6340 | ||
|
|
4e2f35d4c2 | ||
|
|
7fa3b8865c | ||
|
|
8f07ab6392 | ||
|
|
186c747a19 | ||
|
|
6b5334c167 | ||
|
|
ebb3c03293 | ||
|
|
d3428b35c5 | ||
|
|
aea648bb7a | ||
|
|
4b4bbceebf | ||
|
|
f7971f04a5 | ||
|
|
f7c8a2145a | ||
|
|
628f76729e | ||
|
|
29f72966c3 | ||
|
|
77967e6548 | ||
|
|
13760857ff | ||
|
|
924e95c6e8 | ||
|
|
e84195ab7b | ||
|
|
b59c3367c9 | ||
|
|
1ea8cd128c | ||
|
|
eb30ff0615 | ||
|
|
ad053ef09c | ||
|
|
bbdfe7dea6 | ||
|
|
d713727f22 | ||
|
|
04597c3a66 | ||
|
|
aada309f61 | ||
|
|
359f98d140 | ||
|
|
dfe607c6ff | ||
|
|
9f3857ef6f | ||
|
|
7608a64e1e | ||
|
|
a7b02bdce0 | ||
|
|
c6a482b16c | ||
|
|
5ad52f4167 | ||
|
|
3811daa8a3 | ||
|
|
6899fa304c | ||
|
|
57faaf42ca | ||
|
|
f78ac4fbd3 | ||
|
|
3004a73951 | ||
|
|
e33b31e6aa | ||
|
|
b5c54b41fd | ||
|
|
07494e06d7 | ||
|
|
d5b21b051c | ||
|
|
0cc3db4f15 | ||
|
|
38f8a51a8f | ||
|
|
9bbb133094 | ||
|
|
442886d040 | ||
|
|
f6febbe359 | ||
|
|
3ac2d81a95 | ||
|
|
be2065dce9 | ||
|
|
fed70f6bff | ||
|
|
0e748f2f8c | ||
|
|
861ee400cc | ||
|
|
3ce4325350 | ||
|
|
ba4a19d4af | ||
|
|
043eff5ba8 | ||
|
|
05b27e83b7 | ||
|
|
d5aaeb4cce | ||
|
|
3760a38b7e | ||
|
|
5b14411669 | ||
|
|
347e77bdc1 | ||
|
|
04372a8c56 | ||
|
|
d0e60de433 | ||
|
|
7bfc406ded | ||
|
|
d456a2d777 | ||
|
|
b8ad3388ec | ||
|
|
39dd775e38 | ||
|
|
86a96b059d | ||
|
|
396a914f9e | ||
|
|
bab5826504 | ||
|
|
515cfc2d89 | ||
|
|
963d06a13c | ||
|
|
9f00db48d9 | ||
|
|
ec2ebd5ec9 | ||
|
|
0bb36bb140 | ||
|
|
62457729e8 | ||
|
|
09c0df4a21 | ||
|
|
1bbc4a0859 | ||
|
|
d8fe13fc83 | ||
|
|
e59b930927 | ||
|
|
937d68e2e5 | ||
|
|
989ad9b759 | ||
|
|
067e288289 | ||
|
|
7bbc06b487 | ||
|
|
441e5d87e6 | ||
|
|
7fa4ddf93e | ||
|
|
bf348ca8a4 | ||
|
|
ed6a0686df | ||
|
|
c8bfdfd961 | ||
|
|
c02de445bf | ||
|
|
66dd1a846d | ||
|
|
850922269d | ||
|
|
0460b90977 | ||
|
|
85f35a1d59 | ||
|
|
e7c1638d11 | ||
|
|
1c81e9f5ae | ||
|
|
d505ed7b31 | ||
|
|
2c920a1032 | ||
|
|
2b37d7ed86 | ||
|
|
299469cfd5 | ||
|
|
1566ad4053 | ||
|
|
f574d7e084 | ||
|
|
cd28d872e7 | ||
|
|
3d3055909c | ||
|
|
4feb8211ca | ||
|
|
14e6278c2f | ||
|
|
7acd90b651 | ||
|
|
5676a2a076 | ||
|
|
e0e7fa39e7 | ||
|
|
4778c02ab5 | ||
|
|
714c592680 | ||
|
|
e830bc502f | ||
|
|
ecadcdb593 | ||
|
|
48656a49f5 | ||
|
|
64acb42aa7 | ||
|
|
8efbf8d7bb | ||
|
|
e5a67fc3f8 | ||
|
|
a49644ab74 | ||
|
|
0efaf891e5 | ||
|
|
c5e63fd684 | ||
|
|
db03d09312 | ||
|
|
cf9299d222 | ||
|
|
3cdc4d784b | ||
|
|
adf09726b0 | ||
|
|
481ace65c4 | ||
|
|
1c6b332dcd | ||
|
|
90eb0a91e0 | ||
|
|
1f84cc2c88 | ||
|
|
717301d1bc | ||
|
|
4639bb2c8f | ||
|
|
e94862a649 | ||
|
|
ae213721b1 | ||
|
|
5ff2abb90d | ||
|
|
567fe9b7a0 | ||
|
|
377e956655 | ||
|
|
5da596385b | ||
|
|
7bbe7bb98f | ||
|
|
14f01e1981 | ||
|
|
86b0732a10 | ||
|
|
ed69e50ad2 | ||
|
|
5bc4ff9da3 | ||
|
|
fa3e42f826 | ||
|
|
b5d1755dfb | ||
|
|
0ab8fab338 | ||
|
|
65b4d8251b | ||
|
|
53fb230098 | ||
|
|
46ec2fddf8 | ||
|
|
b8bfd1140d | ||
|
|
33a2154f8d | ||
|
|
29362c6ace | ||
|
|
c02a3155d4 | ||
|
|
8d8f890771 | ||
|
|
7f20e9ddc7 | ||
|
|
031b88d315 | ||
|
|
aaee18ce90 | ||
|
|
7c503c64b7 | ||
|
|
4286b16b71 | ||
|
|
cf91b4f2bb | ||
|
|
f924df1835 | ||
|
|
acf10d9af7 | ||
|
|
e1ea8369ad | ||
|
|
40f279c59d | ||
|
|
18a0271a95 | ||
|
|
1ae9896387 | ||
|
|
83b143382e | ||
|
|
e439a1a9a7 | ||
|
|
495436a5d5 | ||
|
|
a35d414c39 | ||
|
|
08a7233d1b | ||
|
|
1e08654f99 | ||
|
|
aa89c5e048 | ||
|
|
6678eb2b4a | ||
|
|
16c5bfeaad | ||
|
|
727dd4664b | ||
|
|
ab89ae4e50 | ||
|
|
eb06d0531a | ||
|
|
ba6edd5634 | ||
|
|
850671b9f1 | ||
|
|
4efa8cdb4c | ||
|
|
830c93fd09 | ||
|
|
c78dbc366c | ||
|
|
53d8d57921 | ||
|
|
5f723bbec6 | ||
|
|
896a9db461 | ||
|
|
73cc5089e3 | ||
|
|
a9baab76c2 | ||
|
|
4f6b2b6429 | ||
|
|
2537677e4c | ||
|
|
9e1abb4842 | ||
|
|
1e38ffc014 | ||
|
|
25f56ff207 | ||
|
|
99ecca55c4 | ||
|
|
9e07e9b4ec | ||
|
|
a271ee5f16 | ||
|
|
943d641054 | ||
|
|
22929fe189 | ||
|
|
375b05a17d | ||
|
|
606a25195f | ||
|
|
c87ffad45c | ||
|
|
2a5506ed98 | ||
|
|
8165707990 | ||
|
|
27cf05af8d | ||
|
|
d2dd27dc3b | ||
|
|
a52e8355b8 | ||
|
|
21410d50af | ||
|
|
829ed74d66 | ||
|
|
1262d474eb | ||
|
|
282bafae4f | ||
|
|
abac6a0e84 | ||
|
|
3d4f6a2940 | ||
|
|
ad47b0fbde | ||
|
|
149d2fd09c | ||
|
|
6399cd3039 | ||
|
|
35e43df625 | ||
|
|
7c1a788893 | ||
|
|
8b379948d0 | ||
|
|
303a0c5843 | ||
|
|
5beab80553 | ||
|
|
faf2546a15 | ||
|
|
5b9d03cfdb | ||
|
|
9d27429527 | ||
|
|
86991d5204 | ||
|
|
3ff9455332 | ||
|
|
21352c4d8e | ||
|
|
981e226ca2 | ||
|
|
8d6b3d44d6 | ||
|
|
8c7f46f7d0 | ||
|
|
922f7a3d0e | ||
|
|
ac230e8b4b | ||
|
|
374ebacc51 |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -54,7 +54,7 @@ To make changes, you need to edit the following files:
|
||||
|
||||
## Please don't
|
||||
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
|
||||
- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
|
||||
- We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments.
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
**Bug Report**
|
||||
|
||||
- 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 expected behavior?
|
||||
|
||||
- And what is the actual behavior instead?
|
||||
|
||||
- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)?
|
||||
|
||||
- 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)?
|
||||
|
||||
|
||||
**Feature Request**
|
||||
|
||||
- Describe the feature in as much detail as possible.
|
||||
|
||||
- Include sample usage where appropriate.
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
- 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 expected behavior?
|
||||
|
||||
- And what is the actual behavior instead?
|
||||
|
||||
- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)?
|
||||
|
||||
- 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)?
|
||||
9
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
- Describe the feature in as much detail as possible.
|
||||
|
||||
- Include sample usage where appropriate.
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -13,7 +13,7 @@ Read the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop
|
||||
|
||||
## Please don't
|
||||
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
|
||||
- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
|
||||
- Please do not open pull requests that address **multiple issues**.
|
||||
|
||||
46
.travis.yml
46
.travis.yml
@@ -155,11 +155,28 @@ matrix:
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.3
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10
|
||||
|
||||
# Linux / GCC
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-4.9
|
||||
env: compiler=g++-4.8
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.8', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: compiler=g++-4.9
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
@@ -189,15 +206,23 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-7', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-8', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- COMPILER=g++-7
|
||||
- COMPILER=g++-8
|
||||
- CXXFLAGS=-std=c++17
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-7', 'ninja-build']
|
||||
packages: ['g++-8', 'ninja-build']
|
||||
|
||||
# Linux / Clang
|
||||
|
||||
@@ -257,15 +282,23 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
|
||||
packages: ['g++-6', 'clang-5.0', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: COMPILER=clang++-6.0
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
|
||||
packages: ['g++-6', 'clang-6.0', 'ninja-build']
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- COMPILER=clang++-5.0
|
||||
- COMPILER=clang++-6.0
|
||||
- CXXFLAGS=-std=c++1z
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
|
||||
packages: ['g++-6', 'clang-5.0', 'ninja-build']
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
|
||||
packages: ['g++-6', 'clang-6.0', 'ninja-build']
|
||||
|
||||
################
|
||||
# build script #
|
||||
@@ -277,6 +310,7 @@ script:
|
||||
if [[ (-x $(which brew)) ]]; then
|
||||
brew update
|
||||
brew install cmake ninja
|
||||
brew upgrade cmake
|
||||
cmake --version
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
##
|
||||
## PROJECT
|
||||
## name and version
|
||||
##
|
||||
project(nlohmann_json VERSION 3.1.2 LANGUAGES CXX)
|
||||
project(nlohmann_json VERSION 3.3.0 LANGUAGES CXX)
|
||||
|
||||
##
|
||||
## INCLUDE
|
||||
@@ -22,13 +22,15 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
|
||||
## CONFIGURATION
|
||||
##
|
||||
set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME})
|
||||
set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||
set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}"
|
||||
CACHE INTERNAL "")
|
||||
set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include")
|
||||
set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in")
|
||||
set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake_config")
|
||||
set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
|
||||
set(NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake")
|
||||
|
||||
if (JSON_MultipleHeaders)
|
||||
set(NLOHMANN_JSON_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include/")
|
||||
@@ -43,6 +45,8 @@ endif()
|
||||
## create target and add include path
|
||||
##
|
||||
add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE)
|
||||
add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME})
|
||||
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
|
||||
|
||||
target_include_directories(
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
@@ -51,8 +55,8 @@ target_include_directories(
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
## add debug view defintion file for msvc (natvis) [cmake <= 3.2.2 does not support export of source files]
|
||||
if (MSVC AND CMAKE_VERSION VERSION_GREATER "3.2.2")
|
||||
## add debug view definition file for msvc (natvis)
|
||||
if (MSVC)
|
||||
set(NLOHMANN_ADD_NATVIS TRUE)
|
||||
set(NLOHMANN_NATVIS_FILE "nlohmann_json.natvis")
|
||||
target_sources(
|
||||
@@ -62,7 +66,7 @@ if (MSVC AND CMAKE_VERSION VERSION_GREATER "3.2.2")
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}>
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
##
|
||||
## TESTS
|
||||
## create and configure the unit test target
|
||||
@@ -82,10 +86,10 @@ include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE} COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
configure_package_config_file(
|
||||
configure_file(
|
||||
${NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE}
|
||||
${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE}
|
||||
INSTALL_DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(
|
||||
@@ -102,6 +106,11 @@ if (NLOHMANN_ADD_NATVIS)
|
||||
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}
|
||||
@@ -109,5 +118,6 @@ install(
|
||||
)
|
||||
install(
|
||||
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
|
||||
)
|
||||
|
||||
250
ChangeLog.md
250
ChangeLog.md
@@ -1,6 +1,254 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [v3.3.0](https://github.com/nlohmann/json/releases/tag/v3.3.0) (2018-10-05)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.2.0...v3.3.0)
|
||||
|
||||
- When key is not found print the key name into error too [\#1273](https://github.com/nlohmann/json/issues/1273)
|
||||
- Visual Studio 2017 15.8.5 "conditional expression is constant" warning on Line 1851 in json.hpp [\#1268](https://github.com/nlohmann/json/issues/1268)
|
||||
- how can we get this working on WSL? [\#1264](https://github.com/nlohmann/json/issues/1264)
|
||||
- Help needed [\#1259](https://github.com/nlohmann/json/issues/1259)
|
||||
- A way to get to a JSON values "key" [\#1258](https://github.com/nlohmann/json/issues/1258)
|
||||
- Two blackslashes on json output file [\#1253](https://github.com/nlohmann/json/issues/1253)
|
||||
- Including nlohmann the badwrong way. [\#1250](https://github.com/nlohmann/json/issues/1250)
|
||||
- how to build with clang? [\#1247](https://github.com/nlohmann/json/issues/1247)
|
||||
- Cmake target\_link\_libraries unable to find nlohmann\_json since version 3.2.0 [\#1243](https://github.com/nlohmann/json/issues/1243)
|
||||
- \[Question\] Access to end\(\) iterator reference [\#1242](https://github.com/nlohmann/json/issues/1242)
|
||||
- Parsing different json format [\#1241](https://github.com/nlohmann/json/issues/1241)
|
||||
- Parsing Multiple JSON Files [\#1240](https://github.com/nlohmann/json/issues/1240)
|
||||
- Doesn't compile under C++17 [\#1239](https://github.com/nlohmann/json/issues/1239)
|
||||
- Conversion operator for nlohmann::json is not SFINAE friendly [\#1237](https://github.com/nlohmann/json/issues/1237)
|
||||
- Custom deserialization of number\_float\_t [\#1236](https://github.com/nlohmann/json/issues/1236)
|
||||
- Move tests to a separate repo [\#1235](https://github.com/nlohmann/json/issues/1235)
|
||||
- deprecated-declarations warnings when compiling tests with GCC 8.2.1. [\#1233](https://github.com/nlohmann/json/issues/1233)
|
||||
- Incomplete type with json\_fwd.hpp [\#1232](https://github.com/nlohmann/json/issues/1232)
|
||||
- Parse Error [\#1229](https://github.com/nlohmann/json/issues/1229)
|
||||
- json::get function with argument [\#1227](https://github.com/nlohmann/json/issues/1227)
|
||||
- questions regarding from\_json [\#1226](https://github.com/nlohmann/json/issues/1226)
|
||||
- Lambda in unevaluated context [\#1225](https://github.com/nlohmann/json/issues/1225)
|
||||
- NLohmann doesn't compile when enabling strict warning policies [\#1224](https://github.com/nlohmann/json/issues/1224)
|
||||
- Creating array of objects [\#1223](https://github.com/nlohmann/json/issues/1223)
|
||||
- Somewhat unhelpful error message "cannot use operator\[\] with object" [\#1220](https://github.com/nlohmann/json/issues/1220)
|
||||
- single\_include json.hpp [\#1218](https://github.com/nlohmann/json/issues/1218)
|
||||
- Maps with enum class keys which are convertible to JSON strings should be converted to JSON dictionaries [\#1217](https://github.com/nlohmann/json/issues/1217)
|
||||
- Adding JSON Array to the Array [\#1216](https://github.com/nlohmann/json/issues/1216)
|
||||
- Best way to output a vector of a given type to json [\#1215](https://github.com/nlohmann/json/issues/1215)
|
||||
- compiler warning: double definition of macro JSON\_INTERNAL\_CATCH [\#1213](https://github.com/nlohmann/json/issues/1213)
|
||||
- Compilation error when using MOCK\_METHOD1 from GMock and nlohmann::json [\#1212](https://github.com/nlohmann/json/issues/1212)
|
||||
- Issues parsing a previously encoded binary \(non-UTF8\) string. [\#1211](https://github.com/nlohmann/json/issues/1211)
|
||||
- Yet another ordering question: char \* and parse\(\) [\#1209](https://github.com/nlohmann/json/issues/1209)
|
||||
- Error using gcc 8.1.0 on Ubuntu 14.04 [\#1207](https://github.com/nlohmann/json/issues/1207)
|
||||
- "type must be string, but is " std::string\(j.type\_name\(\) [\#1206](https://github.com/nlohmann/json/issues/1206)
|
||||
- Returning empty json object from a function of type const json& ? [\#1205](https://github.com/nlohmann/json/issues/1205)
|
||||
- VS2017 compiler suggests using constexpr if [\#1204](https://github.com/nlohmann/json/issues/1204)
|
||||
- Template instatiation error on compiling [\#1203](https://github.com/nlohmann/json/issues/1203)
|
||||
- Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198)
|
||||
- BUG - json dump field with unicode -\> array of ints \(instead of string\) [\#1197](https://github.com/nlohmann/json/issues/1197)
|
||||
- Compile error using Code::Blocks // mingw-w64 GCC 8.1.0 - "Incomplete Type" [\#1193](https://github.com/nlohmann/json/issues/1193)
|
||||
- SEGFAULT on arm target [\#1190](https://github.com/nlohmann/json/issues/1190)
|
||||
- Compiler crash with old Clang [\#1179](https://github.com/nlohmann/json/issues/1179)
|
||||
- Custom Precision on floating point numbers [\#1170](https://github.com/nlohmann/json/issues/1170)
|
||||
- Can we have a json\_view class like std::string\_view? [\#1158](https://github.com/nlohmann/json/issues/1158)
|
||||
- improve error handling [\#1152](https://github.com/nlohmann/json/issues/1152)
|
||||
- We should remove static\_asserts [\#960](https://github.com/nlohmann/json/issues/960)
|
||||
|
||||
- Fix warning C4127: conditional expression is constant [\#1272](https://github.com/nlohmann/json/pull/1272) ([antonioborondo](https://github.com/antonioborondo))
|
||||
- Turn off additional deprecation warnings for GCC. [\#1271](https://github.com/nlohmann/json/pull/1271) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- docs: Add additional CMake documentation [\#1270](https://github.com/nlohmann/json/pull/1270) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- unit-testsuites.cpp: fix hangup if file not found [\#1262](https://github.com/nlohmann/json/pull/1262) ([knilch0r](https://github.com/knilch0r))
|
||||
- Fix broken cmake imported target alias [\#1260](https://github.com/nlohmann/json/pull/1260) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- GCC 48 [\#1257](https://github.com/nlohmann/json/pull/1257) ([henryiii](https://github.com/henryiii))
|
||||
- Add version and license to meson.build [\#1252](https://github.com/nlohmann/json/pull/1252) ([koponomarenko](https://github.com/koponomarenko))
|
||||
- \#1179 Reordered the code. It seems to stop clang 3.4.2 in RHEL 7 from crash… [\#1249](https://github.com/nlohmann/json/pull/1249) ([LEgregius](https://github.com/LEgregius))
|
||||
- Use a version check to provide backwards comatible CMake imported target names [\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- Fix issue \#1237 [\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Add a get overload taking a parameter. [\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel))
|
||||
- Remove static asserts [\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Better error 305 [\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam))
|
||||
- Fix \#1213 [\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt))
|
||||
- Export package to allow builds without installing [\#1202](https://github.com/nlohmann/json/pull/1202) ([dennisfischer](https://github.com/dennisfischer))
|
||||
|
||||
## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-20)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...v3.2.0)
|
||||
|
||||
- Am I doing this wrong? Getting an empty string [\#1199](https://github.com/nlohmann/json/issues/1199)
|
||||
- Incompatible Pointer Type [\#1196](https://github.com/nlohmann/json/issues/1196)
|
||||
- json.exception.type\_error.316 [\#1195](https://github.com/nlohmann/json/issues/1195)
|
||||
- Strange warnings in Code::Blocks 17.12, GNU GCC [\#1192](https://github.com/nlohmann/json/issues/1192)
|
||||
- \[Question\] Current place in code to change floating point resolution [\#1191](https://github.com/nlohmann/json/issues/1191)
|
||||
- Add key name when throwing type error [\#1189](https://github.com/nlohmann/json/issues/1189)
|
||||
- Not able to include in visual studio code? [\#1188](https://github.com/nlohmann/json/issues/1188)
|
||||
- Get an Index or row number of an element [\#1186](https://github.com/nlohmann/json/issues/1186)
|
||||
- reduce repos size [\#1185](https://github.com/nlohmann/json/issues/1185)
|
||||
- Difference between `merge\_patch` and `update` [\#1183](https://github.com/nlohmann/json/issues/1183)
|
||||
- Is there a way to get an element from a JSON without throwing an exception on failure? [\#1182](https://github.com/nlohmann/json/issues/1182)
|
||||
- to\_string? [\#1181](https://github.com/nlohmann/json/issues/1181)
|
||||
- How to cache a json object's pointer into a map? [\#1180](https://github.com/nlohmann/json/issues/1180)
|
||||
- Can this library work within a Qt project for Android using Qt Creator? [\#1178](https://github.com/nlohmann/json/issues/1178)
|
||||
- How to get all keys of one object? [\#1177](https://github.com/nlohmann/json/issues/1177)
|
||||
- How can I only parse the first level and get the value as string? [\#1175](https://github.com/nlohmann/json/issues/1175)
|
||||
- I have a query regarding nlohmann::basic\_json::basic\_json [\#1174](https://github.com/nlohmann/json/issues/1174)
|
||||
- unordered\_map with vectors won't convert to json? [\#1173](https://github.com/nlohmann/json/issues/1173)
|
||||
- return json objects from functions [\#1172](https://github.com/nlohmann/json/issues/1172)
|
||||
- Problem when exporting to CBOR [\#1171](https://github.com/nlohmann/json/issues/1171)
|
||||
- Roundtripping null to nullptr does not work [\#1169](https://github.com/nlohmann/json/issues/1169)
|
||||
- MSVC fails to compile std::swap specialization for nlohmann::json [\#1168](https://github.com/nlohmann/json/issues/1168)
|
||||
- Unexpected behaviour of is\_null - Part II [\#1167](https://github.com/nlohmann/json/issues/1167)
|
||||
- Floating point imprecision [\#1166](https://github.com/nlohmann/json/issues/1166)
|
||||
- Combine json objects into one? [\#1165](https://github.com/nlohmann/json/issues/1165)
|
||||
- Is there any way to know if the object has changed? [\#1164](https://github.com/nlohmann/json/issues/1164)
|
||||
- Value throws on null string [\#1163](https://github.com/nlohmann/json/issues/1163)
|
||||
- Weird template issue in large project [\#1162](https://github.com/nlohmann/json/issues/1162)
|
||||
- \_json returns a different result vs ::parse [\#1161](https://github.com/nlohmann/json/issues/1161)
|
||||
- Showing difference between two json objects [\#1160](https://github.com/nlohmann/json/issues/1160)
|
||||
- no instance of overloaded function "std::swap" matches the specified type [\#1159](https://github.com/nlohmann/json/issues/1159)
|
||||
- resize\(...\)? [\#1157](https://github.com/nlohmann/json/issues/1157)
|
||||
- Issue with struct nested in class' to\_json [\#1155](https://github.com/nlohmann/json/issues/1155)
|
||||
- Deserialize std::map with std::nan [\#1154](https://github.com/nlohmann/json/issues/1154)
|
||||
- Parse throwing errors [\#1149](https://github.com/nlohmann/json/issues/1149)
|
||||
- cocoapod integration [\#1148](https://github.com/nlohmann/json/issues/1148)
|
||||
- wstring parsing [\#1147](https://github.com/nlohmann/json/issues/1147)
|
||||
- Is it possible to dump a two-dimensional array to "\[\[null\],\[1,2,3\]\]"? [\#1146](https://github.com/nlohmann/json/issues/1146)
|
||||
- Want to write a class member variable and a struct variable \( this structure is inside the class\) to the json file [\#1145](https://github.com/nlohmann/json/issues/1145)
|
||||
- Does json support converting an instance of a struct into json string? [\#1143](https://github.com/nlohmann/json/issues/1143)
|
||||
- \#Most efficient way to search for child parameters \(recursive find?\) [\#1141](https://github.com/nlohmann/json/issues/1141)
|
||||
- could not find to\_json\(\) method in T's namespace [\#1140](https://github.com/nlohmann/json/issues/1140)
|
||||
- chars get treated as JSON numbers not JSON strings [\#1139](https://github.com/nlohmann/json/issues/1139)
|
||||
- How do I count number of objects in array? [\#1137](https://github.com/nlohmann/json/issues/1137)
|
||||
- Serializing a vector of classes? [\#1136](https://github.com/nlohmann/json/issues/1136)
|
||||
- Compile error. Unable convert form nullptr to nullptr&& [\#1135](https://github.com/nlohmann/json/issues/1135)
|
||||
- std::unordered\_map in struct, serialization [\#1133](https://github.com/nlohmann/json/issues/1133)
|
||||
- dump\(\) can't handle umlauts [\#1131](https://github.com/nlohmann/json/issues/1131)
|
||||
- Add a way to get a key reference from the iterator [\#1127](https://github.com/nlohmann/json/issues/1127)
|
||||
- can't not parse "\\“ string [\#1123](https://github.com/nlohmann/json/issues/1123)
|
||||
- if json file contain Internationalization chars , get exception [\#1122](https://github.com/nlohmann/json/issues/1122)
|
||||
- How to use a json::iterator dereferenced value in code? [\#1120](https://github.com/nlohmann/json/issues/1120)
|
||||
- clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119)
|
||||
- Disable implicit conversions from json to std::initializer\_list\<T\> for any T [\#1118](https://github.com/nlohmann/json/issues/1118)
|
||||
- Implicit conversions to complex types can lead to surprising and confusing errors [\#1116](https://github.com/nlohmann/json/issues/1116)
|
||||
- How can I write from\_json for a complex datatype that is not default constructible? [\#1115](https://github.com/nlohmann/json/issues/1115)
|
||||
- Compile error in VS2015 when compiling unit-conversions.cpp [\#1114](https://github.com/nlohmann/json/issues/1114)
|
||||
- ADL Serializer for std::any / boost::any [\#1113](https://github.com/nlohmann/json/issues/1113)
|
||||
- Unexpected behaviour of is\_null [\#1112](https://github.com/nlohmann/json/issues/1112)
|
||||
- How to resolve " undefined reference to `std::\_\_throw\_bad\_cast\(\)'" [\#1111](https://github.com/nlohmann/json/issues/1111)
|
||||
- cannot compile on ubuntu 18.04 and 16.04 [\#1110](https://github.com/nlohmann/json/issues/1110)
|
||||
- JSON representation for floating point values has too many digits [\#1109](https://github.com/nlohmann/json/issues/1109)
|
||||
- Not working for classes containing "\_declspec\(dllimport\)" in their declaration [\#1108](https://github.com/nlohmann/json/issues/1108)
|
||||
- Get keys from json object [\#1107](https://github.com/nlohmann/json/issues/1107)
|
||||
- dump\(\) without alphabetical order [\#1106](https://github.com/nlohmann/json/issues/1106)
|
||||
- Cannot deserialize types using std::ratio [\#1105](https://github.com/nlohmann/json/issues/1105)
|
||||
- i want to learn json [\#1104](https://github.com/nlohmann/json/issues/1104)
|
||||
- Type checking during compile [\#1103](https://github.com/nlohmann/json/issues/1103)
|
||||
- Iterate through sub items [\#1102](https://github.com/nlohmann/json/issues/1102)
|
||||
- cppcheck failing for version 3.1.2 [\#1101](https://github.com/nlohmann/json/issues/1101)
|
||||
- Deserializing std::map [\#1100](https://github.com/nlohmann/json/issues/1100)
|
||||
- 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)
|
||||
- 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)
|
||||
- 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)
|
||||
- general crayCC compilation failure [\#1091](https://github.com/nlohmann/json/issues/1091)
|
||||
- Merge Patch clears original data [\#1090](https://github.com/nlohmann/json/issues/1090)
|
||||
- \[Question\] how to use nlohmann/json in c++? [\#1088](https://github.com/nlohmann/json/issues/1088)
|
||||
- C++17 decomposition declaration support [\#1087](https://github.com/nlohmann/json/issues/1087)
|
||||
- \[Question\] Access multi-level json objects [\#1086](https://github.com/nlohmann/json/issues/1086)
|
||||
- Serializing vector [\#1085](https://github.com/nlohmann/json/issues/1085)
|
||||
- update nested value in multi hierarchy json object [\#1084](https://github.com/nlohmann/json/issues/1084)
|
||||
- Overriding default values? [\#1083](https://github.com/nlohmann/json/issues/1083)
|
||||
- detail namespace collision with Cereal? [\#1082](https://github.com/nlohmann/json/issues/1082)
|
||||
- Error using json.dump\(\); [\#1081](https://github.com/nlohmann/json/issues/1081)
|
||||
- Consuming TCP Stream [\#1080](https://github.com/nlohmann/json/issues/1080)
|
||||
- Compilation error with strong typed enums in map in combination with namespaces [\#1079](https://github.com/nlohmann/json/issues/1079)
|
||||
- cassert error [\#1076](https://github.com/nlohmann/json/issues/1076)
|
||||
- Valid json data not being parsed [\#1075](https://github.com/nlohmann/json/issues/1075)
|
||||
- Feature request :: Better testing for key existance without try/catch [\#1074](https://github.com/nlohmann/json/issues/1074)
|
||||
- Hi, I have input like a.b.c and want to convert it to \"a\"{\"b\": \"c\"} form. Any suggestions how do I do this? Thanks. [\#1073](https://github.com/nlohmann/json/issues/1073)
|
||||
- ADL deserializer not picked up for non default-constructible type [\#1072](https://github.com/nlohmann/json/issues/1072)
|
||||
- Deserializing std::array doesn't compiler \(no insert\(\)\) [\#1071](https://github.com/nlohmann/json/issues/1071)
|
||||
- Serializing OpenCV Mat problem [\#1070](https://github.com/nlohmann/json/issues/1070)
|
||||
- Compilation error with ICPC compiler [\#1068](https://github.com/nlohmann/json/issues/1068)
|
||||
- Minimal branch? [\#1066](https://github.com/nlohmann/json/issues/1066)
|
||||
- Not existing value, crash [\#1065](https://github.com/nlohmann/json/issues/1065)
|
||||
- cyryllic symbols [\#1064](https://github.com/nlohmann/json/issues/1064)
|
||||
- newbie usage question [\#1063](https://github.com/nlohmann/json/issues/1063)
|
||||
- Trying j\["strTest"\] = "%A" produces "strTest": "-0X1.CCCCCCCCCCCCCP+205" [\#1062](https://github.com/nlohmann/json/issues/1062)
|
||||
- convert json value to std::string??? [\#1061](https://github.com/nlohmann/json/issues/1061)
|
||||
- Commented out test cases, should they be removed? [\#1060](https://github.com/nlohmann/json/issues/1060)
|
||||
- different behaviour between clang and gcc with braced initialization [\#1059](https://github.com/nlohmann/json/issues/1059)
|
||||
- json array: initialize with prescribed size and `resize` method. [\#1057](https://github.com/nlohmann/json/issues/1057)
|
||||
- Is it possible to use exceptions istead of assertions? [\#1056](https://github.com/nlohmann/json/issues/1056)
|
||||
- when using assign operator in with json object a static assertion fails.. [\#1055](https://github.com/nlohmann/json/issues/1055)
|
||||
- Iterate over leafs of a JSON data structure: enrich the JSON pointer API [\#1054](https://github.com/nlohmann/json/issues/1054)
|
||||
- \[Feature request\] Access by path [\#1053](https://github.com/nlohmann/json/issues/1053)
|
||||
- document that implicit js -\> primitive conversion does not work for std::string::value\_type and why [\#1052](https://github.com/nlohmann/json/issues/1052)
|
||||
- error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\#1051](https://github.com/nlohmann/json/issues/1051)
|
||||
- Destructor is called when filling object through assignement [\#1050](https://github.com/nlohmann/json/issues/1050)
|
||||
- Is this thing thread safe for reads? [\#1049](https://github.com/nlohmann/json/issues/1049)
|
||||
- clang-tidy: Call to virtual function during construction [\#1046](https://github.com/nlohmann/json/issues/1046)
|
||||
- Using STL algorithms with JSON containers with expected results? [\#1045](https://github.com/nlohmann/json/issues/1045)
|
||||
- Usage with gtest/gmock not working as expected [\#1044](https://github.com/nlohmann/json/issues/1044)
|
||||
- Consequences of from\_json / to\_json being in namespace of data struct. [\#1042](https://github.com/nlohmann/json/issues/1042)
|
||||
- const\_reference operator\[\]\(const typename object\_t::key\_type& key\) const throw instead of assert [\#1039](https://github.com/nlohmann/json/issues/1039)
|
||||
- Trying to retrieve data from nested objects [\#1038](https://github.com/nlohmann/json/issues/1038)
|
||||
- Direct download link for json\_fwd.hpp? [\#1037](https://github.com/nlohmann/json/issues/1037)
|
||||
- I know the library supports UTF-8, but failed to dump the value [\#1036](https://github.com/nlohmann/json/issues/1036)
|
||||
- Putting a Vec3-like vector into a json object [\#1035](https://github.com/nlohmann/json/issues/1035)
|
||||
- Ternary operator crash [\#1034](https://github.com/nlohmann/json/issues/1034)
|
||||
- Issued with Clion Inspection Resolution since 2018.1 [\#1033](https://github.com/nlohmann/json/issues/1033)
|
||||
- Some testcases fail and one never finishes [\#1032](https://github.com/nlohmann/json/issues/1032)
|
||||
- Can this class work with wchar\_t / std::wstring? [\#1031](https://github.com/nlohmann/json/issues/1031)
|
||||
- Makefile: Valgrind flags have no effect [\#1030](https://github.com/nlohmann/json/issues/1030)
|
||||
- 「==」 Should be 「\>」 [\#1029](https://github.com/nlohmann/json/issues/1029)
|
||||
- HOCON reader? [\#1027](https://github.com/nlohmann/json/issues/1027)
|
||||
- add json string in previous string?? [\#1025](https://github.com/nlohmann/json/issues/1025)
|
||||
- RFC: fluent parsing interface [\#1023](https://github.com/nlohmann/json/issues/1023)
|
||||
- Does it support chinese character? [\#1022](https://github.com/nlohmann/json/issues/1022)
|
||||
- to/from\_msgpack only works with standard typization [\#1021](https://github.com/nlohmann/json/issues/1021)
|
||||
- Build failure using latest clang and GCC compilers [\#1020](https://github.com/nlohmann/json/issues/1020)
|
||||
- can two json objects be concatenated? [\#1019](https://github.com/nlohmann/json/issues/1019)
|
||||
- Erase by integer index [\#1018](https://github.com/nlohmann/json/issues/1018)
|
||||
- Function find overload taking a json\_pointer [\#1017](https://github.com/nlohmann/json/issues/1017)
|
||||
- I think should implement an parser function [\#1016](https://github.com/nlohmann/json/issues/1016)
|
||||
- Readme gif [\#1015](https://github.com/nlohmann/json/issues/1015)
|
||||
- Python bindings [\#1014](https://github.com/nlohmann/json/issues/1014)
|
||||
- how to add two json string in single object?? [\#1012](https://github.com/nlohmann/json/issues/1012)
|
||||
- how to serialize class Object \(convert data in object into json\)?? [\#1011](https://github.com/nlohmann/json/issues/1011)
|
||||
- Enable forward declaration of json by making json a class instead of a using declaration [\#997](https://github.com/nlohmann/json/issues/997)
|
||||
- compilation error while using intel c++ compiler 2018 [\#994](https://github.com/nlohmann/json/issues/994)
|
||||
- How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990)
|
||||
- istream \>\> json --- 1st character skipped in stream [\#976](https://github.com/nlohmann/json/issues/976)
|
||||
- Add a SAX parser [\#971](https://github.com/nlohmann/json/issues/971)
|
||||
- Add Key name to Exception [\#932](https://github.com/nlohmann/json/issues/932)
|
||||
- How to solve large json file? [\#927](https://github.com/nlohmann/json/issues/927)
|
||||
- json\_pointer public push\_back, pop\_back [\#837](https://github.com/nlohmann/json/issues/837)
|
||||
- Using input\_adapter in a slightly unexpected way [\#834](https://github.com/nlohmann/json/issues/834)
|
||||
- Stack-overflow \(OSS-Fuzz 4234\) [\#832](https://github.com/nlohmann/json/issues/832)
|
||||
|
||||
- Fix -Wno-sometimes-uninitialized by initializing "result" in parse\_sax [\#1200](https://github.com/nlohmann/json/pull/1200) ([thyu](https://github.com/thyu))
|
||||
- \[RFC\] Introduce a new macro function: JSON\_INTERNAL\_CATCH [\#1187](https://github.com/nlohmann/json/pull/1187) ([simnalamburt](https://github.com/simnalamburt))
|
||||
- Fix unit tests that were silently skipped or crashed \(depending on the compiler\) [\#1176](https://github.com/nlohmann/json/pull/1176) ([grembo](https://github.com/grembo))
|
||||
- Refactor/no virtual sax [\#1153](https://github.com/nlohmann/json/pull/1153) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Fixed compiler error in VS 2015 for debug mode [\#1151](https://github.com/nlohmann/json/pull/1151) ([sonulohani](https://github.com/sonulohani))
|
||||
- Fix links to cppreference named requirements \(formerly concepts\) [\#1144](https://github.com/nlohmann/json/pull/1144) ([jrakow](https://github.com/jrakow))
|
||||
- meson: fix include directory [\#1142](https://github.com/nlohmann/json/pull/1142) ([jrakow](https://github.com/jrakow))
|
||||
- Feature/unordered map conversion [\#1138](https://github.com/nlohmann/json/pull/1138) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- fixed compile error for \#1045 [\#1134](https://github.com/nlohmann/json/pull/1134) ([Daniel599](https://github.com/Daniel599))
|
||||
- test \(non\)equality for alt\_string implementation [\#1130](https://github.com/nlohmann/json/pull/1130) ([agrianius](https://github.com/agrianius))
|
||||
- remove stringstream dependency [\#1117](https://github.com/nlohmann/json/pull/1117) ([TinyTinni](https://github.com/TinyTinni))
|
||||
- Provide a from\_json overload for std::map [\#1089](https://github.com/nlohmann/json/pull/1089) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- fix typo in README [\#1078](https://github.com/nlohmann/json/pull/1078) ([martin-mfg](https://github.com/martin-mfg))
|
||||
- Fix typo [\#1058](https://github.com/nlohmann/json/pull/1058) ([dns13](https://github.com/dns13))
|
||||
- Misc cmake packaging enhancements [\#1048](https://github.com/nlohmann/json/pull/1048) ([chuckatkins](https://github.com/chuckatkins))
|
||||
- Fixed incorrect LLVM version number in README [\#1047](https://github.com/nlohmann/json/pull/1047) ([jammehcow](https://github.com/jammehcow))
|
||||
- Fix trivial typo in comment. [\#1043](https://github.com/nlohmann/json/pull/1043) ([coryan](https://github.com/coryan))
|
||||
- Package Manager: Spack [\#1041](https://github.com/nlohmann/json/pull/1041) ([ax3l](https://github.com/ax3l))
|
||||
- CMake: 3.8+ is Sufficient [\#1040](https://github.com/nlohmann/json/pull/1040) ([ax3l](https://github.com/ax3l))
|
||||
- Added support for string\_view in C++17 [\#1028](https://github.com/nlohmann/json/pull/1028) ([gracicot](https://github.com/gracicot))
|
||||
- Added public target\_compile\_features for auto and constexpr [\#1026](https://github.com/nlohmann/json/pull/1026) ([ktonon](https://github.com/ktonon))
|
||||
|
||||
## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...v3.1.2)
|
||||
|
||||
@@ -16,7 +264,6 @@ All notable changes to this project will be documented in this file. This projec
|
||||
- get\<T\> for types that are not default constructible [\#996](https://github.com/nlohmann/json/issues/996)
|
||||
- Prevent Null values to appear in .dump\(\) [\#995](https://github.com/nlohmann/json/issues/995)
|
||||
- number parsing [\#993](https://github.com/nlohmann/json/issues/993)
|
||||
- How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990)
|
||||
- C2664 \(C++/CLR\) cannot convert 'nullptr' to 'nullptr &&' [\#987](https://github.com/nlohmann/json/issues/987)
|
||||
- Uniform initialization from another json object differs between gcc and clang. [\#985](https://github.com/nlohmann/json/issues/985)
|
||||
- Problem with adding the lib as a submodule [\#983](https://github.com/nlohmann/json/issues/983)
|
||||
@@ -785,7 +1032,6 @@ All notable changes to this project will be documented in this file. This projec
|
||||
- json::diff generates incorrect patch when removing multiple array elements. [\#269](https://github.com/nlohmann/json/issues/269)
|
||||
- Docs - What does Json\[key\] return? [\#267](https://github.com/nlohmann/json/issues/267)
|
||||
- Compiler Errors With JSON.hpp [\#265](https://github.com/nlohmann/json/issues/265)
|
||||
- Throw exception instead of crashing my app [\#264](https://github.com/nlohmann/json/issues/264)
|
||||
- Ambiguous push\_back and operator+= overloads [\#263](https://github.com/nlohmann/json/issues/263)
|
||||
- Preseving order of items in json [\#262](https://github.com/nlohmann/json/issues/262)
|
||||
- '\' char problem in strings [\#261](https://github.com/nlohmann/json/issues/261)
|
||||
|
||||
15
Makefile
15
Makefile
@@ -9,6 +9,7 @@ SRCS = include/nlohmann/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/iterators/internal_iterator.hpp \
|
||||
@@ -20,7 +21,10 @@ SRCS = include/nlohmann/json.hpp \
|
||||
include/nlohmann/detail/json_ref.hpp \
|
||||
include/nlohmann/detail/macro_scope.hpp \
|
||||
include/nlohmann/detail/macro_unscope.hpp \
|
||||
include/nlohmann/detail/meta.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 \
|
||||
@@ -82,9 +86,9 @@ clean:
|
||||
|
||||
coverage:
|
||||
mkdir build_coverage
|
||||
cd build_coverage ; CXX=g++-5 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
|
||||
cd build_coverage ; CXX=g++-7 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
|
||||
cd build_coverage ; ninja
|
||||
cd build_coverage ; ctest -j10
|
||||
cd build_coverage ; ctest -E '.*_default' -j10
|
||||
cd build_coverage ; ninja lcov_html
|
||||
open build_coverage/test/html/index.html
|
||||
|
||||
@@ -187,7 +191,10 @@ pedantic_gcc:
|
||||
-Wunused-macros \
|
||||
-Wunused-parameter \
|
||||
-Wuseless-cast \
|
||||
-Wvariadic-macros"
|
||||
-Wvariadic-macros \
|
||||
-Wctor-dtor-privacy \
|
||||
-Winit-self \
|
||||
-Wstrict-null-sentinel"
|
||||
|
||||
##########################################################################
|
||||
# benchmarks
|
||||
|
||||
242
README.md
242
README.md
@@ -5,6 +5,7 @@
|
||||
[](https://coveralls.io/r/nlohmann/json)
|
||||
[](https://scan.coverity.com/projects/nlohmann-json)
|
||||
[](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade)
|
||||
[](https://lgtm.com/projects/g/nlohmann/json/context:cpp)
|
||||
[](https://wandbox.org/permlink/TarF5pPn9NtHQjhf)
|
||||
[](http://nlohmann.github.io/json)
|
||||
[](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
|
||||
@@ -15,6 +16,8 @@
|
||||
|
||||
- [Design goals](#design-goals)
|
||||
- [Integration](#integration)
|
||||
- [CMake](#cmake)
|
||||
- [Package Managers](#package-managers)
|
||||
- [Examples](#examples)
|
||||
- [JSON as first-class data type](#json-as-first-class-data-type)
|
||||
- [Serialization / Deserialization](#serialization--deserialization)
|
||||
@@ -68,6 +71,71 @@ to the files you want to process JSON and set the necessary switches to enable C
|
||||
|
||||
You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`.
|
||||
|
||||
### CMake
|
||||
|
||||
You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags.
|
||||
|
||||
#### External
|
||||
|
||||
To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration:
|
||||
```cmake
|
||||
# CMakeLists.txt
|
||||
find_package(nlohmann_json 3.2.0 REQUIRED)
|
||||
...
|
||||
add_library(foo ...)
|
||||
...
|
||||
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
|
||||
```
|
||||
The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree.
|
||||
|
||||
#### Embedded
|
||||
|
||||
To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file:
|
||||
```cmake
|
||||
# Typically you don't care so much for a third party library's tests to be
|
||||
# run from your own project's code.
|
||||
set(JSON_BuildTests OFF CACHE INTERNAL "")
|
||||
|
||||
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
|
||||
# inintended consequences that will break the build. It's generally
|
||||
# discouraged (although not necessarily well documented as such) to use
|
||||
# include(...) for pulling in other CMake projects anyways.
|
||||
add_subdirectory(nlohmann_json)
|
||||
...
|
||||
add_library(foo ...)
|
||||
...
|
||||
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
|
||||
```
|
||||
|
||||
#### Supporting Both
|
||||
To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following:
|
||||
``` cmake
|
||||
# Top level CMakeLists.txt
|
||||
project(FOO)
|
||||
...
|
||||
option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF)
|
||||
...
|
||||
add_subdirectory(thirdparty)
|
||||
...
|
||||
add_library(foo ...)
|
||||
...
|
||||
# Note that the namespaced target will always be available regardless of the
|
||||
# import method
|
||||
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
|
||||
```
|
||||
```cmake
|
||||
# thirdparty/CMakeLists.txt
|
||||
...
|
||||
if(FOO_USE_EXTERNAL_JSON)
|
||||
find_package(nlohmann_json 3.2.0 REQUIRED)
|
||||
else()
|
||||
set(JSON_BuildTests OFF CACHE INTERNAL "")
|
||||
add_subdirectory(nlohmann_json)
|
||||
endif()
|
||||
...
|
||||
```
|
||||
`thirdparty/nlohmann_json` is then a complete copy of this source tree.
|
||||
|
||||
### 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`.
|
||||
@@ -76,6 +144,8 @@ If you are using the [Meson Build System](http://mesonbuild.com), then you can w
|
||||
|
||||
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 [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).
|
||||
@@ -84,6 +154,8 @@ If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project fo
|
||||
|
||||
If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).
|
||||
|
||||
If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
|
||||
|
||||
## 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)).
|
||||
@@ -169,7 +241,6 @@ json empty_object_explicit = json::object();
|
||||
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
|
||||
```
|
||||
|
||||
|
||||
### Serialization / Deserialization
|
||||
|
||||
#### To/from strings
|
||||
@@ -223,18 +294,22 @@ json j_string = "this is a string";
|
||||
std::string cpp_string = j_string;
|
||||
// retrieve the string value (explicit JSON to std::string conversion)
|
||||
auto cpp_string2 = j_string.get<std::string>();
|
||||
// retrieve the string value (alternative explicit JSON to std::string conversion)
|
||||
std::string cpp_string3;
|
||||
j_string.get_to(cpp_string3);
|
||||
|
||||
// retrieve the serialized value (explicit JSON serialization)
|
||||
std::string serialized_string = j_string.dump();
|
||||
|
||||
// output of original string
|
||||
std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::string>() << '\n';
|
||||
std::cout << cpp_string << " == " << cpp_string2 << " == " << cpp_string3 << " == " << j_string.get<std::string>() << '\n';
|
||||
// output of serialized value
|
||||
std::cout << j_string << " == " << serialized_string << std::endl;
|
||||
```
|
||||
|
||||
[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) 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.
|
||||
|
||||
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_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) may throw an exception.
|
||||
|
||||
#### To/from streams (e.g. files, string streams)
|
||||
|
||||
@@ -283,10 +358,53 @@ std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
json j = json::parse(v);
|
||||
```
|
||||
|
||||
#### SAX interface
|
||||
|
||||
The library uses a SAX-like interface with the following functions:
|
||||
|
||||
```cpp
|
||||
// called when null is parsed
|
||||
bool null();
|
||||
|
||||
// called when a boolean is parsed; value is passed
|
||||
bool boolean(bool val);
|
||||
|
||||
// called when a signed or unsigned integer number is parsed; value is passed
|
||||
bool number_integer(number_integer_t val);
|
||||
bool number_unsigned(number_unsigned_t val);
|
||||
|
||||
// called when a floating-point number is parsed; value and original string is passed
|
||||
bool number_float(number_float_t val, const string_t& s);
|
||||
|
||||
// called when a string is parsed; value is passed and can be safely moved away
|
||||
bool string(string_t& val);
|
||||
|
||||
// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)
|
||||
bool start_object(std::size_t elements);
|
||||
bool end_object();
|
||||
bool start_array(std::size_t elements);
|
||||
bool end_array();
|
||||
// called when an object key is parsed; value is passed and can be safely moved away
|
||||
bool key(string_t& val);
|
||||
|
||||
// called when a parse error occurs; byte position, the last token, and an exception is passed
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);
|
||||
```
|
||||
|
||||
The return value of each function determines whether parsing should proceed.
|
||||
|
||||
To implement your own SAX handler, proceed as follows:
|
||||
|
||||
1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax<json>` as base class, but you can also use any class where the functions described above are implemented and public.
|
||||
2. Create an object of your SAX interface class, e.g. `my_sax`.
|
||||
3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
|
||||
|
||||
Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp).
|
||||
|
||||
|
||||
### STL-like access
|
||||
|
||||
We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement.
|
||||
We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement.
|
||||
|
||||
```cpp
|
||||
// create an array using push_back
|
||||
@@ -523,6 +641,14 @@ int vi = jn.get<int>();
|
||||
// etc.
|
||||
```
|
||||
|
||||
Note that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly:
|
||||
|
||||
```cpp
|
||||
char ch = 'A'; // ASCII value 65
|
||||
json j_default = ch; // stores integer number 65
|
||||
json j_string = std::string(1, ch); // stores string "A"
|
||||
```
|
||||
|
||||
### Arbitrary types conversions
|
||||
|
||||
Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines:
|
||||
@@ -587,24 +713,24 @@ namespace ns {
|
||||
}
|
||||
|
||||
void from_json(const json& j, person& p) {
|
||||
p.name = j.at("name").get<std::string>();
|
||||
p.address = j.at("address").get<std::string>();
|
||||
p.age = j.at("age").get<int>();
|
||||
j.at("name").get_to(p.name);
|
||||
j.at("address").get_to(p.address);
|
||||
j.at("age").get_to(p.age);
|
||||
}
|
||||
} // namespace ns
|
||||
```
|
||||
|
||||
That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called.
|
||||
Likewise, when calling `get<your_type>()`, the `from_json` method will be called.
|
||||
Likewise, when calling `get<your_type>()` or `get_to(your_type&)`, the `from_json` method will be called.
|
||||
|
||||
Some important things:
|
||||
|
||||
* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).
|
||||
* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). (There is a way to bypass this requirement described later.)
|
||||
* Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use the implicit conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise.
|
||||
* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.)
|
||||
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
|
||||
* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get<decltype your_variable>();` instead.
|
||||
* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get<decltype(your_variable)>();` or `your_json.get_to(your_variable);` instead.
|
||||
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
|
||||
* Be careful with the definition order of the `from_json`/`to_json` functions: If a type `B` has a member of type `A`, you **MUST** define `to_json(A)` before `to_json(B)`. Look at [issue 561](https://github.com/nlohmann/json/issues/561) for more details.
|
||||
|
||||
|
||||
#### How do I convert third-party types?
|
||||
@@ -612,7 +738,7 @@ Some important things:
|
||||
This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:
|
||||
|
||||
The library uses **JSON Serializers** to convert types to json.
|
||||
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](http://en.cppreference.com/w/cpp/language/adl)).
|
||||
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)).
|
||||
|
||||
It is implemented like this (simplified):
|
||||
|
||||
@@ -661,7 +787,7 @@ namespace nlohmann {
|
||||
|
||||
#### How can I use `get()` for non-default constructible/non-copyable types?
|
||||
|
||||
There is a way, if your type is [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
|
||||
There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
|
||||
|
||||
```cpp
|
||||
struct move_only_type {
|
||||
@@ -786,8 +912,8 @@ json j_from_ubjson = json::from_ubjson(v_ubjson);
|
||||
|
||||
Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
|
||||
|
||||
- GCC 4.9 - 7.2 (and possibly later)
|
||||
- Clang 3.4 - 5.0 (and possibly later)
|
||||
- GCC 4.8 - 8.2 (and possibly later)
|
||||
- Clang 3.4 - 6.1 (and possibly later)
|
||||
- Intel C++ Compiler 17.0.2 (and possibly later)
|
||||
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
|
||||
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)
|
||||
@@ -796,7 +922,7 @@ I would be happy to learn about other compilers/versions.
|
||||
|
||||
Please note:
|
||||
|
||||
- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues.
|
||||
- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler.
|
||||
- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.
|
||||
|
||||
```
|
||||
@@ -809,32 +935,40 @@ Please note:
|
||||
|
||||
- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).
|
||||
|
||||
- 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):
|
||||
|
||||
| Compiler | Operating System | Version String |
|
||||
|-----------------|------------------------------|----------------|
|
||||
| GCC 4.9.4 | Ubuntu 14.04.5 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 |
|
||||
| GCC 5.4.1 | Ubuntu 14.04.5 LTS | g++-5 (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904 |
|
||||
| GCC 6.3.0 | Ubuntu 14.04.5 LTS | g++-6 (Ubuntu/Linaro 6.3.0-18ubuntu2~14.04) 6.3.0 20170519 |
|
||||
| GCC 7.1.0 | Ubuntu 14.04.5 LTS | g++-7 (Ubuntu 7.1.0-5ubuntu2~14.04) 7.1.0
|
||||
| Clang 3.5.0 | Ubuntu 14.04.5 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) |
|
||||
| Clang 3.6.2 | Ubuntu 14.04.5 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) |
|
||||
| Clang 3.7.1 | Ubuntu 14.04.5 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) |
|
||||
| Clang 3.8.0 | Ubuntu 14.04.5 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) |
|
||||
| Clang 3.9.1 | Ubuntu 14.04.5 LTS | clang version 3.9.1-4ubuntu3~14.04.2 (tags/RELEASE_391/rc2) |
|
||||
| Clang 4.0.1 | Ubuntu 14.04.5 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) |
|
||||
| Clang 5.0.0 | Ubuntu 14.04.5 LTS | clang version 5.0.0-svn310902-1~exp1 (branches/release_50) |
|
||||
| Clang Xcode 6.4 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) |
|
||||
| Clang Xcode 7.3 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.3.0 (clang-703.0.29) |
|
||||
| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 | Apple LLVM version 8.0.0 (clang-800.0.38) |
|
||||
| Clang Xcode 8.1 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
|
||||
| Clang Xcode 8.2 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
|
||||
| Clang Xcode 8.3 | Darwin Kernel Version 16.5.0 (macOS 10.12.4) | Apple LLVM version 8.1.0 (clang-802.0.38) |
|
||||
| Clang Xcode 9.0 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.37) |
|
||||
| Clang Xcode 9.1 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.38) |
|
||||
| Clang Xcode 9.2 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 8.1.0 (clang-900.0.39.2) |
|
||||
| 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 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 |
|
||||
| GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 |
|
||||
| GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 |
|
||||
| GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 |
|
||||
| GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 |
|
||||
| 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 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 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 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) |
|
||||
| Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) |
|
||||
| Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) |
|
||||
| Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) |
|
||||
| Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) |
|
||||
| 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 Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) |
|
||||
| Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) |
|
||||
| Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
|
||||
| Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
|
||||
| Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) |
|
||||
| Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) |
|
||||
| Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) |
|
||||
| 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) |
|
||||
| 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.5.180.51428, MSVC 19.12.25830.2 |
|
||||
| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 |
|
||||
|
||||
## License
|
||||
|
||||
@@ -862,6 +996,9 @@ If you have questions regarding the library, I would like to invite you to [open
|
||||
|
||||
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).
|
||||
|
||||
## Security
|
||||
|
||||
[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69).
|
||||
|
||||
## Thanks
|
||||
|
||||
@@ -916,7 +1053,7 @@ I deeply appreciate the help of the following people.
|
||||
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
|
||||
- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
|
||||
- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
|
||||
- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
|
||||
- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
|
||||
- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.
|
||||
- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning.
|
||||
- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.
|
||||
@@ -975,14 +1112,39 @@ I deeply appreciate the help of the following people.
|
||||
- [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.
|
||||
- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.
|
||||
- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.
|
||||
- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type
|
||||
- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type.
|
||||
- [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.
|
||||
- [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).
|
||||
- [Carlos O'Ryan](https://github.com/coryan) fixed a typo.
|
||||
- [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section.
|
||||
- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration.
|
||||
- [Jan Schöppach](https://github.com/dns13) fixed a typo.
|
||||
- [martin-mfg](https://github.com/martin-mfg) fixed a typo.
|
||||
- [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`.
|
||||
- [agrianius](https://github.com/agrianius) added code to use alternative string implementations.
|
||||
- [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function.
|
||||
- [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com).
|
||||
- [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode.
|
||||
- [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.
|
||||
- [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library.
|
||||
- [thyu](https://github.com/thyu) fixed a compiler warning.
|
||||
- [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2.
|
||||
- [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library.
|
||||
- [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition.
|
||||
- [Ben Berman](https://github.com/rivertam) made some error messages more understandable.
|
||||
- [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler.
|
||||
- [mandreyel](https://github.com/mandreyel) fixed a compilation problem.
|
||||
- [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file.
|
||||
- [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8.
|
||||
- [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory.
|
||||
- [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning.
|
||||
|
||||
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
||||
|
||||
|
||||
## Used third-party tools
|
||||
|
||||
The library itself contains of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!
|
||||
The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!
|
||||
|
||||
- [**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
|
||||
@@ -1015,7 +1177,7 @@ The library is currently used in Apple macOS Sierra and iOS 10. I am not sure wh
|
||||
|
||||
## Notes
|
||||
|
||||
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) 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_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726).
|
||||
- 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_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) 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_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726).
|
||||
- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), 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](http://rfc7159.net/rfc7159#rfc.section.8.1).
|
||||
|
||||
62
appveyor.yml
62
appveyor.yml
@@ -1,26 +1,58 @@
|
||||
version: '{build}'
|
||||
|
||||
os:
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- additional_flags: ""
|
||||
- additional_flags: "/permissive- /std:c++latest /utf-8"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
COMPILER: mingw
|
||||
platform: x86
|
||||
FLAGS: ""
|
||||
GENERATOR: Ninja
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- additional_flags: "/permissive- /std:c++latest /utf-8"
|
||||
os: Visual Studio 2015
|
||||
|
||||
init: []
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
platform: x86
|
||||
FLAGS: ""
|
||||
GENERATOR: Visual Studio 14 2015
|
||||
|
||||
install: []
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: x86
|
||||
FLAGS: ""
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: x86
|
||||
FLAGS: "/permissive- /std:c++latest /utf-8"
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
platform: x64
|
||||
FLAGS: ""
|
||||
GENERATOR: Visual Studio 14 2015
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: x64
|
||||
FLAGS: ""
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: x64
|
||||
FLAGS: "/permissive- /std:c++latest /utf-8"
|
||||
GENERATOR: Visual Studio 15 2017
|
||||
|
||||
init:
|
||||
- cmake --version
|
||||
- msbuild /version
|
||||
|
||||
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" 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:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH%
|
||||
- if "%COMPILER%"=="mingw" g++ --version
|
||||
|
||||
before_build:
|
||||
- cmake . -G "%GENERATOR%" -DCMAKE_CXX_FLAGS="%FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin"
|
||||
|
||||
build_script:
|
||||
- IF "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" ( SET GEN="Visual Studio 14 2015") ELSE (SET GEN="Visual Studio 15 2017")
|
||||
- cmake . -G%GEN% -DCMAKE_CXX_FLAGS="%additional_flags%"
|
||||
- cmake --build . --config Release
|
||||
|
||||
test_script:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
project(JSON_Benchmarks LANGUAGES CXX)
|
||||
|
||||
# set compiler flags
|
||||
if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -flto -DNDEBUG -O3")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -DNDEBUG -O3")
|
||||
endif()
|
||||
|
||||
# configure Google Benchmarks
|
||||
@@ -23,4 +23,5 @@ file(COPY ${CMAKE_SOURCE_DIR}/../test/data/regression/floats.json
|
||||
|
||||
# benchmark binary
|
||||
add_executable(json_benchmarks src/benchmarks.cpp)
|
||||
target_compile_features(json_benchmarks PRIVATE cxx_std_11)
|
||||
target_link_libraries(json_benchmarks benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
include(FindPackageHandleStandardArgs)
|
||||
set(${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE})
|
||||
find_package_handle_standard_args(@PROJECT_NAME@ CONFIG_MODE)
|
||||
|
||||
if(NOT TARGET @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake")
|
||||
if((NOT TARGET @NLOHMANN_JSON_TARGET_NAME@) AND
|
||||
(NOT @PROJECT_NAME@_FIND_VERSION OR
|
||||
@PROJECT_NAME@_FIND_VERSION VERSION_LESS 3.2.0))
|
||||
add_library(@NLOHMANN_JSON_TARGET_NAME@ INTERFACE IMPORTED)
|
||||
set_target_properties(@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "JSON for Modern C++"
|
||||
PROJECT_NUMBER = 3.1.2
|
||||
PROJECT_NUMBER = 3.3.0
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = .
|
||||
|
||||
BIN
doc/avatars.png
BIN
doc/avatars.png
Binary file not shown.
|
Before Width: | Height: | Size: 568 KiB After Width: | Height: | Size: 726 KiB |
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/TarF5pPn9NtHQjhf"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/RWX63GizBsDZ5EnQ"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/tfI8DuCuZs3VB9VF"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/3OPLSVPyweUyEHaX"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/E1HQedkl1zo48WW5"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/4bn447WQbTERfBaL"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/mya8dUDcDDVoUlBZ"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/AHKW5EMQN4YQ68TY"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/sMmEKxW5MGOgLC7z"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/J0KoQF8sOpdMg4kN"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/qq29jfETq7nZRrh5"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/uuQK0DAjhbSd96K6"><b>online</b></a>
|
||||
60
doc/examples/get_to.cpp
Normal file
60
doc/examples/get_to.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// create a JSON value with different types
|
||||
json json_types =
|
||||
{
|
||||
{"boolean", true},
|
||||
{
|
||||
"number", {
|
||||
{"integer", 42},
|
||||
{"floating-point", 17.23}
|
||||
}
|
||||
},
|
||||
{"string", "Hello, world!"},
|
||||
{"array", {1, 2, 3, 4, 5}},
|
||||
{"null", nullptr}
|
||||
};
|
||||
|
||||
bool v1;
|
||||
int v2;
|
||||
short v3;
|
||||
float v4;
|
||||
int v5;
|
||||
std::string v6;
|
||||
std::vector<short> v7;
|
||||
std::unordered_map<std::string, json> v8;
|
||||
|
||||
|
||||
// use explicit conversions
|
||||
json_types["boolean"].get_to(v1);
|
||||
json_types["number"]["integer"].get_to(v2);
|
||||
json_types["number"]["integer"].get_to(v3);
|
||||
json_types["number"]["floating-point"].get_to(v4);
|
||||
json_types["number"]["floating-point"].get_to(v5);
|
||||
json_types["string"].get_to(v6);
|
||||
json_types["array"].get_to(v7);
|
||||
json_types.get_to(v8);
|
||||
|
||||
// print the conversion results
|
||||
std::cout << v1 << '\n';
|
||||
std::cout << v2 << ' ' << v3 << '\n';
|
||||
std::cout << v4 << ' ' << v5 << '\n';
|
||||
std::cout << v6 << '\n';
|
||||
|
||||
for (auto i : v7)
|
||||
{
|
||||
std::cout << i << ' ';
|
||||
}
|
||||
std::cout << "\n\n";
|
||||
|
||||
for (auto i : v8)
|
||||
{
|
||||
std::cout << i.first << ": " << i.second << '\n';
|
||||
}
|
||||
}
|
||||
1
doc/examples/get_to.link
Normal file
1
doc/examples/get_to.link
Normal file
@@ -0,0 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/QxtxaO6JZAMJPutC"><b>online</b></a>
|
||||
11
doc/examples/get_to.output
Normal file
11
doc/examples/get_to.output
Normal file
@@ -0,0 +1,11 @@
|
||||
1
|
||||
42 42
|
||||
17.23 17
|
||||
Hello, world!
|
||||
1 2 3 4 5
|
||||
|
||||
string: "Hello, world!"
|
||||
number: {"floating-point":17.23,"integer":42}
|
||||
null: null
|
||||
boolean: true
|
||||
array: [1,2,3,4,5]
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/0zdmfNQCe4TMw0iI"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/eFzRNyod3g4aVkvl"><b>online</b></a>
|
||||
@@ -2,7 +2,7 @@
|
||||
"compiler": {
|
||||
"c++": "201103",
|
||||
"family": "clang",
|
||||
"version": "9.0.0 (clang-900.0.39.2)"
|
||||
"version": "10.0.0 (clang-1000.10.43.1)"
|
||||
},
|
||||
"copyright": "(C) 2013-2017 Niels Lohmann",
|
||||
"name": "JSON for Modern C++",
|
||||
@@ -10,8 +10,8 @@
|
||||
"url": "https://github.com/nlohmann/json",
|
||||
"version": {
|
||||
"major": 3,
|
||||
"minor": 1,
|
||||
"patch": 2,
|
||||
"string": "3.1.2"
|
||||
"minor": 3,
|
||||
"patch": 0,
|
||||
"string": "3.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ int main()
|
||||
|
||||
// output values and comparisons
|
||||
std::cout << std::boolalpha;
|
||||
std::cout << array_1 << " == " << array_2 << " " << (array_1 > array_2) << '\n';
|
||||
std::cout << object_1 << " == " << object_2 << " " << (object_1 > object_2) << '\n';
|
||||
std::cout << number_1 << " == " << number_2 << " " << (number_1 > number_2) << '\n';
|
||||
std::cout << string_1 << " == " << string_2 << " " << (string_1 > string_2) << '\n';
|
||||
std::cout << array_1 << " > " << array_2 << " " << (array_1 > array_2) << '\n';
|
||||
std::cout << object_1 << " > " << object_2 << " " << (object_1 > object_2) << '\n';
|
||||
std::cout << number_1 << " > " << number_2 << " " << (number_1 > number_2) << '\n';
|
||||
std::cout << string_1 << " > " << string_2 << " " << (string_1 > string_2) << '\n';
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/yiz7oCHVpFHSALB1"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/ntF7DMzC85gbQKHu"><b>online</b></a>
|
||||
@@ -1,4 +1,4 @@
|
||||
[1,2,3] == [1,2,4] false
|
||||
{"A":"a","B":"b"} == {"A":"a","B":"b"} false
|
||||
17 == 17.0000000000001 false
|
||||
"foo" == "bar" true
|
||||
[1,2,3] > [1,2,4] false
|
||||
{"A":"a","B":"b"} > {"A":"a","B":"b"} false
|
||||
17 > 17.0000000000001 false
|
||||
"foo" > "bar" true
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/YrUqrUFMD7JHwSQR"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/IvgowYGaX0SgOFIG"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/wXcm4ObnoaXw7CRt"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/ckGZIBookDffV00n"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/vxt8d8qvYorXS2yq"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/oKnfnFrLHG8H1OAl"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/TSNxHmegVwLW2pXf"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/i3BBhl7Ub5y9b0yp"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/l3zNo3YKC2X8yAw9"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/sGdJMOaJnFNJBtH7"><b>online</b></a>
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/Mf7A6JtvqT1Na7Pk"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/UZgRBIeqdZhm6M8F"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/oa6BVkBXjG8DNkzX"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/VThe0hdMSUdNSOLK"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/QXdl4yzts3qPeZ0U"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/QZgjsR0PiAw2Lqpk"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/8ObNa6ejw4BXQ5qG"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/hFd1W46W2Hb81sHN"><b>online</b></a>
|
||||
124
doc/examples/sax_parse.cpp
Normal file
124
doc/examples/sax_parse.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// a simple event consumer that collects string representations of the passed
|
||||
// values; not inheriting from json::json_sax_t is not required, but can
|
||||
// help not to forget a required function
|
||||
class sax_event_consumer : public json::json_sax_t
|
||||
{
|
||||
public:
|
||||
std::vector<std::string> events;
|
||||
|
||||
bool null() override
|
||||
{
|
||||
events.push_back("value: null");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool val) override
|
||||
{
|
||||
events.push_back("value: " + std::string(val ? "true" : "false"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t val) override
|
||||
{
|
||||
events.push_back("value: " + std::to_string(val));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t val) override
|
||||
{
|
||||
events.push_back("value: " + std::to_string(val));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t& s) override
|
||||
{
|
||||
events.push_back("value: " + s);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t& val) override
|
||||
{
|
||||
events.push_back("value: " + val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t elements) override
|
||||
{
|
||||
events.push_back("start: object");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_object() override
|
||||
{
|
||||
events.push_back("end: object");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t elements) override
|
||||
{
|
||||
events.push_back("start: array");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_array() override
|
||||
{
|
||||
events.push_back("end: array");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t& val) override
|
||||
{
|
||||
events.push_back("key: " + val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override
|
||||
{
|
||||
events.push_back("error: " + std::string(ex.what()));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text
|
||||
auto text = R"(
|
||||
{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
"Height": 600,
|
||||
"Title": "View from 15th Floor",
|
||||
"Thumbnail": {
|
||||
"Url": "http://www.example.com/image/481989943",
|
||||
"Height": 125,
|
||||
"Width": 100
|
||||
},
|
||||
"Animated" : false,
|
||||
"IDs": [116, 943, 234, 38793],
|
||||
"Distance": 12.723374634
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
// create a SAX event consumer object
|
||||
sax_event_consumer sec;
|
||||
|
||||
// parse and serialize JSON
|
||||
bool result = json::sax_parse(text, &sec);
|
||||
|
||||
// output the recorded events
|
||||
for (auto& event : sec.events)
|
||||
{
|
||||
std::cout << "(" << event << ") ";
|
||||
}
|
||||
|
||||
// output the result of sax_parse
|
||||
std::cout << "\nresult: " << std::boolalpha << result << std::endl;
|
||||
}
|
||||
1
doc/examples/sax_parse.link
Normal file
1
doc/examples/sax_parse.link
Normal file
@@ -0,0 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/fGkQLWbQn7enKkIG"><b>online</b></a>
|
||||
2
doc/examples/sax_parse.output
Normal file
2
doc/examples/sax_parse.output
Normal file
@@ -0,0 +1,2 @@
|
||||
(start: object) (key: Image) (start: object) (key: Width) (value: 800) (key: Height) (value: 600) (key: Title) (value: View from 15th Floor) (key: Thumbnail) (start: object) (key: Url) (value: http://www.example.com/image/481989943) (key: Height) (value: 125) (key: Width) (value: 100) (end: object) (key: Animated) (value: false) (key: IDs) (start: array) (value: 116) (value: 943) (value: 234) (value: 38793) (end: array) (key: Distance) (value: 12.723374634) (end: object) (end: object)
|
||||
result: true
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/4bQSclXeqjVFYVL3"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/LRM37xarSuPJmv92"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/WvT2Q0r9vlJYyMM8"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/CaRFhkrefL4miesE"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/j3HE6cOkCmKbxxAt"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/2luqHy9iADx4UNm7"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/U45AGi5nsDtoDf3u"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/knK4jnD2hIVxQoyk"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/TGvdYyJtstacZxWq"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/kjcoWACW7FMqKRBG"><b>online</b></a>
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/BMlas6312rkE4cxz"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/0LBIsEa18IrerWwy"><b>online</b></a>
|
||||
@@ -39,9 +39,11 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
|
||||
- @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
|
||||
- deserialization / parsing
|
||||
- @link nlohmann::basic_json::parse parse @endlink parse from string
|
||||
- @link nlohmann::basic_json::parse parse @endlink parse from input (string, file, etc.) and return JSON value
|
||||
- @link nlohmann::basic_json::sax_parse sax_parse @endlink parse from input (string, file, etc.) and generate SAX events
|
||||
- @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::json_sax SAX interface @endlink define a user-defined SAX event consumer
|
||||
- [binary formats](binary_formats.md):
|
||||
- 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
|
||||
@@ -304,4 +306,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins
|
||||
@author [Niels Lohmann](http://nlohmann.me)
|
||||
@see https://github.com/nlohmann/json to download the source code
|
||||
|
||||
@version 3.1.2
|
||||
@version 3.3.0
|
||||
|
||||
BIN
doc/json.gif
BIN
doc/json.gif
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.6 MiB |
@@ -20,8 +20,10 @@ struct adl_serializer
|
||||
@param[in,out] val value to write to
|
||||
*/
|
||||
template<typename BasicJsonType, typename ValueType>
|
||||
static void from_json(BasicJsonType&& j, ValueType& val) noexcept(
|
||||
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
|
||||
static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(
|
||||
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype(
|
||||
::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()
|
||||
)
|
||||
{
|
||||
::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
|
||||
}
|
||||
@@ -35,9 +37,11 @@ struct adl_serializer
|
||||
@param[in,out] j JSON value to write to
|
||||
@param[in] val value to read from
|
||||
*/
|
||||
template<typename BasicJsonType, typename ValueType>
|
||||
static void to_json(BasicJsonType& j, ValueType&& val) noexcept(
|
||||
template <typename BasicJsonType, typename ValueType>
|
||||
static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
|
||||
noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
|
||||
-> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)),
|
||||
void())
|
||||
{
|
||||
::nlohmann::to_json(j, std::forward<ValueType>(val));
|
||||
}
|
||||
|
||||
@@ -5,21 +5,34 @@
|
||||
#include <ciso646> // and, not
|
||||
#include <forward_list> // forward_list
|
||||
#include <iterator> // inserter, front_inserter, end
|
||||
#include <map> // map
|
||||
#include <string> // string
|
||||
#include <tuple> // tuple, make_tuple
|
||||
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
|
||||
#include <unordered_map> // unordered_map
|
||||
#include <utility> // pair, declval
|
||||
#include <valarray> // valarray
|
||||
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_null()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
|
||||
}
|
||||
n = nullptr;
|
||||
}
|
||||
|
||||
// overloads for basic_json template parameters
|
||||
template<typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t<std::is_arithmetic<ArithmeticType>::value and
|
||||
@@ -70,6 +83,23 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template <
|
||||
typename BasicJsonType, typename CompatibleStringType,
|
||||
enable_if_t <
|
||||
is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
|
||||
not std::is_same<typename BasicJsonType::string_t,
|
||||
CompatibleStringType>::value,
|
||||
int > = 0 >
|
||||
void from_json(const BasicJsonType& j, CompatibleStringType& s)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_string()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
|
||||
}
|
||||
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||
{
|
||||
@@ -97,16 +127,6 @@ void from_json(const BasicJsonType& j, EnumType& e)
|
||||
e = static_cast<EnumType>(val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
}
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
|
||||
// forward_list doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T, typename Allocator,
|
||||
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
|
||||
@@ -136,24 +156,28 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/)
|
||||
template<typename BasicJsonType>
|
||||
void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||
{
|
||||
using std::end;
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
|
||||
std::transform(j.begin(), j.end(),
|
||||
std::inserter(arr, end(arr)), [](const BasicJsonType & i)
|
||||
template <typename BasicJsonType, typename T, std::size_t N>
|
||||
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||
priority_tag<2> /*unused*/)
|
||||
-> decltype(j.template get<T>(), void())
|
||||
{
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||
// method when value_type is BasicJsonType
|
||||
return i.template get<typename CompatibleArrayType::value_type>();
|
||||
});
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
|
||||
-> decltype(
|
||||
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
|
||||
j.template get<typename CompatibleArrayType::value_type>(),
|
||||
void())
|
||||
{
|
||||
using std::end;
|
||||
@@ -168,25 +192,34 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio
|
||||
});
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/)
|
||||
template <typename BasicJsonType, typename CompatibleArrayType>
|
||||
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
|
||||
priority_tag<0> /*unused*/)
|
||||
{
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
using std::end;
|
||||
|
||||
std::transform(
|
||||
j.begin(), j.end(), std::inserter(arr, end(arr)),
|
||||
[](const BasicJsonType & i)
|
||||
{
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
}
|
||||
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||
// method when value_type is BasicJsonType
|
||||
return i.template get<typename CompatibleArrayType::value_type>();
|
||||
});
|
||||
}
|
||||
|
||||
template <
|
||||
typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t <
|
||||
is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
|
||||
not std::is_same<typename BasicJsonType::array_t,
|
||||
CompatibleArrayType>::value and
|
||||
std::is_constructible <
|
||||
BasicJsonType, typename CompatibleArrayType::value_type >::value,
|
||||
int > = 0 >
|
||||
void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
|
||||
template <typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t <
|
||||
is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
|
||||
not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
|
||||
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
|
||||
not is_basic_json<CompatibleArrayType>::value,
|
||||
int > = 0 >
|
||||
|
||||
auto from_json(const BasicJsonType& j, CompatibleArrayType& arr)
|
||||
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
|
||||
j.template get<typename CompatibleArrayType::value_type>(),
|
||||
void())
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
@@ -194,7 +227,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
|
||||
std::string(j.type_name())));
|
||||
}
|
||||
|
||||
from_json_array_impl(j, arr, priority_tag<2> {});
|
||||
from_json_array_impl(j, arr, priority_tag<3> {});
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleObjectType,
|
||||
@@ -277,37 +310,53 @@ void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
|
||||
from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
|
||||
}
|
||||
|
||||
template <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||
typename = enable_if_t<not std::is_constructible<
|
||||
typename BasicJsonType::string_t, Key>::value>>
|
||||
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
}
|
||||
for (const auto& p : j)
|
||||
{
|
||||
if (JSON_UNLIKELY(not p.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
|
||||
}
|
||||
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||
typename = enable_if_t<not std::is_constructible<
|
||||
typename BasicJsonType::string_t, Key>::value>>
|
||||
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
}
|
||||
for (const auto& p : j)
|
||||
{
|
||||
if (JSON_UNLIKELY(not p.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
|
||||
}
|
||||
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
|
||||
}
|
||||
}
|
||||
|
||||
struct from_json_fn
|
||||
{
|
||||
private:
|
||||
template<typename BasicJsonType, typename T>
|
||||
auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const
|
||||
auto operator()(const BasicJsonType& j, T& val) const
|
||||
noexcept(noexcept(from_json(j, val)))
|
||||
-> decltype(from_json(j, val), void())
|
||||
{
|
||||
return from_json(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T>
|
||||
void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept
|
||||
{
|
||||
static_assert(sizeof(BasicJsonType) == 0,
|
||||
"could not find from_json() method in T's namespace");
|
||||
#ifdef _MSC_VER
|
||||
// MSVC does not show a stacktrace for the above assert
|
||||
using decayed = uncvref_t<T>;
|
||||
static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
|
||||
"forcing MSVC stacktrace to show which T we're talking about.");
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename BasicJsonType, typename T>
|
||||
void operator()(const BasicJsonType& j, T& val) const
|
||||
noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
|
||||
{
|
||||
return call(j, val, priority_tag<1> {});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
||||
// numbers, all float's can be recovered using strtod (and strtof). However, the resulting
|
||||
// decimal representations are not exactly "short".
|
||||
//
|
||||
// The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars)
|
||||
// The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
|
||||
// says "value is converted to a string as if by std::sprintf in the default ("C") locale"
|
||||
// and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
|
||||
// does.
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#include <valarray> // valarray
|
||||
#include <vector> // vector
|
||||
|
||||
#include <nlohmann/detail/meta.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
@@ -51,6 +53,16 @@ struct external_constructor<value_t::string>
|
||||
j.m_value = std::move(s);
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleStringType,
|
||||
enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
|
||||
int> = 0>
|
||||
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||
{
|
||||
j.m_type = value_t::string;
|
||||
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
||||
j.assert_invariant();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -236,10 +248,14 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e)
|
||||
external_constructor<value_t::array>::construct(j, e);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or
|
||||
std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value,
|
||||
int> = 0>
|
||||
template <typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t<is_compatible_array_type<BasicJsonType,
|
||||
CompatibleArrayType>::value and
|
||||
not is_compatible_object_type<
|
||||
BasicJsonType, CompatibleArrayType>::value and
|
||||
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
|
||||
not is_basic_json<CompatibleArrayType>::value,
|
||||
int> = 0>
|
||||
void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
@@ -247,7 +263,7 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, std::valarray<T> arr)
|
||||
void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, std::move(arr));
|
||||
}
|
||||
@@ -259,7 +275,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleObjectType,
|
||||
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
|
||||
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
|
||||
{
|
||||
external_constructor<value_t::object>::construct(j, obj);
|
||||
@@ -271,9 +287,12 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
external_constructor<value_t::object>::construct(j, std::move(obj));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, std::size_t N,
|
||||
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, T (&)[N]>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, T (&arr)[N])
|
||||
template <
|
||||
typename BasicJsonType, typename T, std::size_t N,
|
||||
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
|
||||
const T (&)[N]>::value,
|
||||
int> = 0 >
|
||||
void to_json(BasicJsonType& j, const T (&arr)[N])
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
}
|
||||
@@ -284,6 +303,14 @@ void to_json(BasicJsonType& j, const std::pair<Args...>& p)
|
||||
j = {p.first, p.second};
|
||||
}
|
||||
|
||||
// for https://github.com/nlohmann/json/pull/1134
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<std::is_same<T, typename iteration_proxy<typename BasicJsonType::iterator>::iteration_proxy_internal>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, T b) noexcept
|
||||
{
|
||||
j = {{b.key(), b.value()}};
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
|
||||
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>)
|
||||
{
|
||||
@@ -298,35 +325,12 @@ void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
|
||||
|
||||
struct to_json_fn
|
||||
{
|
||||
private:
|
||||
template<typename BasicJsonType, typename T>
|
||||
auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
|
||||
auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
|
||||
-> decltype(to_json(j, std::forward<T>(val)), void())
|
||||
{
|
||||
return to_json(j, std::forward<T>(val));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T>
|
||||
void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept
|
||||
{
|
||||
static_assert(sizeof(BasicJsonType) == 0,
|
||||
"could not find to_json() method in T's namespace");
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// MSVC does not show a stacktrace for the above assert
|
||||
using decayed = uncvref_t<T>;
|
||||
static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
|
||||
"forcing MSVC stacktrace to show which T we're talking about.");
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename BasicJsonType, typename T>
|
||||
void operator()(BasicJsonType& j, T&& val) const
|
||||
noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
|
||||
{
|
||||
return call(j, std::forward<T>(val), priority_tag<1> {});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // min
|
||||
#include <array> // array
|
||||
#include <cassert> // assert
|
||||
#include <cstddef> // size_t
|
||||
#include <cstring> // strlen
|
||||
#include <ios> // streamsize, streamoff, streampos
|
||||
#include <istream> // istream
|
||||
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
|
||||
#include <memory> // shared_ptr, make_shared, addressof
|
||||
@@ -20,6 +17,9 @@ namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// the supported input formats
|
||||
enum class input_format_t { json, cbor, msgpack, ubjson };
|
||||
|
||||
////////////////////
|
||||
// input adapters //
|
||||
////////////////////
|
||||
@@ -28,19 +28,17 @@ namespace detail
|
||||
@brief abstract input adapter interface
|
||||
|
||||
Produces a stream of std::char_traits<char>::int_type characters from a
|
||||
std::istream, a buffer, or some other input type. Accepts the return of exactly
|
||||
one non-EOF character for future input. The int_type characters returned
|
||||
consist of all valid char values as positive values (typically unsigned char),
|
||||
plus an EOF value outside that range, specified by the value of the function
|
||||
std::char_traits<char>::eof(). This value is typically -1, but could be any
|
||||
arbitrary value which is not a valid char value.
|
||||
std::istream, a buffer, or some other input type. Accepts the return of
|
||||
exactly one non-EOF character for future input. The int_type characters
|
||||
returned consist of all valid char values as positive values (typically
|
||||
unsigned char), plus an EOF value outside that range, specified by the value
|
||||
of the function std::char_traits<char>::eof(). This value is typically -1, but
|
||||
could be any arbitrary value which is not a valid char value.
|
||||
*/
|
||||
struct input_adapter_protocol
|
||||
{
|
||||
/// get a character [0,255] or std::char_traits<char>::eof().
|
||||
virtual std::char_traits<char>::int_type get_character() = 0;
|
||||
/// restore the last non-eof() character to input
|
||||
virtual void unget_character() = 0;
|
||||
virtual ~input_adapter_protocol() = default;
|
||||
};
|
||||
|
||||
@@ -68,34 +66,7 @@ class input_stream_adapter : public input_adapter_protocol
|
||||
|
||||
explicit input_stream_adapter(std::istream& i)
|
||||
: is(i), sb(*i.rdbuf())
|
||||
{
|
||||
// skip byte order mark
|
||||
std::char_traits<char>::int_type c;
|
||||
if ((c = get_character()) == 0xEF)
|
||||
{
|
||||
if ((c = get_character()) == 0xBB)
|
||||
{
|
||||
if ((c = get_character()) == 0xBF)
|
||||
{
|
||||
return; // Ignore BOM
|
||||
}
|
||||
else if (c != std::char_traits<char>::eof())
|
||||
{
|
||||
is.unget();
|
||||
}
|
||||
is.putback('\xBB');
|
||||
}
|
||||
else if (c != std::char_traits<char>::eof())
|
||||
{
|
||||
is.unget();
|
||||
}
|
||||
is.putback('\xEF');
|
||||
}
|
||||
else if (c != std::char_traits<char>::eof())
|
||||
{
|
||||
is.unget(); // no byte order mark; process as usual
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
// delete because of pointer members
|
||||
input_stream_adapter(const input_stream_adapter&) = delete;
|
||||
@@ -109,11 +80,6 @@ class input_stream_adapter : public input_adapter_protocol
|
||||
return sb.sbumpc();
|
||||
}
|
||||
|
||||
void unget_character() override
|
||||
{
|
||||
sb.sungetc(); // is.unget() avoided for performance
|
||||
}
|
||||
|
||||
private:
|
||||
/// the associated input stream
|
||||
std::istream& is;
|
||||
@@ -125,14 +91,8 @@ class input_buffer_adapter : public input_adapter_protocol
|
||||
{
|
||||
public:
|
||||
input_buffer_adapter(const char* b, const std::size_t l)
|
||||
: cursor(b), limit(b + l), start(b)
|
||||
{
|
||||
// skip byte order mark
|
||||
if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF')
|
||||
{
|
||||
cursor += 3;
|
||||
}
|
||||
}
|
||||
: cursor(b), limit(b + l)
|
||||
{}
|
||||
|
||||
// delete because of pointer members
|
||||
input_buffer_adapter(const input_buffer_adapter&) = delete;
|
||||
@@ -148,21 +108,172 @@ class input_buffer_adapter : public input_adapter_protocol
|
||||
return std::char_traits<char>::eof();
|
||||
}
|
||||
|
||||
void unget_character() noexcept override
|
||||
{
|
||||
if (JSON_LIKELY(cursor > start))
|
||||
{
|
||||
--cursor;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// pointer to the current character
|
||||
const char* cursor;
|
||||
/// pointer past the last character
|
||||
const char* limit;
|
||||
/// pointer to the first character
|
||||
const char* start;
|
||||
const char* const limit;
|
||||
};
|
||||
|
||||
template<typename WideStringType, size_t T>
|
||||
struct wide_string_input_helper
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
utf8_bytes_index = 0;
|
||||
|
||||
if (current_wchar == str.size())
|
||||
{
|
||||
utf8_bytes[0] = std::char_traits<char>::eof();
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the current character
|
||||
const int wc = static_cast<int>(str[current_wchar++]);
|
||||
|
||||
// UTF-32 to UTF-8 encoding
|
||||
if (wc < 0x80)
|
||||
{
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else if (wc <= 0x7FF)
|
||||
{
|
||||
utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
|
||||
utf8_bytes[1] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 2;
|
||||
}
|
||||
else if (wc <= 0xFFFF)
|
||||
{
|
||||
utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 3;
|
||||
}
|
||||
else if (wc <= 0x10FFFF)
|
||||
{
|
||||
utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07);
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[3] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown character
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WideStringType>
|
||||
struct wide_string_input_helper<WideStringType, 2>
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
utf8_bytes_index = 0;
|
||||
|
||||
if (current_wchar == str.size())
|
||||
{
|
||||
utf8_bytes[0] = std::char_traits<char>::eof();
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the current character
|
||||
const int wc = static_cast<int>(str[current_wchar++]);
|
||||
|
||||
// UTF-16 to UTF-8 encoding
|
||||
if (wc < 0x80)
|
||||
{
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else if (wc <= 0x7FF)
|
||||
{
|
||||
utf8_bytes[0] = 0xC0 | ((wc >> 6));
|
||||
utf8_bytes[1] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 2;
|
||||
}
|
||||
else if (0xD800 > wc or wc >= 0xE000)
|
||||
{
|
||||
utf8_bytes[0] = 0xE0 | ((wc >> 12));
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current_wchar < str.size())
|
||||
{
|
||||
const int wc2 = static_cast<int>(str[current_wchar++]);
|
||||
const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
|
||||
utf8_bytes[0] = 0xf0 | (charcode >> 18);
|
||||
utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
|
||||
utf8_bytes[3] = 0x80 | (charcode & 0x3F);
|
||||
utf8_bytes_filled = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown character
|
||||
++current_wchar;
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WideStringType>
|
||||
class wide_string_input_adapter : public input_adapter_protocol
|
||||
{
|
||||
public:
|
||||
explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
|
||||
|
||||
std::char_traits<char>::int_type get_character() noexcept override
|
||||
{
|
||||
// check if buffer needs to be filled
|
||||
if (utf8_bytes_index == utf8_bytes_filled)
|
||||
{
|
||||
fill_buffer<sizeof(typename WideStringType::value_type)>();
|
||||
|
||||
assert(utf8_bytes_filled > 0);
|
||||
assert(utf8_bytes_index == 0);
|
||||
}
|
||||
|
||||
// use buffer
|
||||
assert(utf8_bytes_filled > 0);
|
||||
assert(utf8_bytes_index < utf8_bytes_filled);
|
||||
return utf8_bytes[utf8_bytes_index++];
|
||||
}
|
||||
|
||||
private:
|
||||
template<size_t T>
|
||||
void fill_buffer()
|
||||
{
|
||||
wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
|
||||
}
|
||||
|
||||
/// the wstring to process
|
||||
const WideStringType& str;
|
||||
|
||||
/// index of the current wchar in str
|
||||
std::size_t current_wchar = 0;
|
||||
|
||||
/// a buffer for UTF-8 bytes
|
||||
std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
|
||||
|
||||
/// index to the utf8_codes array for the next valid byte
|
||||
std::size_t utf8_bytes_index = 0;
|
||||
/// number of valid bytes in the utf8_codes array
|
||||
std::size_t utf8_bytes_filled = 0;
|
||||
};
|
||||
|
||||
class input_adapter
|
||||
@@ -178,6 +289,15 @@ class input_adapter
|
||||
input_adapter(std::istream&& i)
|
||||
: ia(std::make_shared<input_stream_adapter>(i)) {}
|
||||
|
||||
input_adapter(const std::wstring& ws)
|
||||
: ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}
|
||||
|
||||
input_adapter(const std::u16string& ws)
|
||||
: ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
|
||||
|
||||
input_adapter(const std::u32string& ws)
|
||||
: ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
|
||||
|
||||
/// input adapter for buffer
|
||||
template<typename CharT,
|
||||
typename std::enable_if<
|
||||
@@ -208,15 +328,18 @@ class input_adapter
|
||||
int>::type = 0>
|
||||
input_adapter(IteratorType first, IteratorType last)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// assertion to check that the iterator range is indeed contiguous,
|
||||
// see http://stackoverflow.com/a/35008842/266378 for more discussion
|
||||
assert(std::accumulate(
|
||||
first, last, std::pair<bool, int>(true, 0),
|
||||
[&first](std::pair<bool, int> res, decltype(*first) val)
|
||||
const auto is_contiguous = std::accumulate(
|
||||
first, last, std::pair<bool, int>(true, 0),
|
||||
[&first](std::pair<bool, int> res, decltype(*first) val)
|
||||
{
|
||||
res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
|
||||
return res;
|
||||
}).first);
|
||||
}).first;
|
||||
assert(is_contiguous);
|
||||
#endif
|
||||
|
||||
// assertion to check that each element is 1 byte long
|
||||
static_assert(
|
||||
|
||||
702
include/nlohmann/detail/input/json_sax.hpp
Normal file
702
include/nlohmann/detail/input/json_sax.hpp
Normal file
@@ -0,0 +1,702 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/detail/input/parser.hpp>
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
/*!
|
||||
@brief SAX interface
|
||||
|
||||
This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
|
||||
Each function is called in different situations while the input is parsed. The
|
||||
boolean return value informs the parser whether to continue processing the
|
||||
input.
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
struct json_sax
|
||||
{
|
||||
/// type for (signed) integers
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
/// type for unsigned integers
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
/// type for floating-point numbers
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
/// type for strings
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
|
||||
/*!
|
||||
@brief a null value was read
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool null() = 0;
|
||||
|
||||
/*!
|
||||
@brief a boolean value was read
|
||||
@param[in] val boolean value
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool boolean(bool val) = 0;
|
||||
|
||||
/*!
|
||||
@brief an integer number was read
|
||||
@param[in] val integer value
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool number_integer(number_integer_t val) = 0;
|
||||
|
||||
/*!
|
||||
@brief an unsigned integer number was read
|
||||
@param[in] val unsigned integer value
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool number_unsigned(number_unsigned_t val) = 0;
|
||||
|
||||
/*!
|
||||
@brief an floating-point number was read
|
||||
@param[in] val floating-point value
|
||||
@param[in] s raw token value
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool number_float(number_float_t val, const string_t& s) = 0;
|
||||
|
||||
/*!
|
||||
@brief a string was read
|
||||
@param[in] val string value
|
||||
@return whether parsing should proceed
|
||||
@note It is safe to move the passed string.
|
||||
*/
|
||||
virtual bool string(string_t& val) = 0;
|
||||
|
||||
/*!
|
||||
@brief the beginning of an object was read
|
||||
@param[in] elements number of object elements or -1 if unknown
|
||||
@return whether parsing should proceed
|
||||
@note binary formats may report the number of elements
|
||||
*/
|
||||
virtual bool start_object(std::size_t elements) = 0;
|
||||
|
||||
/*!
|
||||
@brief an object key was read
|
||||
@param[in] val object key
|
||||
@return whether parsing should proceed
|
||||
@note It is safe to move the passed string.
|
||||
*/
|
||||
virtual bool key(string_t& val) = 0;
|
||||
|
||||
/*!
|
||||
@brief the end of an object was read
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool end_object() = 0;
|
||||
|
||||
/*!
|
||||
@brief the beginning of an array was read
|
||||
@param[in] elements number of array elements or -1 if unknown
|
||||
@return whether parsing should proceed
|
||||
@note binary formats may report the number of elements
|
||||
*/
|
||||
virtual bool start_array(std::size_t elements) = 0;
|
||||
|
||||
/*!
|
||||
@brief the end of an array was read
|
||||
@return whether parsing should proceed
|
||||
*/
|
||||
virtual bool end_array() = 0;
|
||||
|
||||
/*!
|
||||
@brief a parse error occurred
|
||||
@param[in] position the position in the input where the error occurs
|
||||
@param[in] last_token the last read token
|
||||
@param[in] error_msg a detailed error message
|
||||
@return whether parsing should proceed (must return false)
|
||||
*/
|
||||
virtual bool parse_error(std::size_t position,
|
||||
const std::string& last_token,
|
||||
const detail::exception& ex) = 0;
|
||||
|
||||
virtual ~json_sax() = default;
|
||||
};
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/*!
|
||||
@brief SAX implementation to create a JSON value from SAX events
|
||||
|
||||
This class implements the @ref json_sax interface and processes the SAX events
|
||||
to create a JSON value which makes it basically a DOM parser. The structure or
|
||||
hierarchy of the JSON value is managed by the stack `ref_stack` which contains
|
||||
a pointer to the respective array or object for each recursion depth.
|
||||
|
||||
After successful parsing, the value that is passed by reference to the
|
||||
constructor contains the parsed value.
|
||||
|
||||
@tparam BasicJsonType the JSON type
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
class json_sax_dom_parser
|
||||
{
|
||||
public:
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
|
||||
/*!
|
||||
@param[in, out] r reference to a JSON value that is manipulated while
|
||||
parsing
|
||||
@param[in] allow_exceptions_ whether parse errors yield exceptions
|
||||
*/
|
||||
explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
|
||||
: root(r), allow_exceptions(allow_exceptions_)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
handle_value(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t&)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t& val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t len)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(408,
|
||||
"excessive object size: " + std::to_string(len)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t& val)
|
||||
{
|
||||
// add null at given key and store the reference for later
|
||||
object_element = &(ref_stack.back()->m_value.object->operator[](val));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
ref_stack.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t len)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(408,
|
||||
"excessive array size: " + std::to_string(len)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
ref_stack.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&,
|
||||
const detail::exception& ex)
|
||||
{
|
||||
errored = true;
|
||||
if (allow_exceptions)
|
||||
{
|
||||
// determine the proper exception type from the id
|
||||
switch ((ex.id / 100) % 100)
|
||||
{
|
||||
case 1:
|
||||
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
|
||||
case 4:
|
||||
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
|
||||
// LCOV_EXCL_START
|
||||
case 2:
|
||||
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
|
||||
case 3:
|
||||
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
|
||||
case 5:
|
||||
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
|
||||
default:
|
||||
assert(false);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool is_errored() const
|
||||
{
|
||||
return errored;
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
@invariant If the ref stack is empty, then the passed value will be the new
|
||||
root.
|
||||
@invariant If the ref stack contains a value, then it is an array or an
|
||||
object to which we can add elements
|
||||
*/
|
||||
template<typename Value>
|
||||
BasicJsonType* handle_value(Value&& v)
|
||||
{
|
||||
if (ref_stack.empty())
|
||||
{
|
||||
root = BasicJsonType(std::forward<Value>(v));
|
||||
return &root;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
|
||||
return &(ref_stack.back()->m_value.array->back());
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(object_element);
|
||||
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||
return object_element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// the parsed JSON value
|
||||
BasicJsonType& root;
|
||||
/// stack to model hierarchy of values
|
||||
std::vector<BasicJsonType*> ref_stack;
|
||||
/// helper to hold the reference for the next object element
|
||||
BasicJsonType* object_element = nullptr;
|
||||
/// whether a syntax error occurred
|
||||
bool errored = false;
|
||||
/// whether to throw exceptions in case of errors
|
||||
const bool allow_exceptions = true;
|
||||
};
|
||||
|
||||
template<typename BasicJsonType>
|
||||
class json_sax_dom_callback_parser
|
||||
{
|
||||
public:
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using parser_callback_t = typename BasicJsonType::parser_callback_t;
|
||||
using parse_event_t = typename BasicJsonType::parse_event_t;
|
||||
|
||||
json_sax_dom_callback_parser(BasicJsonType& r,
|
||||
const parser_callback_t cb,
|
||||
const bool allow_exceptions_ = true)
|
||||
: root(r), callback(cb), allow_exceptions(allow_exceptions_)
|
||||
{
|
||||
keep_stack.push_back(true);
|
||||
}
|
||||
|
||||
bool null()
|
||||
{
|
||||
handle_value(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t&)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t& val)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t len)
|
||||
{
|
||||
// check callback for object start
|
||||
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
|
||||
keep_stack.push_back(keep);
|
||||
|
||||
auto val = handle_value(BasicJsonType::value_t::object, true);
|
||||
ref_stack.push_back(val.second);
|
||||
|
||||
// check object limit
|
||||
if (ref_stack.back())
|
||||
{
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t& val)
|
||||
{
|
||||
BasicJsonType k = BasicJsonType(val);
|
||||
|
||||
// check callback for key
|
||||
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
|
||||
key_keep_stack.push_back(keep);
|
||||
|
||||
// add discarded value at given key and store the reference for later
|
||||
if (keep and ref_stack.back())
|
||||
{
|
||||
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
|
||||
assert(not ref_stack.empty());
|
||||
assert(not keep_stack.empty());
|
||||
ref_stack.pop_back();
|
||||
keep_stack.pop_back();
|
||||
|
||||
if (not ref_stack.empty() and ref_stack.back())
|
||||
{
|
||||
// remove discarded value
|
||||
if (ref_stack.back()->is_object())
|
||||
{
|
||||
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
|
||||
{
|
||||
if (it->is_discarded())
|
||||
{
|
||||
ref_stack.back()->erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t len)
|
||||
{
|
||||
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
|
||||
keep_stack.push_back(keep);
|
||||
|
||||
auto val = handle_value(BasicJsonType::value_t::array, true);
|
||||
ref_stack.push_back(val.second);
|
||||
|
||||
// check array limit
|
||||
if (ref_stack.back())
|
||||
{
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
bool keep = true;
|
||||
|
||||
if (ref_stack.back())
|
||||
{
|
||||
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
|
||||
if (not keep)
|
||||
{
|
||||
// discard array
|
||||
*ref_stack.back() = discarded;
|
||||
}
|
||||
}
|
||||
|
||||
assert(not ref_stack.empty());
|
||||
assert(not keep_stack.empty());
|
||||
ref_stack.pop_back();
|
||||
keep_stack.pop_back();
|
||||
|
||||
// remove discarded value
|
||||
if (not keep and not ref_stack.empty())
|
||||
{
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&,
|
||||
const detail::exception& ex)
|
||||
{
|
||||
errored = true;
|
||||
if (allow_exceptions)
|
||||
{
|
||||
// determine the proper exception type from the id
|
||||
switch ((ex.id / 100) % 100)
|
||||
{
|
||||
case 1:
|
||||
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
|
||||
case 4:
|
||||
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
|
||||
// LCOV_EXCL_START
|
||||
case 2:
|
||||
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
|
||||
case 3:
|
||||
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
|
||||
case 5:
|
||||
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
|
||||
default:
|
||||
assert(false);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool is_errored() const
|
||||
{
|
||||
return errored;
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
@param[in] v value to add to the JSON value we build during parsing
|
||||
@param[in] skip_callback whether we should skip calling the callback
|
||||
function; this is required after start_array() and
|
||||
start_object() SAX events, because otherwise we would call the
|
||||
callback function with an empty array or object, respectively.
|
||||
|
||||
@invariant If the ref stack is empty, then the passed value will be the new
|
||||
root.
|
||||
@invariant If the ref stack contains a value, then it is an array or an
|
||||
object to which we can add elements
|
||||
|
||||
@return pair of boolean (whether value should be kept) and pointer (to the
|
||||
passed value in the ref_stack hierarchy; nullptr if not kept)
|
||||
*/
|
||||
template<typename Value>
|
||||
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
|
||||
{
|
||||
assert(not keep_stack.empty());
|
||||
|
||||
// do not handle this value if we know it would be added to a discarded
|
||||
// container
|
||||
if (not keep_stack.back())
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
// create value
|
||||
auto value = BasicJsonType(std::forward<Value>(v));
|
||||
|
||||
// check callback
|
||||
const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
|
||||
|
||||
// do not handle this value if we just learnt it shall be discarded
|
||||
if (not keep)
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
if (ref_stack.empty())
|
||||
{
|
||||
root = std::move(value);
|
||||
return {true, &root};
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip this value if we already decided to skip the parent
|
||||
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
|
||||
if (not ref_stack.back())
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->push_back(std::move(value));
|
||||
return {true, &(ref_stack.back()->m_value.array->back())};
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
assert(object_element);
|
||||
*object_element = std::move(value);
|
||||
return {true, object_element};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// the parsed JSON value
|
||||
BasicJsonType& root;
|
||||
/// stack to model hierarchy of values
|
||||
std::vector<BasicJsonType*> ref_stack;
|
||||
/// stack to manage which values to keep
|
||||
std::vector<bool> keep_stack;
|
||||
/// stack to manage which object keys to keep
|
||||
std::vector<bool> key_keep_stack;
|
||||
/// helper to hold the reference for the next object element
|
||||
BasicJsonType* object_element = nullptr;
|
||||
/// whether a syntax error occurred
|
||||
bool errored = false;
|
||||
/// callback function
|
||||
const parser_callback_t callback = nullptr;
|
||||
/// whether to throw exceptions in case of errors
|
||||
const bool allow_exceptions = true;
|
||||
/// a discarded value for the callback
|
||||
BasicJsonType discarded = BasicJsonType::value_t::discarded;
|
||||
};
|
||||
|
||||
template<typename BasicJsonType>
|
||||
class json_sax_acceptor
|
||||
{
|
||||
public:
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
|
||||
bool null()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t, const string_t&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t = std::size_t(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t = std::size_t(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&, const detail::exception&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,10 +3,8 @@
|
||||
#include <clocale> // localeconv
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
|
||||
#include <cstdio> // snprintf
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <ios> // hex, uppercase
|
||||
#include <iomanip> // setw, setfill
|
||||
#include <sstream> // stringstream
|
||||
#include <string> // char_traits, string
|
||||
#include <vector> // vector
|
||||
|
||||
@@ -94,12 +92,14 @@ class lexer
|
||||
return "end of input";
|
||||
case token_type::literal_or_value:
|
||||
return "'[', '{', or a literal";
|
||||
// LCOV_EXCL_START
|
||||
default: // catch non-enum values
|
||||
return "unknown token"; // LCOV_EXCL_LINE
|
||||
return "unknown token";
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
explicit lexer(detail::input_adapter_t adapter)
|
||||
explicit lexer(detail::input_adapter_t&& adapter)
|
||||
: ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}
|
||||
|
||||
// delete because of pointer members
|
||||
@@ -747,11 +747,13 @@ class lexer
|
||||
goto scan_number_any1;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
{
|
||||
// all other characters are rejected outside scan_number()
|
||||
assert(false); // LCOV_EXCL_LINE
|
||||
assert(false);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
scan_number_minus:
|
||||
@@ -1081,7 +1083,16 @@ scan_number_done:
|
||||
std::char_traits<char>::int_type get()
|
||||
{
|
||||
++chars_read;
|
||||
current = ia->get_character();
|
||||
if (next_unget)
|
||||
{
|
||||
// just reset the next_unget variable and work with current
|
||||
next_unget = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = ia->get_character();
|
||||
}
|
||||
|
||||
if (JSON_LIKELY(current != std::char_traits<char>::eof()))
|
||||
{
|
||||
token_string.push_back(std::char_traits<char>::to_char_type(current));
|
||||
@@ -1089,13 +1100,20 @@ scan_number_done:
|
||||
return current;
|
||||
}
|
||||
|
||||
/// unget current character (return it again on next get)
|
||||
/*!
|
||||
@brief unget current character (read it again on next get)
|
||||
|
||||
We implement unget by setting variable next_unget to true. The input is not
|
||||
changed - we just simulate ungetting by modifying chars_read and
|
||||
token_string. The next call to get() will behave as if the unget character
|
||||
is read again.
|
||||
*/
|
||||
void unget()
|
||||
{
|
||||
next_unget = true;
|
||||
--chars_read;
|
||||
if (JSON_LIKELY(current != std::char_traits<char>::eof()))
|
||||
{
|
||||
ia->unget_character();
|
||||
assert(token_string.size() != 0);
|
||||
token_string.pop_back();
|
||||
}
|
||||
@@ -1131,9 +1149,9 @@ scan_number_done:
|
||||
}
|
||||
|
||||
/// return current string value (implicitly resets the token; useful only once)
|
||||
string_t&& move_string()
|
||||
string_t& get_string()
|
||||
{
|
||||
return std::move(token_buffer);
|
||||
return token_buffer;
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
@@ -1158,10 +1176,9 @@ scan_number_done:
|
||||
if ('\x00' <= c and c <= '\x1F')
|
||||
{
|
||||
// escape control characters
|
||||
std::stringstream ss;
|
||||
ss << "<U+" << std::setw(4) << std::uppercase << std::setfill('0')
|
||||
<< std::hex << static_cast<int>(c) << ">";
|
||||
result += ss.str();
|
||||
char cs[9];
|
||||
snprintf(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c));
|
||||
result += cs;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1183,8 +1200,43 @@ scan_number_done:
|
||||
// actual scanner
|
||||
/////////////////////
|
||||
|
||||
/*!
|
||||
@brief skip the UTF-8 byte order mark
|
||||
@return true iff there is no BOM or the correct BOM has been skipped
|
||||
*/
|
||||
bool skip_bom()
|
||||
{
|
||||
if (get() == 0xEF)
|
||||
{
|
||||
if (get() == 0xBB and get() == 0xBF)
|
||||
{
|
||||
// we completely parsed the BOM
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// after reading 0xEF, an unexpected character followed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the first character is not the beginning of the BOM; unget it to
|
||||
// process is later
|
||||
unget();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
token_type scan()
|
||||
{
|
||||
// initially, skip the BOM
|
||||
if (chars_read == 0 and not skip_bom())
|
||||
{
|
||||
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
// read next character and ignore whitespace
|
||||
do
|
||||
{
|
||||
@@ -1254,6 +1306,9 @@ scan_number_done:
|
||||
/// the current character
|
||||
std::char_traits<char>::int_type current = std::char_traits<char>::eof();
|
||||
|
||||
/// whether the next get() call should just return current
|
||||
bool next_unget = false;
|
||||
|
||||
/// the number of characters read
|
||||
std::size_t chars_read = 0;
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
|
||||
#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/json_sax.hpp>
|
||||
#include <nlohmann/detail/input/lexer.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@@ -57,11 +59,14 @@ class parser
|
||||
std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
|
||||
|
||||
/// a parser reading from an input adapter
|
||||
explicit parser(detail::input_adapter_t adapter,
|
||||
explicit parser(detail::input_adapter_t&& adapter,
|
||||
const parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions_ = true)
|
||||
: callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_)
|
||||
{}
|
||||
: callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief public parser interface
|
||||
@@ -75,31 +80,54 @@ class parser
|
||||
*/
|
||||
void parse(const bool strict, BasicJsonType& result)
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
|
||||
parse_internal(true, result);
|
||||
result.assert_invariant();
|
||||
|
||||
// in strict mode, input must be completely read
|
||||
if (strict)
|
||||
if (callback)
|
||||
{
|
||||
get_token();
|
||||
expect(token_type::end_of_input);
|
||||
json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
|
||||
sax_parse_internal(&sdp);
|
||||
result.assert_invariant();
|
||||
|
||||
// in strict mode, input must be completely read
|
||||
if (strict and (get_token() != token_type::end_of_input))
|
||||
{
|
||||
sdp.parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
|
||||
}
|
||||
|
||||
// in case of an error, return discarded value
|
||||
if (sdp.is_errored())
|
||||
{
|
||||
result = value_t::discarded;
|
||||
return;
|
||||
}
|
||||
|
||||
// set top-level value to null if it was discarded by the callback
|
||||
// function
|
||||
if (result.is_discarded())
|
||||
{
|
||||
result = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// in case of an error, return discarded value
|
||||
if (errored)
|
||||
else
|
||||
{
|
||||
result = value_t::discarded;
|
||||
return;
|
||||
}
|
||||
json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
|
||||
sax_parse_internal(&sdp);
|
||||
result.assert_invariant();
|
||||
|
||||
// set top-level value to null if it was discarded by the callback
|
||||
// function
|
||||
if (result.is_discarded())
|
||||
{
|
||||
result = nullptr;
|
||||
// in strict mode, input must be completely read
|
||||
if (strict and (get_token() != token_type::end_of_input))
|
||||
{
|
||||
sdp.parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
|
||||
}
|
||||
|
||||
// in case of an error, return discarded value
|
||||
if (sdp.is_errored())
|
||||
{
|
||||
result = value_t::discarded;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,414 +139,311 @@ class parser
|
||||
*/
|
||||
bool accept(const bool strict = true)
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
json_sax_acceptor<BasicJsonType> sax_acceptor;
|
||||
return sax_parse(&sax_acceptor, strict);
|
||||
}
|
||||
|
||||
if (not accept_internal())
|
||||
template <typename SAX>
|
||||
bool sax_parse(SAX* sax, const bool strict = true)
|
||||
{
|
||||
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
|
||||
const bool result = sax_parse_internal(sax);
|
||||
|
||||
// strict mode: next byte must be EOF
|
||||
if (result and strict and (get_token() != token_type::end_of_input))
|
||||
{
|
||||
return false;
|
||||
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_of_input)));
|
||||
}
|
||||
|
||||
// strict => last token must be EOF
|
||||
return not strict or (get_token() == token_type::end_of_input);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
@brief the actual parser
|
||||
@throw parse_error.101 in case of an unexpected token
|
||||
@throw parse_error.102 if to_unicode fails or surrogate error
|
||||
@throw parse_error.103 if to_unicode fails
|
||||
*/
|
||||
void parse_internal(bool keep, BasicJsonType& result)
|
||||
template <typename SAX>
|
||||
bool sax_parse_internal(SAX* sax)
|
||||
{
|
||||
// never parse after a parse error was detected
|
||||
assert(not errored);
|
||||
// stack to remember the hieararchy of structured values we are parsing
|
||||
// true = array; false = object
|
||||
std::vector<bool> states;
|
||||
// value to avoid a goto (see comment where set to true)
|
||||
bool skip_to_state_evaluation = false;
|
||||
|
||||
// start with a discarded value
|
||||
if (not result.is_discarded())
|
||||
while (true)
|
||||
{
|
||||
result.m_value.destroy(result.m_type);
|
||||
result.m_type = value_t::discarded;
|
||||
}
|
||||
|
||||
switch (last_token)
|
||||
{
|
||||
case token_type::begin_object:
|
||||
if (not skip_to_state_evaluation)
|
||||
{
|
||||
if (keep)
|
||||
// invariant: get_token() was called before each iteration
|
||||
switch (last_token)
|
||||
{
|
||||
if (callback)
|
||||
case token_type::begin_object:
|
||||
{
|
||||
keep = callback(depth++, parse_event_t::object_start, result);
|
||||
}
|
||||
|
||||
if (not callback or keep)
|
||||
{
|
||||
// explicitly set result to object to cope with {}
|
||||
result.m_type = value_t::object;
|
||||
result.m_value = value_t::object;
|
||||
}
|
||||
}
|
||||
|
||||
// read next token
|
||||
get_token();
|
||||
|
||||
// closing } -> we are done
|
||||
if (last_token == token_type::end_object)
|
||||
{
|
||||
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
|
||||
{
|
||||
result.m_value.destroy(result.m_type);
|
||||
result.m_type = value_t::discarded;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// parse values
|
||||
string_t key;
|
||||
BasicJsonType value;
|
||||
while (true)
|
||||
{
|
||||
// store key
|
||||
if (not expect(token_type::value_string))
|
||||
{
|
||||
return;
|
||||
}
|
||||
key = m_lexer.move_string();
|
||||
|
||||
bool keep_tag = false;
|
||||
if (keep)
|
||||
{
|
||||
if (callback)
|
||||
if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
|
||||
{
|
||||
BasicJsonType k(key);
|
||||
keep_tag = callback(depth, parse_event_t::key, k);
|
||||
return false;
|
||||
}
|
||||
|
||||
// closing } -> we are done
|
||||
if (get_token() == token_type::end_object)
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->end_object()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// parse key
|
||||
if (JSON_UNLIKELY(last_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)));
|
||||
}
|
||||
else
|
||||
{
|
||||
keep_tag = true;
|
||||
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)));
|
||||
}
|
||||
|
||||
// remember we are now inside an object
|
||||
states.push_back(false);
|
||||
|
||||
// parse values
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
case token_type::begin_array:
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// closing ] -> we are done
|
||||
if (get_token() == token_type::end_array)
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->end_array()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// remember we are now inside an array
|
||||
states.push_back(true);
|
||||
|
||||
// parse values (no need to call get_token)
|
||||
continue;
|
||||
}
|
||||
|
||||
case token_type::value_float:
|
||||
{
|
||||
const auto res = m_lexer.get_number_float();
|
||||
|
||||
if (JSON_UNLIKELY(not std::isfinite(res)))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// parse separator (:)
|
||||
get_token();
|
||||
if (not expect(token_type::name_separator))
|
||||
case token_type::literal_false:
|
||||
{
|
||||
return;
|
||||
if (JSON_UNLIKELY(not sax->boolean(false)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// parse and add value
|
||||
get_token();
|
||||
value.m_value.destroy(value.m_type);
|
||||
value.m_type = value_t::discarded;
|
||||
parse_internal(keep, value);
|
||||
|
||||
if (JSON_UNLIKELY(errored))
|
||||
case token_type::literal_null:
|
||||
{
|
||||
return;
|
||||
if (JSON_UNLIKELY(not sax->null()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (keep and keep_tag and not value.is_discarded())
|
||||
case token_type::literal_true:
|
||||
{
|
||||
result.m_value.object->emplace(std::move(key), std::move(value));
|
||||
if (JSON_UNLIKELY(not sax->boolean(true)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// comma -> next value
|
||||
get_token();
|
||||
if (last_token == token_type::value_separator)
|
||||
case token_type::value_integer:
|
||||
{
|
||||
get_token();
|
||||
continue;
|
||||
if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// closing }
|
||||
if (not expect(token_type::end_object))
|
||||
case token_type::value_string:
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
|
||||
{
|
||||
result.m_value.destroy(result.m_type);
|
||||
result.m_type = value_t::discarded;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::begin_array:
|
||||
{
|
||||
if (keep)
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
keep = callback(depth++, parse_event_t::array_start, result);
|
||||
if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (not callback or keep)
|
||||
case token_type::value_unsigned:
|
||||
{
|
||||
// explicitly set result to array to cope with []
|
||||
result.m_type = value_t::array;
|
||||
result.m_value = value_t::array;
|
||||
if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::parse_error:
|
||||
{
|
||||
// using "uninitialized" to avoid "expected" message
|
||||
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::uninitialized)));
|
||||
}
|
||||
|
||||
default: // the last token was unexpected
|
||||
{
|
||||
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::literal_or_value)));
|
||||
}
|
||||
}
|
||||
|
||||
// read next token
|
||||
get_token();
|
||||
|
||||
// closing ] -> we are done
|
||||
if (last_token == token_type::end_array)
|
||||
{
|
||||
if (callback and not callback(--depth, parse_event_t::array_end, result))
|
||||
{
|
||||
result.m_value.destroy(result.m_type);
|
||||
result.m_type = value_t::discarded;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// parse values
|
||||
BasicJsonType value;
|
||||
while (true)
|
||||
{
|
||||
// parse value
|
||||
value.m_value.destroy(value.m_type);
|
||||
value.m_type = value_t::discarded;
|
||||
parse_internal(keep, value);
|
||||
|
||||
if (JSON_UNLIKELY(errored))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (keep and not value.is_discarded())
|
||||
{
|
||||
result.m_value.array->push_back(std::move(value));
|
||||
}
|
||||
|
||||
// comma -> next value
|
||||
get_token();
|
||||
if (last_token == token_type::value_separator)
|
||||
{
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
// closing ]
|
||||
if (not expect(token_type::end_array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
|
||||
{
|
||||
result.m_value.destroy(result.m_type);
|
||||
result.m_type = value_t::discarded;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::literal_null:
|
||||
else
|
||||
{
|
||||
result.m_type = value_t::null;
|
||||
break;
|
||||
skip_to_state_evaluation = false;
|
||||
}
|
||||
|
||||
case token_type::value_string:
|
||||
// we reached this line after we successfully parsed a value
|
||||
if (states.empty())
|
||||
{
|
||||
result.m_type = value_t::string;
|
||||
result.m_value = m_lexer.move_string();
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::literal_true:
|
||||
{
|
||||
result.m_type = value_t::boolean;
|
||||
result.m_value = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::literal_false:
|
||||
{
|
||||
result.m_type = value_t::boolean;
|
||||
result.m_value = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::value_unsigned:
|
||||
{
|
||||
result.m_type = value_t::number_unsigned;
|
||||
result.m_value = m_lexer.get_number_unsigned();
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::value_integer:
|
||||
{
|
||||
result.m_type = value_t::number_integer;
|
||||
result.m_value = m_lexer.get_number_integer();
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::value_float:
|
||||
{
|
||||
result.m_type = value_t::number_float;
|
||||
result.m_value = m_lexer.get_number_float();
|
||||
|
||||
// throw in case of infinity or NAN
|
||||
if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float)))
|
||||
{
|
||||
if (allow_exceptions)
|
||||
{
|
||||
JSON_THROW(out_of_range::create(406, "number overflow parsing '" +
|
||||
m_lexer.get_token_string() + "'"));
|
||||
}
|
||||
expect(token_type::uninitialized);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case token_type::parse_error:
|
||||
{
|
||||
// using "uninitialized" to avoid "expected" message
|
||||
if (not expect(token_type::uninitialized))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// the last token was unexpected; we expected a value
|
||||
if (not expect(token_type::literal_or_value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break; // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
if (keep and callback and not callback(depth, parse_event_t::value, result))
|
||||
{
|
||||
result.m_value.destroy(result.m_type);
|
||||
result.m_type = value_t::discarded;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief the actual acceptor
|
||||
|
||||
@invariant 1. The last token is not yet processed. Therefore, the caller
|
||||
of this function must make sure a token has been read.
|
||||
2. When this function returns, the last token is processed.
|
||||
That is, the last read character was already considered.
|
||||
|
||||
This invariant makes sure that no token needs to be "unput".
|
||||
*/
|
||||
bool accept_internal()
|
||||
{
|
||||
switch (last_token)
|
||||
{
|
||||
case token_type::begin_object:
|
||||
{
|
||||
// read next token
|
||||
get_token();
|
||||
|
||||
// closing } -> we are done
|
||||
if (last_token == token_type::end_object)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// parse values
|
||||
while (true)
|
||||
{
|
||||
// parse key
|
||||
if (last_token != token_type::value_string)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse separator (:)
|
||||
get_token();
|
||||
if (last_token != token_type::name_separator)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse value
|
||||
get_token();
|
||||
if (not accept_internal())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// comma -> next value
|
||||
get_token();
|
||||
if (last_token == token_type::value_separator)
|
||||
{
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
// closing }
|
||||
return (last_token == token_type::end_object);
|
||||
}
|
||||
}
|
||||
|
||||
case token_type::begin_array:
|
||||
{
|
||||
// read next token
|
||||
get_token();
|
||||
|
||||
// closing ] -> we are done
|
||||
if (last_token == token_type::end_array)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// parse values
|
||||
while (true)
|
||||
{
|
||||
// parse value
|
||||
if (not accept_internal())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// comma -> next value
|
||||
get_token();
|
||||
if (last_token == token_type::value_separator)
|
||||
{
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
// closing ]
|
||||
return (last_token == token_type::end_array);
|
||||
}
|
||||
}
|
||||
|
||||
case token_type::value_float:
|
||||
{
|
||||
// reject infinity or NAN
|
||||
return std::isfinite(m_lexer.get_number_float());
|
||||
}
|
||||
|
||||
case token_type::literal_false:
|
||||
case token_type::literal_null:
|
||||
case token_type::literal_true:
|
||||
case token_type::value_integer:
|
||||
case token_type::value_string:
|
||||
case token_type::value_unsigned:
|
||||
// empty stack: we reached the end of the hieararchy: done
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (states.back()) // array
|
||||
{
|
||||
// comma -> next value
|
||||
if (get_token() == token_type::value_separator)
|
||||
{
|
||||
// parse a new value
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
default: // the last token was unexpected
|
||||
return false;
|
||||
// closing ]
|
||||
if (JSON_LIKELY(last_token == token_type::end_array))
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->end_array()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We are done with this array. 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(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
|
||||
}
|
||||
}
|
||||
else // object
|
||||
{
|
||||
// comma -> next value
|
||||
if (get_token() == token_type::value_separator)
|
||||
{
|
||||
// parse key
|
||||
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)));
|
||||
}
|
||||
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)));
|
||||
}
|
||||
|
||||
// parse values
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
// closing }
|
||||
if (JSON_LIKELY(last_token == token_type::end_object))
|
||||
{
|
||||
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(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,29 +453,7 @@ class parser
|
||||
return (last_token = m_lexer.scan());
|
||||
}
|
||||
|
||||
/*!
|
||||
@throw parse_error.101 if expected token did not occur
|
||||
*/
|
||||
bool expect(token_type t)
|
||||
{
|
||||
if (JSON_UNLIKELY(t != last_token))
|
||||
{
|
||||
errored = true;
|
||||
expected = t;
|
||||
if (allow_exceptions)
|
||||
{
|
||||
throw_exception();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[noreturn]] void throw_exception() const
|
||||
std::string exception_message(const token_type expected)
|
||||
{
|
||||
std::string error_msg = "syntax error - ";
|
||||
if (last_token == token_type::parse_error)
|
||||
@@ -568,22 +471,16 @@ class parser
|
||||
error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
|
||||
}
|
||||
|
||||
JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
/// current level of recursion
|
||||
int depth = 0;
|
||||
/// callback function
|
||||
const parser_callback_t callback = nullptr;
|
||||
/// the type of the last read token
|
||||
token_type last_token = token_type::uninitialized;
|
||||
/// the lexer
|
||||
lexer_t m_lexer;
|
||||
/// whether a syntax error occurred
|
||||
bool errored = false;
|
||||
/// possible reason for the syntax error
|
||||
token_type expected = token_type::uninitialized;
|
||||
/// whether to throw exceptions in case of errors
|
||||
const bool allow_exceptions = true;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <nlohmann/detail/iterators/internal_iterator.hpp>
|
||||
#include <nlohmann/detail/iterators/primitive_iterator.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
@@ -31,7 +31,7 @@ This class implements a both iterators (iterator and const_iterator) for the
|
||||
|
||||
@requirement The class satisfies the following concept requirements:
|
||||
-
|
||||
[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator):
|
||||
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
|
||||
The iterator that can be moved can be moved in both directions (i.e.
|
||||
incremented and decremented).
|
||||
|
||||
@@ -583,7 +583,7 @@ class iter_impl
|
||||
@brief return the key of an object iterator
|
||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||
*/
|
||||
typename object_t::key_type key() const
|
||||
const typename object_t::key_type& key() const
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <string> // string, to_string
|
||||
#include <iterator> // input_iterator_tag
|
||||
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@@ -16,15 +17,31 @@ template<typename IteratorType> class iteration_proxy
|
||||
/// helper class for iteration
|
||||
class iteration_proxy_internal
|
||||
{
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = iteration_proxy_internal;
|
||||
using pointer = iteration_proxy_internal*;
|
||||
using reference = iteration_proxy_internal&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
private:
|
||||
/// the iterator
|
||||
IteratorType anchor;
|
||||
/// an index for arrays (used to create key names)
|
||||
std::size_t array_index = 0;
|
||||
/// last stringified array index
|
||||
mutable std::size_t array_index_last = 0;
|
||||
/// a string representation of the array index
|
||||
mutable std::string array_index_str = "0";
|
||||
/// an empty string (to return a reference for primitive values)
|
||||
const std::string empty_str = "";
|
||||
|
||||
public:
|
||||
explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
|
||||
|
||||
iteration_proxy_internal(const iteration_proxy_internal&) = default;
|
||||
iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default;
|
||||
|
||||
/// dereference operator (needed for range-based for)
|
||||
iteration_proxy_internal& operator*()
|
||||
{
|
||||
@@ -40,6 +57,12 @@ template<typename IteratorType> class iteration_proxy
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// equality operator (needed for InputIterator)
|
||||
bool operator==(const iteration_proxy_internal& o) const noexcept
|
||||
{
|
||||
return anchor == o.anchor;
|
||||
}
|
||||
|
||||
/// inequality operator (needed for range-based for)
|
||||
bool operator!=(const iteration_proxy_internal& o) const noexcept
|
||||
{
|
||||
@@ -47,7 +70,7 @@ template<typename IteratorType> class iteration_proxy
|
||||
}
|
||||
|
||||
/// return key of the iterator
|
||||
std::string key() const
|
||||
const std::string& key() const
|
||||
{
|
||||
assert(anchor.m_object != nullptr);
|
||||
|
||||
@@ -55,7 +78,14 @@ template<typename IteratorType> class iteration_proxy
|
||||
{
|
||||
// use integer array index as key
|
||||
case value_t::array:
|
||||
return std::to_string(array_index);
|
||||
{
|
||||
if (array_index != array_index_last)
|
||||
{
|
||||
array_index_str = std::to_string(array_index);
|
||||
array_index_last = array_index;
|
||||
}
|
||||
return array_index_str;
|
||||
}
|
||||
|
||||
// use key from the object
|
||||
case value_t::object:
|
||||
@@ -63,7 +93,7 @@ template<typename IteratorType> class iteration_proxy
|
||||
|
||||
// use an empty key for all primitive types
|
||||
default:
|
||||
return "";
|
||||
return empty_str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ create @ref const_reverse_iterator).
|
||||
|
||||
@requirement The class satisfies the following concept requirements:
|
||||
-
|
||||
[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator):
|
||||
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
|
||||
The iterator that can be moved can be moved in both directions (i.e.
|
||||
incremented and decremented).
|
||||
- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
|
||||
- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
|
||||
It is possible to write to the pointed-to element (only if @a Base is
|
||||
@ref iterator).
|
||||
|
||||
@@ -41,11 +41,11 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
|
||||
using reference = typename Base::reference;
|
||||
|
||||
/// create reverse iterator from iterator
|
||||
json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
|
||||
explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
|
||||
: base_iterator(it) {}
|
||||
|
||||
/// create reverse iterator from base class
|
||||
json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
|
||||
explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
|
||||
|
||||
/// post-increment (it++)
|
||||
json_reverse_iterator const operator++(int)
|
||||
|
||||
@@ -87,7 +87,7 @@ class primitive_iterator_t
|
||||
primitive_iterator_t const operator++(int) noexcept
|
||||
{
|
||||
auto result = *this;
|
||||
m_it++;
|
||||
++m_it;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ class primitive_iterator_t
|
||||
primitive_iterator_t const operator--(int) noexcept
|
||||
{
|
||||
auto result = *this;
|
||||
m_it--;
|
||||
--m_it;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
|
||||
|
||||
// exclude unsupported compilers
|
||||
#if defined(__clang__)
|
||||
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
|
||||
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
||||
#endif
|
||||
#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
|
||||
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
|
||||
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
||||
#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
|
||||
#if defined(__clang__)
|
||||
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
|
||||
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
||||
#endif
|
||||
#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
|
||||
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
|
||||
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -40,10 +42,12 @@
|
||||
#define JSON_THROW(exception) throw exception
|
||||
#define JSON_TRY try
|
||||
#define JSON_CATCH(exception) catch(exception)
|
||||
#define JSON_INTERNAL_CATCH(exception) catch(exception)
|
||||
#else
|
||||
#define JSON_THROW(exception) std::abort()
|
||||
#define JSON_TRY if(true)
|
||||
#define JSON_CATCH(exception) if(false)
|
||||
#define JSON_INTERNAL_CATCH(exception) if(false)
|
||||
#endif
|
||||
|
||||
// override exception macros
|
||||
@@ -58,6 +62,12 @@
|
||||
#if defined(JSON_CATCH_USER)
|
||||
#undef JSON_CATCH
|
||||
#define JSON_CATCH JSON_CATCH_USER
|
||||
#undef JSON_INTERNAL_CATCH
|
||||
#define JSON_INTERNAL_CATCH JSON_CATCH_USER
|
||||
#endif
|
||||
#if defined(JSON_INTERNAL_CATCH_USER)
|
||||
#undef JSON_INTERNAL_CATCH
|
||||
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
|
||||
#endif
|
||||
|
||||
// manual branch prediction
|
||||
@@ -92,24 +102,3 @@
|
||||
basic_json<ObjectType, ArrayType, StringType, BooleanType, \
|
||||
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
|
||||
AllocatorType, JSONSerializer>
|
||||
|
||||
/*!
|
||||
@brief Helper to determine whether there's a key_type for T.
|
||||
|
||||
This helper is used to tell associative containers apart from other containers
|
||||
such as sequence containers. For instance, `std::map` passes the test as it
|
||||
contains a `mapped_type`, whereas `std::vector` fails the test.
|
||||
|
||||
@sa http://stackoverflow.com/a/7728728/266378
|
||||
@since version 1.0.0, overworked in version 2.0.6
|
||||
*/
|
||||
#define NLOHMANN_JSON_HAS_HELPER(type) \
|
||||
template<typename T> struct has_##type { \
|
||||
private: \
|
||||
template<typename U, typename = typename U::type> \
|
||||
static int detect(U &&); \
|
||||
static void detect(...); \
|
||||
public: \
|
||||
static constexpr bool value = \
|
||||
std::is_integral<decltype(detect(std::declval<T>()))>::value; \
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endif
|
||||
|
||||
// clean up
|
||||
#undef JSON_INTERNAL_CATCH
|
||||
#undef JSON_CATCH
|
||||
#undef JSON_THROW
|
||||
#undef JSON_TRY
|
||||
@@ -19,4 +20,3 @@
|
||||
#undef JSON_HAS_CPP_17
|
||||
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
#undef NLOHMANN_BASIC_JSON_TPL
|
||||
#undef NLOHMANN_JSON_HAS_HELPER
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <ciso646> // not
|
||||
#include <cstddef> // size_t
|
||||
#include <limits> // numeric_limits
|
||||
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
|
||||
#include <utility> // declval
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
/*!
|
||||
@brief detail namespace with internal helper functions
|
||||
|
||||
This namespace collects functions that should not be exposed,
|
||||
implementations of some @ref basic_json methods, and meta-programming helpers.
|
||||
|
||||
@since version 2.1.0
|
||||
*/
|
||||
namespace detail
|
||||
{
|
||||
/////////////
|
||||
// helpers //
|
||||
/////////////
|
||||
|
||||
template<typename> struct is_basic_json : std::false_type {};
|
||||
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
|
||||
|
||||
// alias templates to reduce boilerplate
|
||||
template<bool B, typename T = void>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
template<typename T>
|
||||
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
// implementation of C++14 index_sequence and affiliates
|
||||
// source: https://stackoverflow.com/a/32223343
|
||||
template<std::size_t... Ints>
|
||||
struct index_sequence
|
||||
{
|
||||
using type = index_sequence;
|
||||
using value_type = std::size_t;
|
||||
static constexpr std::size_t size() noexcept
|
||||
{
|
||||
return sizeof...(Ints);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Sequence1, class Sequence2>
|
||||
struct merge_and_renumber;
|
||||
|
||||
template<std::size_t... I1, std::size_t... I2>
|
||||
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
|
||||
: index_sequence < I1..., (sizeof...(I1) + I2)... > {};
|
||||
|
||||
template<std::size_t N>
|
||||
struct make_index_sequence
|
||||
: merge_and_renumber < typename make_index_sequence < N / 2 >::type,
|
||||
typename make_index_sequence < N - N / 2 >::type > {};
|
||||
|
||||
template<> struct make_index_sequence<0> : index_sequence<> {};
|
||||
template<> struct make_index_sequence<1> : index_sequence<0> {};
|
||||
|
||||
template<typename... Ts>
|
||||
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
||||
|
||||
/*
|
||||
Implementation of two C++17 constructs: conjunction, negation. This is needed
|
||||
to avoid evaluating all the traits in a condition
|
||||
|
||||
For example: not std::is_same<void, T>::value and has_value_type<T>::value
|
||||
will not compile when T = void (on MSVC at least). Whereas
|
||||
conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will
|
||||
stop evaluating if negation<...>::value == false
|
||||
|
||||
Please note that those constructs must be used with caution, since symbols can
|
||||
become very long quickly (which can slow down compilation and cause MSVC
|
||||
internal compiler errors). Only use it when you have to (see example ahead).
|
||||
*/
|
||||
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<class B> struct negation : std::integral_constant<bool, not B::value> {};
|
||||
|
||||
// dispatch utility (taken from ranges-v3)
|
||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||
template<> struct priority_tag<0> {};
|
||||
|
||||
////////////////////////
|
||||
// has_/is_ functions //
|
||||
////////////////////////
|
||||
|
||||
// source: https://stackoverflow.com/a/37193089/4116453
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_complete_type : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
|
||||
|
||||
NLOHMANN_JSON_HAS_HELPER(mapped_type);
|
||||
NLOHMANN_JSON_HAS_HELPER(key_type);
|
||||
NLOHMANN_JSON_HAS_HELPER(value_type);
|
||||
NLOHMANN_JSON_HAS_HELPER(iterator);
|
||||
|
||||
template<bool B, class RealType, class CompatibleObjectType>
|
||||
struct is_compatible_object_type_impl : std::false_type {};
|
||||
|
||||
template<class RealType, class CompatibleObjectType>
|
||||
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
|
||||
{
|
||||
static constexpr auto value =
|
||||
std::is_constructible<typename RealType::key_type, typename CompatibleObjectType::key_type>::value and
|
||||
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
|
||||
};
|
||||
|
||||
template<class BasicJsonType, class CompatibleObjectType>
|
||||
struct is_compatible_object_type
|
||||
{
|
||||
static auto constexpr value = is_compatible_object_type_impl <
|
||||
conjunction<negation<std::is_same<void, CompatibleObjectType>>,
|
||||
has_mapped_type<CompatibleObjectType>,
|
||||
has_key_type<CompatibleObjectType>>::value,
|
||||
typename BasicJsonType::object_t, CompatibleObjectType >::value;
|
||||
};
|
||||
|
||||
template<typename BasicJsonType, typename T>
|
||||
struct is_basic_json_nested_type
|
||||
{
|
||||
static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
|
||||
std::is_same<T, typename BasicJsonType::const_iterator>::value or
|
||||
std::is_same<T, typename BasicJsonType::reverse_iterator>::value or
|
||||
std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value;
|
||||
};
|
||||
|
||||
template<class BasicJsonType, class CompatibleArrayType>
|
||||
struct is_compatible_array_type
|
||||
{
|
||||
static auto constexpr value =
|
||||
conjunction<negation<std::is_same<void, CompatibleArrayType>>,
|
||||
negation<is_compatible_object_type<
|
||||
BasicJsonType, CompatibleArrayType>>,
|
||||
negation<std::is_constructible<typename BasicJsonType::string_t,
|
||||
CompatibleArrayType>>,
|
||||
negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>,
|
||||
has_value_type<CompatibleArrayType>,
|
||||
has_iterator<CompatibleArrayType>>::value;
|
||||
};
|
||||
|
||||
template<bool, typename, typename>
|
||||
struct is_compatible_integer_type_impl : std::false_type {};
|
||||
|
||||
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||
struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
|
||||
{
|
||||
// is there an assert somewhere on overflows?
|
||||
using RealLimits = std::numeric_limits<RealIntegerType>;
|
||||
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
|
||||
|
||||
static constexpr auto value =
|
||||
std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and
|
||||
CompatibleLimits::is_integer and
|
||||
RealLimits::is_signed == CompatibleLimits::is_signed;
|
||||
};
|
||||
|
||||
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||
struct is_compatible_integer_type
|
||||
{
|
||||
static constexpr auto value =
|
||||
is_compatible_integer_type_impl <
|
||||
std::is_integral<CompatibleNumberIntegerType>::value and
|
||||
not std::is_same<bool, CompatibleNumberIntegerType>::value,
|
||||
RealIntegerType, CompatibleNumberIntegerType > ::value;
|
||||
};
|
||||
|
||||
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
|
||||
template<typename BasicJsonType, typename T>
|
||||
struct has_from_json
|
||||
{
|
||||
private:
|
||||
// also check the return type of from_json
|
||||
template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
|
||||
std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
|
||||
static int detect(U&&);
|
||||
static void detect(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = std::is_integral<decltype(
|
||||
detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
|
||||
};
|
||||
|
||||
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
|
||||
// this overload is used for non-default-constructible user-defined-types
|
||||
template<typename BasicJsonType, typename T>
|
||||
struct has_non_default_from_json
|
||||
{
|
||||
private:
|
||||
template <
|
||||
typename U,
|
||||
typename = enable_if_t<std::is_same<
|
||||
T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >>
|
||||
static int detect(U&&);
|
||||
static void detect(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = std::is_integral<decltype(detect(
|
||||
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
|
||||
};
|
||||
|
||||
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
|
||||
template<typename BasicJsonType, typename T>
|
||||
struct has_to_json
|
||||
{
|
||||
private:
|
||||
template<typename U, typename = decltype(uncvref_t<U>::to_json(
|
||||
std::declval<BasicJsonType&>(), std::declval<T>()))>
|
||||
static int detect(U&&);
|
||||
static void detect(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = std::is_integral<decltype(detect(
|
||||
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleCompleteType>
|
||||
struct is_compatible_complete_type
|
||||
{
|
||||
static constexpr bool value =
|
||||
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
|
||||
not is_basic_json<CompatibleCompleteType>::value and
|
||||
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
|
||||
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleType>
|
||||
struct is_compatible_type
|
||||
: conjunction<is_complete_type<CompatibleType>,
|
||||
is_compatible_complete_type<BasicJsonType, CompatibleType>>
|
||||
{
|
||||
};
|
||||
|
||||
// taken from ranges-v3
|
||||
template<typename T>
|
||||
struct static_const
|
||||
{
|
||||
static constexpr T value{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr T static_const<T>::value;
|
||||
}
|
||||
}
|
||||
63
include/nlohmann/detail/meta/cpp_future.hpp
Normal file
63
include/nlohmann/detail/meta/cpp_future.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <ciso646> // not
|
||||
#include <cstddef> // size_t
|
||||
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// alias templates to reduce boilerplate
|
||||
template<bool B, typename T = void>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
template<typename T>
|
||||
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
// implementation of C++14 index_sequence and affiliates
|
||||
// source: https://stackoverflow.com/a/32223343
|
||||
template<std::size_t... Ints>
|
||||
struct index_sequence
|
||||
{
|
||||
using type = index_sequence;
|
||||
using value_type = std::size_t;
|
||||
static constexpr std::size_t size() noexcept
|
||||
{
|
||||
return sizeof...(Ints);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Sequence1, class Sequence2>
|
||||
struct merge_and_renumber;
|
||||
|
||||
template<std::size_t... I1, std::size_t... I2>
|
||||
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
|
||||
: index_sequence < I1..., (sizeof...(I1) + I2)... > {};
|
||||
|
||||
template<std::size_t N>
|
||||
struct make_index_sequence
|
||||
: merge_and_renumber < typename make_index_sequence < N / 2 >::type,
|
||||
typename make_index_sequence < N - N / 2 >::type > {};
|
||||
|
||||
template<> struct make_index_sequence<0> : index_sequence<> {};
|
||||
template<> struct make_index_sequence<1> : index_sequence<0> {};
|
||||
|
||||
template<typename... Ts>
|
||||
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
||||
|
||||
// dispatch utility (taken from ranges-v3)
|
||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||
template<> struct priority_tag<0> {};
|
||||
|
||||
// taken from ranges-v3
|
||||
template<typename T>
|
||||
struct static_const
|
||||
{
|
||||
static constexpr T value{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr T static_const<T>::value;
|
||||
}
|
||||
}
|
||||
56
include/nlohmann/detail/meta/detected.hpp
Normal file
56
include/nlohmann/detail/meta/detected.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <nlohmann/detail/meta/void_t.hpp>
|
||||
|
||||
// http://en.cppreference.com/w/cpp/experimental/is_detected
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct nonesuch
|
||||
{
|
||||
nonesuch() = delete;
|
||||
~nonesuch() = delete;
|
||||
nonesuch(nonesuch const&) = delete;
|
||||
void operator=(nonesuch const&) = delete;
|
||||
};
|
||||
|
||||
template <class Default,
|
||||
class AlwaysVoid,
|
||||
template <class...> class Op,
|
||||
class... Args>
|
||||
struct detector
|
||||
{
|
||||
using value_t = std::false_type;
|
||||
using type = Default;
|
||||
};
|
||||
|
||||
template <class Default, template <class...> class Op, class... Args>
|
||||
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
|
||||
{
|
||||
using value_t = std::true_type;
|
||||
using type = Op<Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
|
||||
|
||||
template <class Default, template <class...> class Op, class... Args>
|
||||
using detected_or = detector<Default, void, Op, Args...>;
|
||||
|
||||
template <class Default, template <class...> class Op, class... Args>
|
||||
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
|
||||
|
||||
template <class Expected, template <class...> class Op, class... Args>
|
||||
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
||||
|
||||
template <class To, template <class...> class Op, class... Args>
|
||||
using is_detected_convertible =
|
||||
std::is_convertible<detected_t<Op, Args...>, To>;
|
||||
}
|
||||
}
|
||||
141
include/nlohmann/detail/meta/is_sax.hpp
Normal file
141
include/nlohmann/detail/meta/is_sax.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // size_t
|
||||
#include <utility> // declval
|
||||
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
using null_function_t = decltype(std::declval<T&>().null());
|
||||
|
||||
template <typename T>
|
||||
using boolean_function_t =
|
||||
decltype(std::declval<T&>().boolean(std::declval<bool>()));
|
||||
|
||||
template <typename T, typename Integer>
|
||||
using number_integer_function_t =
|
||||
decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
|
||||
|
||||
template <typename T, typename Unsigned>
|
||||
using number_unsigned_function_t =
|
||||
decltype(std::declval<T &>().number_unsigned(std::declval<Unsigned>()));
|
||||
|
||||
template <typename T, typename Float, typename String>
|
||||
using number_float_function_t = decltype(std::declval<T &>().number_float(
|
||||
std::declval<Float>(), std::declval<const String &>()));
|
||||
|
||||
template <typename T, typename String>
|
||||
using string_function_t =
|
||||
decltype(std::declval<T &>().string(std::declval<String &>()));
|
||||
|
||||
template <typename T>
|
||||
using start_object_function_t =
|
||||
decltype(std::declval<T &>().start_object(std::declval<std::size_t>()));
|
||||
|
||||
template <typename T, typename String>
|
||||
using key_function_t =
|
||||
decltype(std::declval<T &>().key(std::declval<String &>()));
|
||||
|
||||
template <typename T>
|
||||
using end_object_function_t = decltype(std::declval<T &>().end_object());
|
||||
|
||||
template <typename T>
|
||||
using start_array_function_t =
|
||||
decltype(std::declval<T &>().start_array(std::declval<std::size_t>()));
|
||||
|
||||
template <typename T>
|
||||
using end_array_function_t = decltype(std::declval<T &>().end_array());
|
||||
|
||||
template <typename T, typename Exception>
|
||||
using parse_error_function_t = decltype(std::declval<T &>().parse_error(
|
||||
std::declval<std::size_t>(), std::declval<const std::string &>(),
|
||||
std::declval<const Exception &>()));
|
||||
|
||||
template <typename SAX, typename BasicJsonType>
|
||||
struct is_sax
|
||||
{
|
||||
private:
|
||||
static_assert(is_basic_json<BasicJsonType>::value,
|
||||
"BasicJsonType must be of type basic_json<...>");
|
||||
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using exception_t = typename BasicJsonType::exception;
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
is_detected_exact<bool, null_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, boolean_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, number_integer_function_t, SAX,
|
||||
number_integer_t>::value &&
|
||||
is_detected_exact<bool, number_unsigned_function_t, SAX,
|
||||
number_unsigned_t>::value &&
|
||||
is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
|
||||
string_t>::value &&
|
||||
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
|
||||
is_detected_exact<bool, start_object_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
|
||||
is_detected_exact<bool, end_object_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, start_array_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, end_array_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
|
||||
};
|
||||
|
||||
template <typename SAX, typename BasicJsonType>
|
||||
struct is_sax_static_asserts
|
||||
{
|
||||
private:
|
||||
static_assert(is_basic_json<BasicJsonType>::value,
|
||||
"BasicJsonType must be of type basic_json<...>");
|
||||
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using exception_t = typename BasicJsonType::exception;
|
||||
|
||||
public:
|
||||
static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool null()");
|
||||
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool boolean(bool)");
|
||||
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool boolean(bool)");
|
||||
static_assert(
|
||||
is_detected_exact<bool, number_integer_function_t, SAX,
|
||||
number_integer_t>::value,
|
||||
"Missing/invalid function: bool number_integer(number_integer_t)");
|
||||
static_assert(
|
||||
is_detected_exact<bool, number_unsigned_function_t, SAX,
|
||||
number_unsigned_t>::value,
|
||||
"Missing/invalid function: bool number_unsigned(number_unsigned_t)");
|
||||
static_assert(is_detected_exact<bool, number_float_function_t, SAX,
|
||||
number_float_t, string_t>::value,
|
||||
"Missing/invalid function: bool number_float(number_float_t, const string_t&)");
|
||||
static_assert(
|
||||
is_detected_exact<bool, string_function_t, SAX, string_t>::value,
|
||||
"Missing/invalid function: bool string(string_t&)");
|
||||
static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool start_object(std::size_t)");
|
||||
static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
|
||||
"Missing/invalid function: bool key(string_t&)");
|
||||
static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool end_object()");
|
||||
static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool start_array(std::size_t)");
|
||||
static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool end_array()");
|
||||
static_assert(
|
||||
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
|
||||
"Missing/invalid function: bool parse_error(std::size_t, const "
|
||||
"std::string&, const exception&)");
|
||||
};
|
||||
}
|
||||
}
|
||||
251
include/nlohmann/detail/meta/type_traits.hpp
Normal file
251
include/nlohmann/detail/meta/type_traits.hpp
Normal file
@@ -0,0 +1,251 @@
|
||||
#pragma once
|
||||
|
||||
#include <ciso646> // not
|
||||
#include <limits> // numeric_limits
|
||||
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
||||
#include <utility> // declval
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
/*!
|
||||
@brief detail namespace with internal helper functions
|
||||
|
||||
This namespace collects functions that should not be exposed,
|
||||
implementations of some @ref basic_json methods, and meta-programming helpers.
|
||||
|
||||
@since version 2.1.0
|
||||
*/
|
||||
namespace detail
|
||||
{
|
||||
/////////////
|
||||
// helpers //
|
||||
/////////////
|
||||
|
||||
template<typename> struct is_basic_json : std::false_type {};
|
||||
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
|
||||
|
||||
//////////////////////////
|
||||
// aliases for detected //
|
||||
//////////////////////////
|
||||
|
||||
template <typename T>
|
||||
using mapped_type_t = typename T::mapped_type;
|
||||
|
||||
template <typename T>
|
||||
using key_type_t = typename T::key_type;
|
||||
|
||||
template <typename T>
|
||||
using value_type_t = typename T::value_type;
|
||||
|
||||
template <typename T>
|
||||
using difference_type_t = typename T::difference_type;
|
||||
|
||||
template <typename T>
|
||||
using pointer_t = typename T::pointer;
|
||||
|
||||
template <typename T>
|
||||
using reference_t = typename T::reference;
|
||||
|
||||
template <typename T>
|
||||
using iterator_category_t = typename T::iterator_category;
|
||||
|
||||
template <typename T>
|
||||
using iterator_t = typename T::iterator;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
using to_json_function = decltype(T::to_json(std::declval<Args>()...));
|
||||
|
||||
template <typename T, typename... Args>
|
||||
using from_json_function = decltype(T::from_json(std::declval<Args>()...));
|
||||
|
||||
template <typename T, typename U>
|
||||
using get_template_function = decltype(std::declval<T>().template get<U>());
|
||||
|
||||
///////////////////
|
||||
// is_ functions //
|
||||
///////////////////
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_iterator_traits : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_iterator_traits<std::iterator_traits<T>>
|
||||
{
|
||||
private:
|
||||
using traits = std::iterator_traits<T>;
|
||||
|
||||
public:
|
||||
static constexpr auto value =
|
||||
is_detected<value_type_t, traits>::value &&
|
||||
is_detected<difference_type_t, traits>::value &&
|
||||
is_detected<pointer_t, traits>::value &&
|
||||
is_detected<iterator_category_t, traits>::value &&
|
||||
is_detected<reference_t, traits>::value;
|
||||
};
|
||||
|
||||
// source: https://stackoverflow.com/a/37193089/4116453
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_complete_type : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleObjectType,
|
||||
typename = void>
|
||||
struct is_compatible_object_type_impl : std::false_type {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleObjectType>
|
||||
struct is_compatible_object_type_impl <
|
||||
BasicJsonType, CompatibleObjectType,
|
||||
enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
|
||||
is_detected<key_type_t, CompatibleObjectType>::value >>
|
||||
{
|
||||
|
||||
using object_t = typename BasicJsonType::object_t;
|
||||
|
||||
// macOS's is_constructible does not play well with nonesuch...
|
||||
static constexpr bool value =
|
||||
std::is_constructible<typename object_t::key_type,
|
||||
typename CompatibleObjectType::key_type>::value and
|
||||
std::is_constructible<typename object_t::mapped_type,
|
||||
typename CompatibleObjectType::mapped_type>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleObjectType>
|
||||
struct is_compatible_object_type
|
||||
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleStringType,
|
||||
typename = void>
|
||||
struct is_compatible_string_type_impl : std::false_type {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleStringType>
|
||||
struct is_compatible_string_type_impl <
|
||||
BasicJsonType, CompatibleStringType,
|
||||
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
|
||||
value_type_t, CompatibleStringType>::value >>
|
||||
{
|
||||
static constexpr auto value =
|
||||
std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleStringType>
|
||||
struct is_compatible_string_type
|
||||
: is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
|
||||
struct is_compatible_array_type_impl : std::false_type {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleArrayType>
|
||||
struct is_compatible_array_type_impl <
|
||||
BasicJsonType, CompatibleArrayType,
|
||||
enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
|
||||
is_detected<iterator_t, CompatibleArrayType>::value >>
|
||||
{
|
||||
// This is needed because json_reverse_iterator has a ::iterator type...
|
||||
// Therefore it is detected as a CompatibleArrayType.
|
||||
// The real fix would be to have an Iterable concept.
|
||||
static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleArrayType>
|
||||
struct is_compatible_array_type
|
||||
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
||||
|
||||
template <typename RealIntegerType, typename CompatibleNumberIntegerType,
|
||||
typename = void>
|
||||
struct is_compatible_integer_type_impl : std::false_type {};
|
||||
|
||||
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||
struct is_compatible_integer_type_impl <
|
||||
RealIntegerType, CompatibleNumberIntegerType,
|
||||
enable_if_t<std::is_integral<RealIntegerType>::value and
|
||||
std::is_integral<CompatibleNumberIntegerType>::value and
|
||||
not std::is_same<bool, CompatibleNumberIntegerType>::value >>
|
||||
{
|
||||
// is there an assert somewhere on overflows?
|
||||
using RealLimits = std::numeric_limits<RealIntegerType>;
|
||||
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
|
||||
|
||||
static constexpr auto value =
|
||||
std::is_constructible<RealIntegerType,
|
||||
CompatibleNumberIntegerType>::value and
|
||||
CompatibleLimits::is_integer and
|
||||
RealLimits::is_signed == CompatibleLimits::is_signed;
|
||||
};
|
||||
|
||||
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||
struct is_compatible_integer_type
|
||||
: is_compatible_integer_type_impl<RealIntegerType,
|
||||
CompatibleNumberIntegerType> {};
|
||||
|
||||
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
|
||||
template <typename BasicJsonType, typename T, typename = void>
|
||||
struct has_from_json : std::false_type {};
|
||||
|
||||
template <typename BasicJsonType, typename T>
|
||||
struct has_from_json<BasicJsonType, T,
|
||||
enable_if_t<not is_basic_json<T>::value>>
|
||||
{
|
||||
using serializer = typename BasicJsonType::template json_serializer<T, void>;
|
||||
|
||||
static constexpr bool value =
|
||||
is_detected_exact<void, from_json_function, serializer,
|
||||
const BasicJsonType&, T&>::value;
|
||||
};
|
||||
|
||||
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
|
||||
// this overload is used for non-default-constructible user-defined-types
|
||||
template <typename BasicJsonType, typename T, typename = void>
|
||||
struct has_non_default_from_json : std::false_type {};
|
||||
|
||||
template<typename BasicJsonType, typename T>
|
||||
struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
|
||||
{
|
||||
using serializer = typename BasicJsonType::template json_serializer<T, void>;
|
||||
|
||||
static constexpr bool value =
|
||||
is_detected_exact<T, from_json_function, serializer,
|
||||
const BasicJsonType&>::value;
|
||||
};
|
||||
|
||||
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
|
||||
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
|
||||
template <typename BasicJsonType, typename T, typename = void>
|
||||
struct has_to_json : std::false_type {};
|
||||
|
||||
template <typename BasicJsonType, typename T>
|
||||
struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
|
||||
{
|
||||
using serializer = typename BasicJsonType::template json_serializer<T, void>;
|
||||
|
||||
static constexpr bool value =
|
||||
is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
|
||||
T>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleType, typename = void>
|
||||
struct is_compatible_type_impl: std::false_type {};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleType>
|
||||
struct is_compatible_type_impl <
|
||||
BasicJsonType, CompatibleType,
|
||||
enable_if_t<is_complete_type<CompatibleType>::value >>
|
||||
{
|
||||
static constexpr bool value =
|
||||
has_to_json<BasicJsonType, CompatibleType>::value;
|
||||
};
|
||||
|
||||
template <typename BasicJsonType, typename CompatibleType>
|
||||
struct is_compatible_type
|
||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||
}
|
||||
}
|
||||
13
include/nlohmann/detail/meta/void_t.hpp
Normal file
13
include/nlohmann/detail/meta/void_t.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename ...Ts> struct make_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
|
||||
}
|
||||
}
|
||||
@@ -149,9 +149,9 @@ class binary_writer
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::number_float: // Double-Precision Float
|
||||
case value_t::number_float:
|
||||
{
|
||||
oa->write_character(static_cast<CharType>(0xFB));
|
||||
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
|
||||
write_number(j.m_value.number_float);
|
||||
break;
|
||||
}
|
||||
@@ -409,9 +409,9 @@ class binary_writer
|
||||
break;
|
||||
}
|
||||
|
||||
case value_t::number_float: // float 64
|
||||
case value_t::number_float:
|
||||
{
|
||||
oa->write_character(static_cast<CharType>(0xCB));
|
||||
oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
|
||||
write_number(j.m_value.number_float);
|
||||
break;
|
||||
}
|
||||
@@ -588,7 +588,7 @@ class binary_writer
|
||||
if (use_type and not j.m_value.array->empty())
|
||||
{
|
||||
assert(use_count);
|
||||
const char first_prefix = ubjson_prefix(j.front());
|
||||
const CharType first_prefix = ubjson_prefix(j.front());
|
||||
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
||||
[this, first_prefix](const BasicJsonType & v)
|
||||
{
|
||||
@@ -599,7 +599,7 @@ class binary_writer
|
||||
{
|
||||
prefix_required = false;
|
||||
oa->write_character(static_cast<CharType>('$'));
|
||||
oa->write_character(static_cast<CharType>(first_prefix));
|
||||
oa->write_character(first_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ class binary_writer
|
||||
if (use_type and not j.m_value.object->empty())
|
||||
{
|
||||
assert(use_count);
|
||||
const char first_prefix = ubjson_prefix(j.front());
|
||||
const CharType first_prefix = ubjson_prefix(j.front());
|
||||
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
||||
[this, first_prefix](const BasicJsonType & v)
|
||||
{
|
||||
@@ -644,7 +644,7 @@ class binary_writer
|
||||
{
|
||||
prefix_required = false;
|
||||
oa->write_character(static_cast<CharType>('$'));
|
||||
oa->write_character(static_cast<CharType>(first_prefix));
|
||||
oa->write_character(first_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,7 +712,7 @@ class binary_writer
|
||||
{
|
||||
if (add_prefix)
|
||||
{
|
||||
oa->write_character(static_cast<CharType>('D')); // float64
|
||||
oa->write_character(get_ubjson_float_prefix(n));
|
||||
}
|
||||
write_number(n);
|
||||
}
|
||||
@@ -833,7 +833,7 @@ class binary_writer
|
||||
write_number_with_ubjson_prefix. Therefore, we return 'L' for any
|
||||
value that does not fit the previous limits.
|
||||
*/
|
||||
char ubjson_prefix(const BasicJsonType& j) const noexcept
|
||||
CharType ubjson_prefix(const BasicJsonType& j) const noexcept
|
||||
{
|
||||
switch (j.type())
|
||||
{
|
||||
@@ -892,7 +892,7 @@ class binary_writer
|
||||
}
|
||||
|
||||
case value_t::number_float:
|
||||
return 'D';
|
||||
return get_ubjson_float_prefix(j.m_value.number_float);
|
||||
|
||||
case value_t::string:
|
||||
return 'S';
|
||||
@@ -908,6 +908,36 @@ class binary_writer
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr CharType get_cbor_float_prefix(float)
|
||||
{
|
||||
return static_cast<CharType>(0xFA); // Single-Precision Float
|
||||
}
|
||||
|
||||
static constexpr CharType get_cbor_float_prefix(double)
|
||||
{
|
||||
return static_cast<CharType>(0xFB); // Double-Precision Float
|
||||
}
|
||||
|
||||
static constexpr CharType get_msgpack_float_prefix(float)
|
||||
{
|
||||
return static_cast<CharType>(0xCA); // float 32
|
||||
}
|
||||
|
||||
static constexpr CharType get_msgpack_float_prefix(double)
|
||||
{
|
||||
return static_cast<CharType>(0xCB); // float 64
|
||||
}
|
||||
|
||||
static constexpr CharType get_ubjson_float_prefix(float)
|
||||
{
|
||||
return 'd'; // float 32
|
||||
}
|
||||
|
||||
static constexpr CharType get_ubjson_float_prefix(double)
|
||||
{
|
||||
return 'D'; // float 64
|
||||
}
|
||||
|
||||
private:
|
||||
/// whether we can assume little endianess
|
||||
const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
|
||||
|
||||
@@ -9,17 +9,14 @@
|
||||
#include <cstddef> // size_t, ptrdiff_t
|
||||
#include <cstdint> // uint8_t
|
||||
#include <cstdio> // snprintf
|
||||
#include <iomanip> // setfill
|
||||
#include <iterator> // next
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string
|
||||
#include <sstream> // stringstream
|
||||
#include <type_traits> // is_same
|
||||
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
#include <nlohmann/detail/conversions/to_chars.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/output/output_adapters.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@@ -389,9 +386,9 @@ class serializer
|
||||
|
||||
case UTF8_REJECT: // decode found invalid UTF-8 byte
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(byte);
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str()));
|
||||
std::string sn(3, '\0');
|
||||
snprintf(&sn[0], sn.size(), "%.2X", byte);
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
|
||||
}
|
||||
|
||||
default: // decode found yet incomplete multi-byte code point
|
||||
@@ -417,9 +414,9 @@ class serializer
|
||||
else
|
||||
{
|
||||
// we finish reading, but do not accept: string was incomplete
|
||||
std::stringstream ss;
|
||||
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(static_cast<uint8_t>(s.back()));
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str()));
|
||||
std::string sn(3, '\0');
|
||||
snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +442,7 @@ class serializer
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_negative = (x <= 0) and (x != 0); // see issue #755
|
||||
const bool is_negative = not (x >= 0); // see issue #755
|
||||
std::size_t i = 0;
|
||||
|
||||
while (x != 0)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,10 +18,10 @@ namespace nlohmann
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl))
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename = void, typename = void>
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
|
||||
14
meson.build
14
meson.build
@@ -1,7 +1,13 @@
|
||||
project('nlohmann_json', 'cpp')
|
||||
|
||||
nlohmann_json_inc = include_directories('single_include/nlohmann')
|
||||
project('nlohmann_json',
|
||||
'cpp',
|
||||
version : '3.3.0',
|
||||
license : 'MIT',
|
||||
)
|
||||
|
||||
nlohmann_json_dep = declare_dependency(
|
||||
include_directories : nlohmann_json_inc
|
||||
include_directories: include_directories('single_include')
|
||||
)
|
||||
|
||||
nlohmann_json_multiple_headers = declare_dependency(
|
||||
include_directories: include_directories('include')
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,15 +6,14 @@ option(JSON_Coverage "Build test suite with coverage information" OFF)
|
||||
if(JSON_Sanitizer)
|
||||
message(STATUS "Building test suite with Clang sanitizer")
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-std=c++11 -g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS "-g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(JSON_Valgrind)
|
||||
find_program(CMAKE_MEMORYCHECK_COMMAND valgrind)
|
||||
message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})")
|
||||
set(MEMORYCHECK_COMMAND_OPTIONS "--error-exitcode=1 --leak-check=full")
|
||||
set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}")
|
||||
set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full")
|
||||
separate_arguments(memcheck_command)
|
||||
endif()
|
||||
|
||||
@@ -62,11 +61,10 @@ add_library(catch_main OBJECT
|
||||
"src/unit.cpp"
|
||||
)
|
||||
set_target_properties(catch_main PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>"
|
||||
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>"
|
||||
)
|
||||
target_compile_features(catch_main PUBLIC cxx_std_11)
|
||||
target_include_directories(catch_main PRIVATE "thirdparty/catch")
|
||||
|
||||
# https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake
|
||||
@@ -83,6 +81,9 @@ if(MSVC)
|
||||
# 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
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996")
|
||||
|
||||
# https://github.com/nlohmann/json/issues/1114
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||
endif()
|
||||
|
||||
#############################################################################
|
||||
@@ -95,23 +96,21 @@ foreach(file ${files})
|
||||
string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename})
|
||||
|
||||
add_executable(${testcase} $<TARGET_OBJECTS:catch_main> ${file})
|
||||
set_target_properties(${testcase} PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>"
|
||||
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>"
|
||||
target_compile_definitions(${testcase} PRIVATE
|
||||
CATCH_CONFIG_FAST_COMPILE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>
|
||||
)
|
||||
target_compile_options(${testcase} PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
|
||||
)
|
||||
target_include_directories(${testcase} PRIVATE
|
||||
thirdparty/catch
|
||||
thirdparty/fifo_map
|
||||
)
|
||||
|
||||
target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE)
|
||||
target_include_directories(${testcase} PRIVATE "thirdparty/catch")
|
||||
target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map")
|
||||
target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR})
|
||||
target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME})
|
||||
|
||||
if(NOT MSVC)
|
||||
set_target_properties(${testcase} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-float-equal")
|
||||
endif()
|
||||
|
||||
add_test(NAME "${testcase}_default"
|
||||
COMMAND ${testcase} ${CATCH_TEST_FILTER}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
@@ -131,5 +130,11 @@ foreach(file ${files})
|
||||
)
|
||||
set_tests_properties("${testcase}_valgrind" PROPERTIES LABELS "valgrind")
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
#############################################################################
|
||||
# Test the generated build configs
|
||||
#############################################################################
|
||||
add_subdirectory(cmake_import)
|
||||
add_subdirectory(cmake_import_minver)
|
||||
add_subdirectory(cmake_add_subdirectory)
|
||||
|
||||
@@ -42,7 +42,8 @@ SOURCES = src/unit.cpp \
|
||||
src/unit-serialization.cpp \
|
||||
src/unit-testsuites.cpp \
|
||||
src/unit-ubjson.cpp \
|
||||
src/unit-unicode.cpp
|
||||
src/unit-unicode.cpp \
|
||||
src/unit-wstring.cpp
|
||||
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
|
||||
|
||||
15
test/cmake_add_subdirectory/CMakeLists.txt
Normal file
15
test/cmake_add_subdirectory/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
add_test(NAME cmake_add_subdirectory_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-Dnlohmann_json_source=${PROJECT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_add_subdirectory_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_add_subdirectory_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_add_subdirectory
|
||||
)
|
||||
set_tests_properties(cmake_add_subdirectory_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_add_subdirectory
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user