mirror of
https://github.com/nlohmann/json.git
synced 2026-02-17 09:03:58 +00:00
Compare commits
446 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db53bdac19 | ||
|
|
78348afeb6 | ||
|
|
1107f8cd82 | ||
|
|
98f4e31c3e | ||
|
|
58c269b039 | ||
|
|
2182157dc1 | ||
|
|
45f5611d9b | ||
|
|
117c1d14fb | ||
|
|
d584ab269a | ||
|
|
45a8a093d7 | ||
|
|
85849940ba | ||
|
|
ebd3f45808 | ||
|
|
4f270e38cc | ||
|
|
f1080d7c39 | ||
|
|
5d390e91ff | ||
|
|
c1c85b025c | ||
|
|
635a4fc344 | ||
|
|
cf31193de2 | ||
|
|
a794cfdba3 | ||
|
|
91ff96a737 | ||
|
|
b7a2642fba | ||
|
|
fa7f1a524e | ||
|
|
ef283e0cf8 | ||
|
|
3335da622a | ||
|
|
ae48acbb23 | ||
|
|
52f6fd1d91 | ||
|
|
67b0daf27b | ||
|
|
2c23f0a346 | ||
|
|
e73dfef6e5 | ||
|
|
767a3a327d | ||
|
|
d53873a251 | ||
|
|
7a56f5a42b | ||
|
|
5de184b8fb | ||
|
|
ef90d62ddf | ||
|
|
7b961368d5 | ||
|
|
da81e7be22 | ||
|
|
f80efd3954 | ||
|
|
35829928da | ||
|
|
f86090aafc | ||
|
|
30e1cbb0df | ||
|
|
aa10382629 | ||
|
|
798754dfb6 | ||
|
|
97b81da840 | ||
|
|
ffe08983dd | ||
|
|
f665a92330 | ||
|
|
d2e6e1bf58 | ||
|
|
a7567bc596 | ||
|
|
689382a722 | ||
|
|
2f73a4d1f3 | ||
|
|
e3c28afb61 | ||
|
|
0f3c74d821 | ||
|
|
7b2f8cce03 | ||
|
|
8cee0e38d9 | ||
|
|
856fc31d0a | ||
|
|
39419cd5c4 | ||
|
|
86b5ce953a | ||
|
|
d2e4f0b0d9 | ||
|
|
f0c1459554 | ||
|
|
24946f67f1 | ||
|
|
7d0dc10169 | ||
|
|
45a761bd60 | ||
|
|
4e765596f7 | ||
|
|
1308ea055d | ||
|
|
0e7be06bef | ||
|
|
85aaf91b85 | ||
|
|
5a6bdf5934 | ||
|
|
037e93f5c0 | ||
|
|
9f48bb6937 | ||
|
|
6384fe28db | ||
|
|
ad639ad5e6 | ||
|
|
544150d5a5 | ||
|
|
c2e175763c | ||
|
|
d97fa30795 | ||
|
|
7ce720b700 | ||
|
|
19647e083c | ||
|
|
62126278a6 | ||
|
|
1968e5c793 | ||
|
|
4d1eaace8c | ||
|
|
e2c5913a50 | ||
|
|
bba159121f | ||
|
|
f102df3cba | ||
|
|
7b501de054 | ||
|
|
20038e2703 | ||
|
|
87ef3f25f2 | ||
|
|
b49f76931f | ||
|
|
2343d9caeb | ||
|
|
951a7a6455 | ||
|
|
c51b1e6fab | ||
|
|
c7af027cbb | ||
|
|
e5dce64115 | ||
|
|
c5821d91e5 | ||
|
|
ad11b6c35e | ||
|
|
9294e25c98 | ||
|
|
b553a8a93c | ||
|
|
5ba812d518 | ||
|
|
8de10c518b | ||
|
|
f0c55ce0e0 | ||
|
|
2a63869159 | ||
|
|
4b2a00641c | ||
|
|
dbb0b63187 | ||
|
|
a946dfc19c | ||
|
|
978c3c4116 | ||
|
|
0671e92ced | ||
|
|
daa3ca8a2e | ||
|
|
5bccacda30 | ||
|
|
45c8af2c46 | ||
|
|
dd672939a0 | ||
|
|
11fecc25af | ||
|
|
e426219256 | ||
|
|
adfa961ed0 | ||
|
|
6d34d64bfd | ||
|
|
74a31075e3 | ||
|
|
6e49d9f5ff | ||
|
|
f8158997b5 | ||
|
|
df0f612d1b | ||
|
|
3abb788139 | ||
|
|
858e75c4df | ||
|
|
062aeaf7b6 | ||
|
|
6d09cdec34 | ||
|
|
011b15dd08 | ||
|
|
81f4b34e06 | ||
|
|
ac38e95780 | ||
|
|
fa722d5ac3 | ||
|
|
ec95438a59 | ||
|
|
f1768a540a | ||
|
|
cdfe6ceda6 | ||
|
|
b968faa882 | ||
|
|
cd518fbbab | ||
|
|
e8427061a0 | ||
|
|
b911654857 | ||
|
|
bb55885215 | ||
|
|
5c7d27c338 | ||
|
|
b6fdad9acd | ||
|
|
7c385a4844 | ||
|
|
9ba3f79667 | ||
|
|
8d1585f065 | ||
|
|
ad3c216bb5 | ||
|
|
0231059290 | ||
|
|
9f18e17063 | ||
|
|
53ec0a16f3 | ||
|
|
4c617611e2 | ||
|
|
829571ab5c | ||
|
|
c8231eff75 | ||
|
|
02e653bdf7 | ||
|
|
564506a885 | ||
|
|
1729db85c1 | ||
|
|
910a895027 | ||
|
|
1fae82b7a7 | ||
|
|
22e55349a6 | ||
|
|
70e587c3da | ||
|
|
d26f39466e | ||
|
|
c61a9071ae | ||
|
|
e8730e5e82 | ||
|
|
b59a58406e | ||
|
|
4e54c9a13d | ||
|
|
0a09db9cc2 | ||
|
|
95432c34f9 | ||
|
|
8c1387cfb3 | ||
|
|
521fe49fec | ||
|
|
680a4ab672 | ||
|
|
7a37ba0c02 | ||
|
|
ef358ae695 | ||
|
|
99b7c7c8ef | ||
|
|
bce4816275 | ||
|
|
763705c2a7 | ||
|
|
e184b6ecf2 | ||
|
|
88b055c2df | ||
|
|
8799759b85 | ||
|
|
4e52277b70 | ||
|
|
e4bc98d036 | ||
|
|
4d780b091b | ||
|
|
3b1a5cafad | ||
|
|
99939d6340 | ||
|
|
4e2f35d4c2 | ||
|
|
7fa3b8865c | ||
|
|
8f07ab6392 | ||
|
|
df33a90774 | ||
|
|
cf485c2907 | ||
|
|
120d1d77d4 | ||
|
|
5ce7d6bdd7 | ||
|
|
83b427ad67 | ||
|
|
c0d8921a67 | ||
|
|
7ee361f7ad | ||
|
|
c5ef023171 | ||
|
|
6c447de076 | ||
|
|
0c0f2e44b5 | ||
|
|
9a0dddc5d2 | ||
|
|
5f5836ce1c | ||
|
|
f06c8fd8e3 | ||
|
|
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 | ||
|
|
8a6c8cb0f7 | ||
|
|
afef474c0d | ||
|
|
a52e8355b8 | ||
|
|
21410d50af | ||
|
|
829ed74d66 | ||
|
|
1262d474eb | ||
|
|
282bafae4f | ||
|
|
abac6a0e84 | ||
|
|
919d1fef8f | ||
|
|
8557151d90 | ||
|
|
b56ac86471 | ||
|
|
0cab3b2c8e | ||
|
|
3d4f6a2940 | ||
|
|
ad47b0fbde | ||
|
|
392c033805 | ||
|
|
51349537fc | ||
|
|
830f3e5290 | ||
|
|
ed6b1464f9 | ||
|
|
faccc37d0d | ||
|
|
149d2fd09c | ||
|
|
6399cd3039 | ||
|
|
6151dfaed7 | ||
|
|
35e43df625 | ||
|
|
9918523077 | ||
|
|
e737de8941 | ||
|
|
aa8fc2a41c | ||
|
|
7c1a788893 | ||
|
|
cf60e18c89 | ||
|
|
97559bb1b2 | ||
|
|
38345fd06c | ||
|
|
8b379948d0 | ||
|
|
303a0c5843 | ||
|
|
d183d34b96 | ||
|
|
d2d65bb25b | ||
|
|
476b2e09be | ||
|
|
62030615a0 | ||
|
|
5beab80553 | ||
|
|
faf2546a15 | ||
|
|
5b9d03cfdb | ||
|
|
9d27429527 | ||
|
|
86991d5204 | ||
|
|
fdecbf6e1e | ||
|
|
fd30ad8a14 | ||
|
|
2a2ed799b1 | ||
|
|
8d104e6fe3 | ||
|
|
5773e164bb | ||
|
|
8711ec6034 | ||
|
|
c22f2d41f3 | ||
|
|
3ff9455332 | ||
|
|
21352c4d8e | ||
|
|
981e226ca2 | ||
|
|
1f3d2a3be7 | ||
|
|
13ca723c38 | ||
|
|
05d3bf1699 | ||
|
|
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**.
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,6 +10,7 @@ fuzz-testing
|
||||
|
||||
build
|
||||
build_coverage
|
||||
clang_analyze_build
|
||||
|
||||
doc/xml
|
||||
doc/html
|
||||
@@ -21,3 +22,4 @@ benchmarks/files/numbers/*.json
|
||||
cmake-build-debug
|
||||
|
||||
test/test-*
|
||||
/.vs
|
||||
|
||||
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.1 LANGUAGES CXX)
|
||||
project(nlohmann_json VERSION 3.5.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,18 +55,18 @@ 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(
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
$<INSTALL_INTERFACE:${NLOHMANN_NATVIS_FILE}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}>
|
||||
$<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}
|
||||
)
|
||||
|
||||
417
ChangeLog.md
417
ChangeLog.md
@@ -1,7 +1,421 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-12)
|
||||
## [v3.5.0](https://github.com/nlohmann/json/releases/tag/v3.5.0) (2018-12-21)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.4.0...v3.5.0)
|
||||
|
||||
- Copyconstructor inserts original into array with single element [\#1397](https://github.com/nlohmann/json/issues/1397)
|
||||
- Get value without explicit typecasting [\#1395](https://github.com/nlohmann/json/issues/1395)
|
||||
- Big file parsing [\#1393](https://github.com/nlohmann/json/issues/1393)
|
||||
- some static analysis warning at line 11317 [\#1390](https://github.com/nlohmann/json/issues/1390)
|
||||
- Adding Structured Binding Support [\#1388](https://github.com/nlohmann/json/issues/1388)
|
||||
- map\<json::value\_t, string\> exhibits unexpected behavior [\#1387](https://github.com/nlohmann/json/issues/1387)
|
||||
- Error Code Return [\#1386](https://github.com/nlohmann/json/issues/1386)
|
||||
- using unordered\_map as object type [\#1385](https://github.com/nlohmann/json/issues/1385)
|
||||
- float precision [\#1384](https://github.com/nlohmann/json/issues/1384)
|
||||
- \[json.exception.type\_error.316\] invalid UTF-8 byte at index 1: 0xC3 [\#1383](https://github.com/nlohmann/json/issues/1383)
|
||||
- Inconsistent Constructor \(GCC vs. Clang\) [\#1381](https://github.com/nlohmann/json/issues/1381)
|
||||
- \#define or || [\#1379](https://github.com/nlohmann/json/issues/1379)
|
||||
- How to iterate inside the values ? [\#1377](https://github.com/nlohmann/json/issues/1377)
|
||||
- items\(\) unable to get the elements [\#1375](https://github.com/nlohmann/json/issues/1375)
|
||||
- conversion json to std::map doesn't work for types \<int, double\> [\#1372](https://github.com/nlohmann/json/issues/1372)
|
||||
- A minor issue in the build instructions [\#1371](https://github.com/nlohmann/json/issues/1371)
|
||||
- Using this library without stream ? [\#1370](https://github.com/nlohmann/json/issues/1370)
|
||||
- Writing and reading BSON data [\#1368](https://github.com/nlohmann/json/issues/1368)
|
||||
- Retrieving array elements from object type iterator. [\#1367](https://github.com/nlohmann/json/issues/1367)
|
||||
- json::dump\(\) silently crashes if items contain accented letters [\#1365](https://github.com/nlohmann/json/issues/1365)
|
||||
- warnings in MSVC \(2015\) in 3.4.0 related to bool... [\#1364](https://github.com/nlohmann/json/issues/1364)
|
||||
- Cant compile with -C++17 and beyond compiler options [\#1362](https://github.com/nlohmann/json/issues/1362)
|
||||
- json to concrete type conversion through reference or pointer fails [\#1361](https://github.com/nlohmann/json/issues/1361)
|
||||
- the first attributes of JSON string is misplaced [\#1360](https://github.com/nlohmann/json/issues/1360)
|
||||
- Copy-construct using initializer-list converts objects to arrays [\#1359](https://github.com/nlohmann/json/issues/1359)
|
||||
- About value\(key, default\_value\) and operator\[\]\(key\) [\#1358](https://github.com/nlohmann/json/issues/1358)
|
||||
- Problem with printing json response object [\#1356](https://github.com/nlohmann/json/issues/1356)
|
||||
- Serializing pointer segfaults [\#1355](https://github.com/nlohmann/json/issues/1355)
|
||||
- Read `long long int` data as a number. [\#1354](https://github.com/nlohmann/json/issues/1354)
|
||||
- eclipse oxygen in ubuntu get\<size\_t\> is ambiguous [\#1353](https://github.com/nlohmann/json/issues/1353)
|
||||
- Can't build on Visual Studio 2017 v15.8.9 [\#1350](https://github.com/nlohmann/json/issues/1350)
|
||||
- cannot parse from string? [\#1349](https://github.com/nlohmann/json/issues/1349)
|
||||
- Error: out\_of\_range [\#1348](https://github.com/nlohmann/json/issues/1348)
|
||||
- expansion pattern 'CompatibleObjectType' contains no argument packs, with CUDA 10 [\#1347](https://github.com/nlohmann/json/issues/1347)
|
||||
- Unable to update a value for a nested\(multi-level\) json file [\#1344](https://github.com/nlohmann/json/issues/1344)
|
||||
- Fails to compile when std::iterator\_traits is not SFINAE friendly. [\#1341](https://github.com/nlohmann/json/issues/1341)
|
||||
- EOF flag not set on exhausted input streams. [\#1340](https://github.com/nlohmann/json/issues/1340)
|
||||
- Shadowed Member in merge\_patch [\#1339](https://github.com/nlohmann/json/issues/1339)
|
||||
- Periods/literal dots in keys? [\#1338](https://github.com/nlohmann/json/issues/1338)
|
||||
- Protect macro expansion of commonly defined macros [\#1337](https://github.com/nlohmann/json/issues/1337)
|
||||
- How to validate an input before parsing? [\#1336](https://github.com/nlohmann/json/issues/1336)
|
||||
- Non-verifying dump\(\) alternative for debugging/logging needed [\#1335](https://github.com/nlohmann/json/issues/1335)
|
||||
- Improve number-to-string conversion [\#1334](https://github.com/nlohmann/json/issues/1334)
|
||||
- Json Libarary is not responding for me in c++ [\#1332](https://github.com/nlohmann/json/issues/1332)
|
||||
- Question - how to find an object in an array [\#1331](https://github.com/nlohmann/json/issues/1331)
|
||||
- Nesting additional data in json object [\#1328](https://github.com/nlohmann/json/issues/1328)
|
||||
- can to\_json\(\) be defined inside a class? [\#1324](https://github.com/nlohmann/json/issues/1324)
|
||||
- CodeBlocks IDE can't find `json.hpp` header [\#1318](https://github.com/nlohmann/json/issues/1318)
|
||||
- Change json\_pointer to provide an iterator begin/end/etc, don't use vectors, and also enable string\_view [\#1312](https://github.com/nlohmann/json/issues/1312)
|
||||
- Xcode - adding it to library [\#1300](https://github.com/nlohmann/json/issues/1300)
|
||||
- unicode: accept char16\_t, char32\_t sequences [\#1298](https://github.com/nlohmann/json/issues/1298)
|
||||
- unicode: char16\_t\* is compiler error, but char16\_t\[\] is accepted [\#1297](https://github.com/nlohmann/json/issues/1297)
|
||||
- Dockerfile Project Help Needed [\#1296](https://github.com/nlohmann/json/issues/1296)
|
||||
- Comparisons between large unsigned and negative signed integers [\#1295](https://github.com/nlohmann/json/issues/1295)
|
||||
- CMake alias to `nlohmann::json` [\#1291](https://github.com/nlohmann/json/issues/1291)
|
||||
- Release zips without tests [\#1285](https://github.com/nlohmann/json/issues/1285)
|
||||
- Suggestion to improve value\(\) accessors with respect to move semantics [\#1275](https://github.com/nlohmann/json/issues/1275)
|
||||
- separate object\_t::key\_type from basic\_json::key\_type, and use an allocator which returns object\_t::key\_type [\#1274](https://github.com/nlohmann/json/issues/1274)
|
||||
- Is there a nice way to associate external values with json elements? [\#1256](https://github.com/nlohmann/json/issues/1256)
|
||||
- Delete by json\_pointer [\#1248](https://github.com/nlohmann/json/issues/1248)
|
||||
- Expose lexer, as a StAX parser [\#1219](https://github.com/nlohmann/json/issues/1219)
|
||||
- Subclassing json\(\) & error on recursive load [\#1201](https://github.com/nlohmann/json/issues/1201)
|
||||
- Check value for existence by json\_pointer [\#1194](https://github.com/nlohmann/json/issues/1194)
|
||||
|
||||
- Feature/add file input adapter [\#1392](https://github.com/nlohmann/json/pull/1392) ([dumarjo](https://github.com/dumarjo))
|
||||
- Added Support for Structured Bindings [\#1391](https://github.com/nlohmann/json/pull/1391) ([pratikpc](https://github.com/pratikpc))
|
||||
- Link to issue \#958 broken [\#1382](https://github.com/nlohmann/json/pull/1382) ([kjpus](https://github.com/kjpus))
|
||||
- readme: fix typo [\#1380](https://github.com/nlohmann/json/pull/1380) ([manu-chroma](https://github.com/manu-chroma))
|
||||
- recommend using explicit from JSON conversions [\#1363](https://github.com/nlohmann/json/pull/1363) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Fix merge\_patch shadow warning [\#1346](https://github.com/nlohmann/json/pull/1346) ([ax3l](https://github.com/ax3l))
|
||||
- Allow installation via Meson [\#1345](https://github.com/nlohmann/json/pull/1345) ([mpoquet](https://github.com/mpoquet))
|
||||
- Set eofbit on exhausted input stream. [\#1343](https://github.com/nlohmann/json/pull/1343) ([mefyl](https://github.com/mefyl))
|
||||
- Add a SFINAE friendly iterator\_traits and use that instead. [\#1342](https://github.com/nlohmann/json/pull/1342) ([davedissian](https://github.com/davedissian))
|
||||
- Fix EOL Whitespaces & CMake Spelling [\#1329](https://github.com/nlohmann/json/pull/1329) ([ax3l](https://github.com/ax3l))
|
||||
|
||||
## [v3.4.0](https://github.com/nlohmann/json/releases/tag/v3.4.0) (2018-10-30)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.3.0...v3.4.0)
|
||||
|
||||
- Big uint64\_t values are serialized wrong [\#1327](https://github.com/nlohmann/json/issues/1327)
|
||||
- \[Question\] Efficient check for equivalency? [\#1325](https://github.com/nlohmann/json/issues/1325)
|
||||
- Can't use ifstream and .clear\(\) [\#1321](https://github.com/nlohmann/json/issues/1321)
|
||||
- \[Warning\] -Wparentheses on line 555 on single\_include [\#1319](https://github.com/nlohmann/json/issues/1319)
|
||||
- Compilation error using at and find with enum struct [\#1316](https://github.com/nlohmann/json/issues/1316)
|
||||
- Parsing JSON from a web address [\#1311](https://github.com/nlohmann/json/issues/1311)
|
||||
- How to convert JSON to Struct with embeded subject [\#1310](https://github.com/nlohmann/json/issues/1310)
|
||||
- Null safety/coalescing function? [\#1309](https://github.com/nlohmann/json/issues/1309)
|
||||
- Building fails using single include file: json.hpp [\#1308](https://github.com/nlohmann/json/issues/1308)
|
||||
- json::parse\(std::string\) Exception inside packaged Lib [\#1306](https://github.com/nlohmann/json/issues/1306)
|
||||
- Problem in Dockerfile with installation of library [\#1304](https://github.com/nlohmann/json/issues/1304)
|
||||
- compile error in from\_json converting to container with std::pair [\#1299](https://github.com/nlohmann/json/issues/1299)
|
||||
- Json that I am trying to parse, and I am lost Structure Array below top level [\#1293](https://github.com/nlohmann/json/issues/1293)
|
||||
- Serializing std::variant causes stack overflow [\#1292](https://github.com/nlohmann/json/issues/1292)
|
||||
- How do I go about customising from\_json to support \_\_int128\_t/\_\_uint128\_t? [\#1290](https://github.com/nlohmann/json/issues/1290)
|
||||
- merge\_patch: inconsistent behaviour merging empty sub-object [\#1289](https://github.com/nlohmann/json/issues/1289)
|
||||
- Buffer over/underrun using UBJson? [\#1288](https://github.com/nlohmann/json/issues/1288)
|
||||
- Enable the latest C++ standard with Visual Studio [\#1287](https://github.com/nlohmann/json/issues/1287)
|
||||
- truncation of constant value in to\_cbor\(\) [\#1286](https://github.com/nlohmann/json/issues/1286)
|
||||
- eosio.wasmsdk error [\#1284](https://github.com/nlohmann/json/issues/1284)
|
||||
- use the same interface for writing arrays and non-arrays [\#1283](https://github.com/nlohmann/json/issues/1283)
|
||||
- How to read json file with optional entries and entries with different types [\#1281](https://github.com/nlohmann/json/issues/1281)
|
||||
- merge result not as espected [\#1279](https://github.com/nlohmann/json/issues/1279)
|
||||
- how to get only "name" from below json [\#1278](https://github.com/nlohmann/json/issues/1278)
|
||||
- syntax error on right json string [\#1276](https://github.com/nlohmann/json/issues/1276)
|
||||
- Parsing JSON Array where members have no key, using custom types [\#1267](https://github.com/nlohmann/json/issues/1267)
|
||||
- I get a json exception periodically from json::parse for the same json [\#1263](https://github.com/nlohmann/json/issues/1263)
|
||||
- serialize std::variant\<...\> [\#1261](https://github.com/nlohmann/json/issues/1261)
|
||||
- GCC 8.2.1. Compilation error: invalid conversion from... [\#1246](https://github.com/nlohmann/json/issues/1246)
|
||||
- BSON support [\#1244](https://github.com/nlohmann/json/issues/1244)
|
||||
- enum to json mapping [\#1208](https://github.com/nlohmann/json/issues/1208)
|
||||
- Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198)
|
||||
- CMakeLists.txt in release zips? [\#1184](https://github.com/nlohmann/json/issues/1184)
|
||||
- CBOR byte string support [\#1129](https://github.com/nlohmann/json/issues/1129)
|
||||
|
||||
- Add macro to define enum/JSON mapping [\#1323](https://github.com/nlohmann/json/pull/1323) ([nlohmann](https://github.com/nlohmann))
|
||||
- Add BSON support [\#1320](https://github.com/nlohmann/json/pull/1320) ([nlohmann](https://github.com/nlohmann))
|
||||
- Properly convert constants to CharType [\#1315](https://github.com/nlohmann/json/pull/1315) ([nlohmann](https://github.com/nlohmann))
|
||||
- Allow to set error handler for decoding errors [\#1314](https://github.com/nlohmann/json/pull/1314) ([nlohmann](https://github.com/nlohmann))
|
||||
- Add Meson related info to README [\#1305](https://github.com/nlohmann/json/pull/1305) ([koponomarenko](https://github.com/koponomarenko))
|
||||
- Improve diagnostic messages for binary formats [\#1303](https://github.com/nlohmann/json/pull/1303) ([nlohmann](https://github.com/nlohmann))
|
||||
- add new is\_constructible\_\* traits used in from\_json [\#1301](https://github.com/nlohmann/json/pull/1301) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- add constraints for variadic json\_ref constructors [\#1294](https://github.com/nlohmann/json/pull/1294) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Improve diagnostic messages [\#1282](https://github.com/nlohmann/json/pull/1282) ([nlohmann](https://github.com/nlohmann))
|
||||
- Removed linter warnings [\#1280](https://github.com/nlohmann/json/pull/1280) ([nlohmann](https://github.com/nlohmann))
|
||||
- Thirdparty benchmark: Fix Clang detection. [\#1277](https://github.com/nlohmann/json/pull/1277) ([Lord-Kamina](https://github.com/Lord-Kamina))
|
||||
|
||||
## [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)
|
||||
- While compiling got 76 errors [\#1255](https://github.com/nlohmann/json/issues/1255)
|
||||
- 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)
|
||||
- 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)
|
||||
|
||||
- STL containers are always serialized to a nested array like \[\[1,2,3\]\] [\#1013](https://github.com/nlohmann/json/issues/1013)
|
||||
- The library doesn't want to insert an unordered\_map [\#1010](https://github.com/nlohmann/json/issues/1010)
|
||||
- Convert Json to uint8\_t [\#1008](https://github.com/nlohmann/json/issues/1008)
|
||||
- How to compare two JSON objects? [\#1007](https://github.com/nlohmann/json/issues/1007)
|
||||
- Syntax checking [\#1003](https://github.com/nlohmann/json/issues/1003)
|
||||
- more than one operator '=' matches these operands [\#1002](https://github.com/nlohmann/json/issues/1002)
|
||||
- How to check if key existed [\#1000](https://github.com/nlohmann/json/issues/1000)
|
||||
- nlohmann::json::parse exhaust memory in go binding [\#999](https://github.com/nlohmann/json/issues/999)
|
||||
- Range-based iteration over a non-array object [\#998](https://github.com/nlohmann/json/issues/998)
|
||||
- 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)
|
||||
- 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)
|
||||
- UTF-8/Unicode error [\#982](https://github.com/nlohmann/json/issues/982)
|
||||
- "forcing MSVC stacktrace to show which T we're talking about." error [\#980](https://github.com/nlohmann/json/issues/980)
|
||||
- reverse order of serialization [\#979](https://github.com/nlohmann/json/issues/979)
|
||||
- Assigning between different json types [\#977](https://github.com/nlohmann/json/issues/977)
|
||||
- Support serialisation of `unique\_ptr\<\>` and `shared\_ptr\<\>` [\#975](https://github.com/nlohmann/json/issues/975)
|
||||
- Unexpected end of input \(not same as one before\) [\#974](https://github.com/nlohmann/json/issues/974)
|
||||
- Segfault on direct initializing json object [\#973](https://github.com/nlohmann/json/issues/973)
|
||||
- Segmentation fault on G++ when trying to assign json string literal to custom json type. [\#972](https://github.com/nlohmann/json/issues/972)
|
||||
- os\_defines.h:44:19: error: missing binary operator before token "\(" [\#970](https://github.com/nlohmann/json/issues/970)
|
||||
- Passing an iteration object by reference to a function [\#967](https://github.com/nlohmann/json/issues/967)
|
||||
- Json and fmt::lib's format\_arg\(\) [\#964](https://github.com/nlohmann/json/issues/964)
|
||||
- Feature: to\_string\(const json& j\); [\#916](https://github.com/nlohmann/json/issues/916)
|
||||
|
||||
- Allowing for user-defined string type in lexer/parser [\#1009](https://github.com/nlohmann/json/pull/1009) ([nlohmann](https://github.com/nlohmann))
|
||||
- dump to alternative string type, as defined in basic\_json template [\#1006](https://github.com/nlohmann/json/pull/1006) ([agrianius](https://github.com/agrianius))
|
||||
- Fix memory leak during parser callback [\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann))
|
||||
- fixed misprinted condition detected by PVS Studio. [\#992](https://github.com/nlohmann/json/pull/992) ([bogemic](https://github.com/bogemic))
|
||||
- Fix/basic json conversion [\#986](https://github.com/nlohmann/json/pull/986) ([theodelrieu](https://github.com/theodelrieu))
|
||||
- Make integration section concise [\#981](https://github.com/nlohmann/json/pull/981) ([wla80](https://github.com/wla80))
|
||||
|
||||
## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-13)
|
||||
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.0...v3.1.1)
|
||||
|
||||
- Updation of child object isn't reflected in parent Object [\#968](https://github.com/nlohmann/json/issues/968)
|
||||
@@ -746,7 +1160,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)
|
||||
|
||||
31
Makefile
31
Makefile
@@ -9,8 +9,10 @@ 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/input/position_t.hpp \
|
||||
include/nlohmann/detail/iterators/internal_iterator.hpp \
|
||||
include/nlohmann/detail/iterators/iter_impl.hpp \
|
||||
include/nlohmann/detail/iterators/iteration_proxy.hpp \
|
||||
@@ -20,7 +22,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 \
|
||||
@@ -43,6 +48,7 @@ all:
|
||||
@echo "cppcheck - analyze code with cppcheck"
|
||||
@echo "doctest - compile example files and check their output"
|
||||
@echo "fuzz_testing - prepare fuzz testing of the JSON parser"
|
||||
@echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser"
|
||||
@echo "fuzz_testing_cbor - prepare fuzz testing of the CBOR parser"
|
||||
@echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser"
|
||||
@echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser"
|
||||
@@ -82,9 +88,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 +193,10 @@ pedantic_gcc:
|
||||
-Wunused-macros \
|
||||
-Wunused-parameter \
|
||||
-Wuseless-cast \
|
||||
-Wvariadic-macros"
|
||||
-Wvariadic-macros \
|
||||
-Wctor-dtor-privacy \
|
||||
-Winit-self \
|
||||
-Wstrict-null-sentinel"
|
||||
|
||||
##########################################################################
|
||||
# benchmarks
|
||||
@@ -212,6 +221,14 @@ fuzz_testing:
|
||||
find test/data/json_tests -size -5k -name *json | xargs -I{} cp "{}" fuzz-testing/testcases
|
||||
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
|
||||
|
||||
fuzz_testing_bson:
|
||||
rm -fr fuzz-testing
|
||||
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
|
||||
$(MAKE) parse_bson_fuzzer -C test CXX=afl-clang++
|
||||
mv test/parse_bson_fuzzer fuzz-testing/fuzzer
|
||||
find test/data -size -5k -name *.bson | xargs -I{} cp "{}" fuzz-testing/testcases
|
||||
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
|
||||
|
||||
fuzz_testing_cbor:
|
||||
rm -fr fuzz-testing
|
||||
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
|
||||
@@ -258,6 +275,12 @@ fuzzing-stop:
|
||||
cppcheck:
|
||||
cppcheck --enable=warning --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1
|
||||
|
||||
# compile and check with Clang Static Analyzer
|
||||
clang_analyze:
|
||||
rm -fr clang_analyze_build
|
||||
mkdir clang_analyze_build
|
||||
cd clang_analyze_build ; CCC_CXX=/Users/niels/Documents/projects/llvm-clang/local/bin/clang++ /Users/niels/Documents/projects/llvm-clang/local/bin/scan-build cmake ..
|
||||
/Users/niels/Documents/projects/llvm-clang/local/bin/scan-build -enable-checker alpha.core.DynamicTypeChecker,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.cplusplus.DeleteWithNonVirtualDtor,alpha.cplusplus.IteratorRange,alpha.cplusplus.MisusedMovedObject,alpha.security.ArrayBoundV2,alpha.core.Conversion --use-c++=/Users/niels/Documents/projects/llvm-clang/local/bin/clang++ --view -analyze-headers -o clang_analyze_build/report.html make -j10 -C clang_analyze_build
|
||||
|
||||
##########################################################################
|
||||
# maintainer targets
|
||||
|
||||
433
README.md
433
README.md
@@ -5,7 +5,8 @@
|
||||
[](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://wandbox.org/permlink/DfWUb7e2q2USw0Q6)
|
||||
[](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)
|
||||
[](https://github.com/nlohmann/json/releases)
|
||||
@@ -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)
|
||||
@@ -24,7 +27,8 @@
|
||||
- [JSON Merge Patch](#json-merge-patch)
|
||||
- [Implicit conversions](#implicit-conversions)
|
||||
- [Conversions to/from arbitrary types](#arbitrary-types-conversions)
|
||||
- [Binary formats (CBOR, MessagePack, and UBJSON)](#binary-formats-cbor-messagepack-and-ubjson)
|
||||
- [Specializing enum conversion](#specializing-enum-conversion)
|
||||
- [Binary formats (BSON, CBOR, MessagePack, and UBJSON)](#binary-formats-bson-cbor-messagepack-and-ubjson)
|
||||
- [Supported compilers](#supported-compilers)
|
||||
- [License](#license)
|
||||
- [Contact](#contact)
|
||||
@@ -42,7 +46,7 @@ There are myriads of [JSON](http://json.org) libraries out there, and each may e
|
||||
|
||||
- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
|
||||
|
||||
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289).
|
||||
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289).
|
||||
|
||||
Other aspects were not so important to us:
|
||||
|
||||
@@ -55,7 +59,7 @@ See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.
|
||||
|
||||
## Integration
|
||||
|
||||
The single required source, file `json.hpp` is in the `single_include/nlohmann` directory or [released here](https://github.com/nlohmann/json/releases). All you need to do is add
|
||||
[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add
|
||||
|
||||
```cpp
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -64,25 +68,100 @@ The single required source, file `json.hpp` is in the `single_include/nlohmann`
|
||||
using json = nlohmann::json;
|
||||
```
|
||||
|
||||
to the files you want to use JSON objects. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).
|
||||
to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).
|
||||
|
||||
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`:
|
||||
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`.
|
||||
|
||||
If you are using the [Meson Build System](http://mesonbuild.com), then you can wrap this repository as a subproject.
|
||||
If you are using the [Meson Build System](http://mesonbuild.com), then you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`.
|
||||
|
||||
If you are using [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).
|
||||
|
||||
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging.
|
||||
|
||||
If you are using [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 [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
|
||||
|
||||
@@ -111,7 +190,7 @@ Assume you want to create the JSON object
|
||||
}
|
||||
```
|
||||
|
||||
With the JSON class, you could write:
|
||||
With this library, you could write:
|
||||
|
||||
```cpp
|
||||
// create an empty structure (null)
|
||||
@@ -155,7 +234,7 @@ json j2 = {
|
||||
};
|
||||
```
|
||||
|
||||
Note that in all these cases, you never need to "tell" the compiler which JSON value you want to use. If you want to be explicit or express some edge cases, the functions `json::array` and `json::object` will help:
|
||||
Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa80485befaffcadaa39965494e0b4d2e.html#aa80485befaffcadaa39965494e0b4d2e) and [`json::object`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa13f7c0615867542ce80337cbcf13ada.html#aa13f7c0615867542ce80337cbcf13ada) will help:
|
||||
|
||||
```cpp
|
||||
// a way to express the empty array []
|
||||
@@ -169,12 +248,11 @@ json empty_object_explicit = json::object();
|
||||
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
|
||||
```
|
||||
|
||||
|
||||
### Serialization / Deserialization
|
||||
|
||||
#### To/from strings
|
||||
|
||||
You can create an object (deserialization) by appending `_json` to a string literal:
|
||||
You can create a JSON value (deserialization) by appending `_json` to a string literal:
|
||||
|
||||
```cpp
|
||||
// create object from string literal
|
||||
@@ -191,14 +269,14 @@ auto j2 = R"(
|
||||
|
||||
Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object.
|
||||
|
||||
The above example can also be expressed explicitly using `json::parse()`:
|
||||
The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa9676414f2e36383c4b181fe856aa3c0.html#aa9676414f2e36383c4b181fe856aa3c0):
|
||||
|
||||
```cpp
|
||||
// parse explicitly
|
||||
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
|
||||
```
|
||||
|
||||
You can also get a string representation (serialize):
|
||||
You can also get a string representation of a JSON value (serialize):
|
||||
|
||||
```cpp
|
||||
// explicit conversion to string
|
||||
@@ -219,10 +297,11 @@ Note the difference between serialization and assignment:
|
||||
// store a string in a JSON value
|
||||
json j_string = "this is a string";
|
||||
|
||||
// retrieve the string value (implicit JSON to std::string conversion)
|
||||
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
|
||||
auto cpp_string = j_string.get<std::string>();
|
||||
// retrieve the string value (alternative when an variable already exists)
|
||||
std::string cpp_string2;
|
||||
j_string.get_to(cpp_string2);
|
||||
|
||||
// retrieve the serialized value (explicit JSON serialization)
|
||||
std::string serialized_string = j_string.dump();
|
||||
@@ -233,8 +312,9 @@ std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::
|
||||
std::cout << j_string << " == " << serialized_string << std::endl;
|
||||
```
|
||||
|
||||
`.dump()` always returns the serialized value, and `.get<std::string>()` returns the originally stored string value.
|
||||
[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_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_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
|
||||
|
||||
#### To/from streams (e.g. files, string streams)
|
||||
|
||||
@@ -269,7 +349,7 @@ Please note that setting the exception bit for `failbit` is inappropriate for th
|
||||
|
||||
#### Read from iterator range
|
||||
|
||||
You can also read JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector<std::uint8_t>`:
|
||||
You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector<std::uint8_t>`:
|
||||
|
||||
```cpp
|
||||
std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
@@ -283,10 +363,52 @@ 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
|
||||
@@ -309,7 +431,7 @@ for (auto& element : j) {
|
||||
}
|
||||
|
||||
// getter/setter
|
||||
const std::string tmp = j[0];
|
||||
const auto tmp = j[0].get<std::string>();
|
||||
j[1] = 42;
|
||||
bool foo = j.at(2);
|
||||
|
||||
@@ -344,6 +466,16 @@ for (json::iterator it = o.begin(); it != o.end(); ++it) {
|
||||
std::cout << it.key() << " : " << it.value() << "\n";
|
||||
}
|
||||
|
||||
// the same code as range for
|
||||
for (auto& el : o.items()) {
|
||||
std::cout << el.key() << " : " << el.value() << "\n";
|
||||
}
|
||||
|
||||
// even easier with structured bindings (C++17)
|
||||
for (auto& [key, value] : o.items()) {
|
||||
std::cout << key << " : " << value << "\n";
|
||||
}
|
||||
|
||||
// find an entry
|
||||
if (o.find("foo") != o.end()) {
|
||||
// there is an entry with key "foo"
|
||||
@@ -360,7 +492,7 @@ o.erase("foo");
|
||||
|
||||
### Conversion from STL containers
|
||||
|
||||
Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON types (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container.
|
||||
Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container.
|
||||
|
||||
```cpp
|
||||
std::vector<int> c_vector {1, 2, 3, 4};
|
||||
@@ -400,7 +532,7 @@ json j_umset(c_umset); // both entries for "one" are used
|
||||
// maybe ["one", "two", "one", "four"]
|
||||
```
|
||||
|
||||
Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container.
|
||||
Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container.
|
||||
|
||||
```cpp
|
||||
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
|
||||
@@ -492,40 +624,53 @@ j_original.merge_patch(j_patch);
|
||||
|
||||
### Implicit conversions
|
||||
|
||||
The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted.
|
||||
Supported types can be implicitly converted to JSON values.
|
||||
|
||||
It is recommended to **NOT USE** implicit conversions **FROM** a JSON value.
|
||||
You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958).
|
||||
|
||||
```cpp
|
||||
// strings
|
||||
std::string s1 = "Hello, world!";
|
||||
json js = s1;
|
||||
std::string s2 = js;
|
||||
auto s2 = js.get<std::string>();
|
||||
// NOT RECOMMENDED
|
||||
std::string s3 = js;
|
||||
std::string s4;
|
||||
s4 = js;
|
||||
|
||||
// Booleans
|
||||
bool b1 = true;
|
||||
json jb = b1;
|
||||
bool b2 = jb;
|
||||
auto b2 = jb.get<bool>();
|
||||
// NOT RECOMMENDED
|
||||
bool b3 = jb;
|
||||
bool b4;
|
||||
b4 = jb;
|
||||
|
||||
// numbers
|
||||
int i = 42;
|
||||
json jn = i;
|
||||
double f = jn;
|
||||
auto f = jn.get<double>();
|
||||
// NOT RECOMMENDED
|
||||
double f2 = jb;
|
||||
double f3;
|
||||
f3 = jb;
|
||||
|
||||
// etc.
|
||||
```
|
||||
|
||||
You can also explicitly ask for the value:
|
||||
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
|
||||
std::string vs = js.get<std::string>();
|
||||
bool vb = jb.get<bool>();
|
||||
int vi = jn.get<int>();
|
||||
|
||||
// etc.
|
||||
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:
|
||||
Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines:
|
||||
|
||||
```cpp
|
||||
namespace ns {
|
||||
@@ -568,7 +713,7 @@ std::cout << j << std::endl;
|
||||
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
|
||||
|
||||
// conversion: json -> person
|
||||
ns::person p2 = j;
|
||||
auto p2 = j.get<ns::person>();
|
||||
|
||||
// that's it
|
||||
assert(p == p2);
|
||||
@@ -587,24 +732,23 @@ 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 these 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.
|
||||
* 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 +756,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):
|
||||
|
||||
@@ -629,7 +773,7 @@ struct adl_serializer {
|
||||
};
|
||||
```
|
||||
|
||||
This serializer works fine when you have control over the type's namespace. However, what about `boost::optional`, or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...
|
||||
This serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...
|
||||
|
||||
To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:
|
||||
|
||||
@@ -651,7 +795,7 @@ namespace nlohmann {
|
||||
if (j.is_null()) {
|
||||
opt = boost::none;
|
||||
} else {
|
||||
opt = j.get<T>(); // same as above, but with
|
||||
opt = j.get<T>(); // same as above, but with
|
||||
// adl_serializer<T>::from_json
|
||||
}
|
||||
}
|
||||
@@ -661,7 +805,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 {
|
||||
@@ -669,7 +813,7 @@ struct move_only_type {
|
||||
move_only_type(int ii): i(ii) {}
|
||||
move_only_type(const move_only_type&) = delete;
|
||||
move_only_type(move_only_type&&) = default;
|
||||
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
@@ -681,7 +825,7 @@ namespace nlohmann {
|
||||
static move_only_type from_json(const json& j) {
|
||||
return {j.get<int>()};
|
||||
}
|
||||
|
||||
|
||||
// Here's the catch! You must provide a to_json method! Otherwise you
|
||||
// will not be able to convert move_only_type to json, since you fully
|
||||
// specialized adl_serializer on that type
|
||||
@@ -698,9 +842,9 @@ Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohma
|
||||
|
||||
If you write your own serializer, you'll need to do a few things:
|
||||
|
||||
* use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`)
|
||||
* use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods
|
||||
* use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL
|
||||
- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`)
|
||||
- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods
|
||||
- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL
|
||||
|
||||
Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL.
|
||||
|
||||
@@ -716,7 +860,7 @@ struct less_than_32_serializer {
|
||||
// this is where the magic happens
|
||||
to_json(j, value);
|
||||
}
|
||||
|
||||
|
||||
template <typename BasicJsonType>
|
||||
static void from_json(const BasicJsonType& j, T& value) {
|
||||
// same thing here
|
||||
@@ -738,7 +882,7 @@ struct bad_serializer
|
||||
// if BasicJsonType::json_serializer == bad_serializer ... oops!
|
||||
j = value;
|
||||
}
|
||||
|
||||
|
||||
template <typename BasicJsonType>
|
||||
static void to_json(const BasicJsonType& j, T& value) {
|
||||
// this calls BasicJsonType::json_serializer<T>::from_json(j, value);
|
||||
@@ -748,14 +892,72 @@ struct bad_serializer
|
||||
};
|
||||
```
|
||||
|
||||
### Binary formats (CBOR, MessagePack, and UBJSON)
|
||||
### Specializing enum conversion
|
||||
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
By default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be undefined or a different enum value than was originally intended.
|
||||
|
||||
It is possible to more precisely specify how a given enum is mapped to and from JSON as shown below:
|
||||
|
||||
```cpp
|
||||
// example enum type declaration
|
||||
enum TaskState {
|
||||
TS_STOPPED,
|
||||
TS_RUNNING,
|
||||
TS_COMPLETED,
|
||||
TS_INVALID=-1,
|
||||
};
|
||||
|
||||
// map TaskState values to JSON as strings
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
|
||||
{TS_INVALID, nullptr},
|
||||
{TS_STOPPED, "stopped"},
|
||||
{TS_RUNNING, "running"},
|
||||
{TS_COMPLETED, "completed"},
|
||||
});
|
||||
```
|
||||
|
||||
The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serilization code.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```cpp
|
||||
// enum to JSON as string
|
||||
json j = TS_STOPPED;
|
||||
assert(j == "stopped");
|
||||
|
||||
// json string to enum
|
||||
json j3 = "running";
|
||||
assert(j3.get<TaskState>() == TS_RUNNING);
|
||||
|
||||
// undefined json value to enum (where the first map entry above is the default)
|
||||
json jPi = 3.14;
|
||||
assert(jPi.get<TaskState>() == TS_INVALID );
|
||||
```
|
||||
|
||||
Just as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above,
|
||||
- `NLOHMANN_JSON_SERIALIZE_ENUM()` MUST be declared in your enum type's namespace (which can be the global namespace), or the library will not be able to locate it and it will default to integer serialization.
|
||||
- It MUST be available (e.g., proper headers must be included) everywhere you use the conversions.
|
||||
|
||||
Other Important points:
|
||||
- When using `get<ENUM_TYPE>()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully.
|
||||
- If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON.
|
||||
|
||||
### Binary formats (BSON, CBOR, MessagePack, and UBJSON)
|
||||
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](http://bsonspec.org) (Binary JSON), [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
|
||||
```cpp
|
||||
// create a JSON value
|
||||
json j = R"({"compact": true, "schema": 0})"_json;
|
||||
|
||||
// serialize to BSON
|
||||
std::vector<std::uint8_t> v_bson = json::to_bson(j);
|
||||
|
||||
// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
// roundtrip
|
||||
json j_from_bson = json::from_bson(v_bson);
|
||||
|
||||
// serialize to CBOR
|
||||
std::vector<std::uint8_t> v_cbor = json::to_cbor(j);
|
||||
|
||||
@@ -786,8 +988,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 - 9.0 (and possibly later)
|
||||
- Clang 3.4 - 8.0 (and possibly later)
|
||||
- Intel C++ Compiler 17.0.2 (and possibly later)
|
||||
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
|
||||
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)
|
||||
@@ -796,45 +998,53 @@ 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.
|
||||
|
||||
|
||||
```
|
||||
APP_STL := c++_shared
|
||||
NDK_TOOLCHAIN_VERSION := clang3.6
|
||||
APP_CPPFLAGS += -frtti -fexceptions
|
||||
```
|
||||
|
||||
|
||||
The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.
|
||||
|
||||
- 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) |
|
||||
| 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 |
|
||||
| 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.7.180.61344, MSVC 19.14.26433.0 |
|
||||
|
||||
## License
|
||||
|
||||
@@ -862,12 +1072,15 @@ 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
|
||||
|
||||
I deeply appreciate the help of the following people.
|
||||
|
||||

|
||||
<img src="https://raw.githubusercontent.com/nlohmann/json/develop/doc/avatars.png" align="right">
|
||||
|
||||
- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization.
|
||||
- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes.
|
||||
@@ -896,7 +1109,7 @@ I deeply appreciate the help of the following people.
|
||||
- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
||||
- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.
|
||||
- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
|
||||
- [msm-](https://github.com/msm-) added support for American Fuzzy Lop.
|
||||
- [msm-](https://github.com/msm-) added support for American Fuzzy Lop.
|
||||
- [Annihil](https://github.com/Annihil) fixed an example in the README file.
|
||||
- [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.
|
||||
- [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.
|
||||
@@ -916,7 +1129,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.
|
||||
@@ -973,13 +1186,53 @@ I deeply appreciate the help of the following people.
|
||||
- [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file.
|
||||
- [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings.
|
||||
- [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.
|
||||
- [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.
|
||||
- [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define a enum/JSON mapping.
|
||||
- [efp](https://github.com/efp) added line and column information to parse errors.
|
||||
- [julian-becker](https://github.com/julian-becker) added BSON support.
|
||||
- [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings.
|
||||
- [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version).
|
||||
- [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`.
|
||||
- [kjpus](https://github.com/kjpus) fixed a link in the documentation.
|
||||
- [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation.
|
||||
- [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning.
|
||||
- [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.
|
||||
- [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.
|
||||
- [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.
|
||||
|
||||
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
|
||||
@@ -987,7 +1240,7 @@ The library itself contains of a single header file licensed under the MIT licen
|
||||
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code identation
|
||||
- [**Catch**](https://github.com/philsquared/Catch) for the unit tests
|
||||
- [**Clang**](http://clang.llvm.org) for compilation with code sanitizers
|
||||
- [**Cmake**](https://cmake.org) for build automation
|
||||
- [**CMake**](https://cmake.org) for build automation
|
||||
- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)
|
||||
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
|
||||
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
|
||||
@@ -1002,7 +1255,7 @@ The library itself contains of a single header file licensed under the MIT licen
|
||||
- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox)
|
||||
- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS
|
||||
- [**Valgrind**](http://valgrind.org) to check for correct memory management
|
||||
- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/DfWUb7e2q2USw0Q6)
|
||||
- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TarF5pPn9NtHQjhf)
|
||||
|
||||
|
||||
## Projects using JSON for Modern C++
|
||||
@@ -1012,7 +1265,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})
|
||||
|
||||
@@ -140,7 +140,7 @@ else()
|
||||
if (GCC_RANLIB)
|
||||
set(CMAKE_RANLIB ${GCC_RANLIB})
|
||||
endif()
|
||||
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
||||
elseif("${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
|
||||
include(llvm-toolchain)
|
||||
endif()
|
||||
endif()
|
||||
@@ -165,7 +165,7 @@ else()
|
||||
endif()
|
||||
|
||||
if (BENCHMARK_USE_LIBCXX)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
add_cxx_compiler_flag(-stdlib=libc++)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
|
||||
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
|
||||
@@ -7,7 +7,7 @@ macro(build_external_gtest)
|
||||
include(ExternalProject)
|
||||
set(GTEST_FLAGS "")
|
||||
if (BENCHMARK_USE_LIBCXX)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
list(APPEND GTEST_FLAGS -stdlib=libc++)
|
||||
else()
|
||||
message(WARNING "Unsupported compiler (${CMAKE_CXX_COMPILER}) when using libc++")
|
||||
|
||||
@@ -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.1
|
||||
PROJECT_NUMBER = 3.5.0
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = .
|
||||
|
||||
BIN
doc/avatars.png
BIN
doc/avatars.png
Binary file not shown.
|
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 812 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/DfWUb7e2q2USw0Q6"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/jhAlfAa9ZPKTp8JK"><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>
|
||||
@@ -30,7 +30,7 @@ int main()
|
||||
<< j_string.dump(-1, ' ', true) << '\n';
|
||||
|
||||
// create JSON value with invalid UTF-8 byte sequence
|
||||
json j_invalid = "\xF0\xA4\xAD\xC0";
|
||||
json j_invalid = "ä\xA9ü";
|
||||
try
|
||||
{
|
||||
std::cout << j_invalid.dump() << std::endl;
|
||||
@@ -39,4 +39,10 @@ int main()
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "string with replaced invalid characters: "
|
||||
<< j_invalid.dump(-1, ' ', false, json::error_handler_t::replace)
|
||||
<< "\nstring with ignored invalid characters: "
|
||||
<< j_invalid.dump(-1, ' ', false, json::error_handler_t::ignore)
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/uC4kna7QsQ0rAt80"><b>online</b></a>
|
||||
<a target="_blank" href="https://wandbox.org/permlink/KtH6hJIe10abhHMi"><b>online</b></a>
|
||||
@@ -50,4 +50,6 @@ arrays:
|
||||
strings:
|
||||
"Hellö 😀!"
|
||||
"Hell\u00f6 \ud83d\ude00!"
|
||||
[json.exception.type_error.316] invalid UTF-8 byte at index 3: 0xC0
|
||||
[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9
|
||||
string with replaced invalid characters: "ä<>ü"
|
||||
string with ignored invalid characters: "äü"
|
||||
|
||||
@@ -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>
|
||||
21
doc/examples/from_bson.cpp
Normal file
21
doc/examples/from_bson.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// create byte vector
|
||||
std::vector<uint8_t> v = {0x1b, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73,
|
||||
0x63, 0x68, 0x65, 0x6d, 0x61, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// deserialize it with BSON
|
||||
json j = json::from_bson(v);
|
||||
|
||||
// print the deserialized JSON value
|
||||
std::cout << std::setw(2) << j << std::endl;
|
||||
}
|
||||
1
doc/examples/from_bson.link
Normal file
1
doc/examples/from_bson.link
Normal file
@@ -0,0 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/qtfoxfHO7u4eKMcO"><b>online</b></a>
|
||||
4
doc/examples/from_bson.output
Normal file
4
doc/examples/from_bson.output
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"compact": true,
|
||||
"schema": 0
|
||||
}
|
||||
@@ -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,3 +1,3 @@
|
||||
[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo'
|
||||
[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'
|
||||
[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'
|
||||
[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'
|
||||
|
||||
@@ -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.11.45.5)"
|
||||
},
|
||||
"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": 1,
|
||||
"string": "3.1.1"
|
||||
"minor": 5,
|
||||
"patch": 0,
|
||||
"string": "3.5.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,3 +1,3 @@
|
||||
message: [json.exception.parse_error.101] parse error at 8: syntax error - unexpected ']'; expected '[', '{', or a literal
|
||||
message: [json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
|
||||
exception id: 101
|
||||
byte position of error: 8
|
||||
|
||||
@@ -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
|
||||
21
doc/examples/to_bson.cpp
Normal file
21
doc/examples/to_bson.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// create a JSON value
|
||||
json j = R"({"compact": true, "schema": 0})"_json;
|
||||
|
||||
// serialize it to BSON
|
||||
std::vector<uint8_t> v = json::to_bson(j);
|
||||
|
||||
// print the vector content
|
||||
for (auto& byte : v)
|
||||
{
|
||||
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int)byte << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
1
doc/examples/to_bson.link
Normal file
1
doc/examples/to_bson.link
Normal file
@@ -0,0 +1 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/2roucrct3qDL6LCk"><b>online</b></a>
|
||||
1
doc/examples/to_bson.output
Normal file
1
doc/examples/to_bson.output
Normal file
@@ -0,0 +1 @@
|
||||
0x1b 0x00 0x00 0x00 0x08 0x63 0x6f 0x6d 0x70 0x61 0x63 0x74 0x00 0x01 0x10 0x73 0x63 0x68 0x65 0x6d 0x61 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
@@ -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.1
|
||||
@version 3.5.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 |
@@ -7,6 +7,7 @@
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
template<typename, typename>
|
||||
struct adl_serializer
|
||||
{
|
||||
@@ -16,12 +17,13 @@ struct adl_serializer
|
||||
This function is usually called by the `get()` function of the
|
||||
@ref basic_json class (either explicit or via conversion operators).
|
||||
|
||||
@param[in] j JSON value to read from
|
||||
@param[in] j JSON value to read from
|
||||
@param[in,out] val value to write to
|
||||
*/
|
||||
template<typename BasicJsonType, typename ValueType>
|
||||
static void from_json(BasicJsonType&& j, ValueType& val) noexcept(
|
||||
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);
|
||||
}
|
||||
@@ -33,13 +35,15 @@ struct adl_serializer
|
||||
class.
|
||||
|
||||
@param[in,out] j JSON value to write to
|
||||
@param[in] val value to read from
|
||||
@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));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace nlohmann
|
||||
|
||||
@@ -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 ConstructibleStringType,
|
||||
enable_if_t <
|
||||
is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and
|
||||
not std::is_same<typename BasicJsonType::string_t,
|
||||
ConstructibleStringType>::value,
|
||||
int > = 0 >
|
||||
void from_json(const BasicJsonType& j, ConstructibleStringType& 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;
|
||||
|
||||
std::transform(j.begin(), j.end(),
|
||||
std::inserter(arr, end(arr)), [](const BasicJsonType & 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 = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
|
||||
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)
|
||||
{
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleArrayType>
|
||||
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
|
||||
-> decltype(
|
||||
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
|
||||
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
|
||||
j.template get<typename ConstructibleArrayType::value_type>(),
|
||||
void())
|
||||
{
|
||||
using std::end;
|
||||
@@ -164,29 +188,38 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio
|
||||
{
|
||||
// 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>();
|
||||
return i.template get<typename ConstructibleArrayType::value_type>();
|
||||
});
|
||||
}
|
||||
|
||||
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 ConstructibleArrayType>
|
||||
void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& 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 ConstructibleArrayType::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 ConstructibleArrayType,
|
||||
enable_if_t <
|
||||
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and
|
||||
not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and
|
||||
not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and
|
||||
not is_basic_json<ConstructibleArrayType>::value,
|
||||
int > = 0 >
|
||||
|
||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
|
||||
j.template get<typename ConstructibleArrayType::value_type>(),
|
||||
void())
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
@@ -194,12 +227,12 @@ 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,
|
||||
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
|
||||
void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||
void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_object()))
|
||||
{
|
||||
@@ -207,13 +240,13 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
|
||||
}
|
||||
|
||||
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
using value_type = typename CompatibleObjectType::value_type;
|
||||
using value_type = typename ConstructibleObjectType::value_type;
|
||||
std::transform(
|
||||
inner_object->begin(), inner_object->end(),
|
||||
std::inserter(obj, obj.begin()),
|
||||
[](typename BasicJsonType::object_t::value_type const & p)
|
||||
{
|
||||
return value_type(p.first, p.second.template get<typename CompatibleObjectType::mapped_type>());
|
||||
return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -266,7 +299,7 @@ void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
|
||||
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...>)
|
||||
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
|
||||
}
|
||||
@@ -277,39 +310,55 @@ 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> {});
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// namespace to hold default `from_json` function
|
||||
/// to see why this is required:
|
||||
@@ -317,5 +366,5 @@ struct from_json_fn
|
||||
namespace
|
||||
{
|
||||
constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // namespace nlohmann
|
||||
|
||||
@@ -47,10 +47,9 @@ struct diyfp // f * 2^e
|
||||
{
|
||||
static constexpr int kPrecision = 64; // = q
|
||||
|
||||
uint64_t f;
|
||||
int e;
|
||||
uint64_t f = 0;
|
||||
int e = 0;
|
||||
|
||||
constexpr diyfp() noexcept : f(0), e(0) {}
|
||||
constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
|
||||
|
||||
/*!
|
||||
@@ -62,7 +61,7 @@ struct diyfp // f * 2^e
|
||||
assert(x.e == y.e);
|
||||
assert(x.f >= y.f);
|
||||
|
||||
return diyfp(x.f - y.f, x.e);
|
||||
return {x.f - y.f, x.e};
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -127,7 +126,7 @@ struct diyfp // f * 2^e
|
||||
|
||||
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
|
||||
|
||||
return diyfp(h, x.e + y.e + 64);
|
||||
return {h, x.e + y.e + 64};
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -158,7 +157,7 @@ struct diyfp // f * 2^e
|
||||
assert(delta >= 0);
|
||||
assert(((x.f << delta) >> delta) == x.f);
|
||||
|
||||
return diyfp(x.f << delta, target_exponent);
|
||||
return {x.f << delta, target_exponent};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -461,7 +460,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
|
||||
assert(e >= -1500);
|
||||
assert(e <= 1500);
|
||||
const int f = kAlpha - e - 1;
|
||||
const int k = (f * 78913) / (1 << 18) + (f > 0);
|
||||
const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
|
||||
|
||||
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
|
||||
assert(index >= 0);
|
||||
@@ -609,7 +608,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
|
||||
|
||||
const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e);
|
||||
|
||||
uint32_t p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
|
||||
auto p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
|
||||
uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e
|
||||
|
||||
// 1)
|
||||
@@ -887,7 +886,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.
|
||||
@@ -928,7 +927,7 @@ inline char* append_exponent(char* buf, int e)
|
||||
*buf++ = '+';
|
||||
}
|
||||
|
||||
uint32_t k = static_cast<uint32_t>(e);
|
||||
auto k = static_cast<uint32_t>(e);
|
||||
if (k < 10)
|
||||
{
|
||||
// Always print at least two digits in the exponent.
|
||||
@@ -1046,7 +1045,7 @@ format. Returns an iterator pointing past-the-end of the decimal representation.
|
||||
@note The result is NOT null-terminated.
|
||||
*/
|
||||
template <typename FloatType>
|
||||
char* to_chars(char* first, char* last, FloatType value)
|
||||
char* to_chars(char* first, const char* last, FloatType value)
|
||||
{
|
||||
static_cast<void>(last); // maybe unused - fix warning
|
||||
assert(std::isfinite(value));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -281,13 +300,21 @@ void to_json(BasicJsonType& j, T (&arr)[N])
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
void to_json(BasicJsonType& j, const std::pair<Args...>& p)
|
||||
{
|
||||
j = {p.first, p.second};
|
||||
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, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, const T& b)
|
||||
{
|
||||
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...>)
|
||||
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
j = {std::get<Idx>(t)...};
|
||||
j = { std::get<Idx>(t)... };
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
@@ -298,41 +325,18 @@ 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> {});
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// namespace to hold default `to_json` function
|
||||
namespace
|
||||
{
|
||||
constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // namespace nlohmann
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <stdexcept> // runtime_error
|
||||
#include <string> // to_string
|
||||
|
||||
#include <nlohmann/detail/input/position_t.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
@@ -91,6 +93,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number
|
||||
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
|
||||
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
|
||||
json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
|
||||
json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).
|
||||
|
||||
@note For an input with n bytes, 1 is the index of the first character and n+1
|
||||
is the index of the terminating null byte or the end of file. This also
|
||||
@@ -114,15 +117,23 @@ class parse_error : public exception
|
||||
/*!
|
||||
@brief create a parse error exception
|
||||
@param[in] id_ the id of the exception
|
||||
@param[in] byte_ the byte index where the error occurred (or 0 if the
|
||||
position cannot be determined)
|
||||
@param[in] position the position where the error occurred (or with
|
||||
chars_read_total=0 if the position cannot be
|
||||
determined)
|
||||
@param[in] what_arg the explanatory string
|
||||
@return parse_error object
|
||||
*/
|
||||
static parse_error create(int id_, const position_t& pos, const std::string& what_arg)
|
||||
{
|
||||
std::string w = exception::name("parse_error", id_) + "parse error" +
|
||||
position_string(pos) + ": " + what_arg;
|
||||
return parse_error(id_, pos.chars_read_total, w.c_str());
|
||||
}
|
||||
|
||||
static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)
|
||||
{
|
||||
std::string w = exception::name("parse_error", id_) + "parse error" +
|
||||
(byte_ != 0 ? (" at " + std::to_string(byte_)) : "") +
|
||||
(byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") +
|
||||
": " + what_arg;
|
||||
return parse_error(id_, byte_, w.c_str());
|
||||
}
|
||||
@@ -141,6 +152,12 @@ class parse_error : public exception
|
||||
private:
|
||||
parse_error(int id_, std::size_t byte_, const char* what_arg)
|
||||
: exception(id_, what_arg), byte(byte_) {}
|
||||
|
||||
static std::string position_string(const position_t& pos)
|
||||
{
|
||||
return " at line " + std::to_string(pos.lines_read + 1) +
|
||||
", column " + std::to_string(pos.chars_read_current_line);
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -220,6 +237,7 @@ json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten
|
||||
json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
|
||||
json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
|
||||
json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |
|
||||
json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |
|
||||
|
||||
@liveexample{The following code shows how a `type_error` exception can be
|
||||
caught.,type_error}
|
||||
@@ -262,8 +280,9 @@ json.exception.out_of_range.403 | key 'foo' not found | The provided key was not
|
||||
json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
|
||||
json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
|
||||
json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
|
||||
json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. |
|
||||
json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. |
|
||||
json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
|
||||
json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |
|
||||
|
||||
@liveexample{The following code shows how an `out_of_range` exception can be
|
||||
caught.,out_of_range}
|
||||
@@ -326,5 +345,5 @@ class other_error : public exception
|
||||
private:
|
||||
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
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
|
||||
@@ -13,6 +10,7 @@
|
||||
#include <string> // string, char_traits
|
||||
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
|
||||
#include <utility> // pair, declval
|
||||
#include <cstdio> //FILE *
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
@@ -20,6 +18,9 @@ namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// the supported input formats
|
||||
enum class input_format_t { json, cbor, msgpack, ubjson, bson };
|
||||
|
||||
////////////////////
|
||||
// input adapters //
|
||||
////////////////////
|
||||
@@ -28,25 +29,44 @@ 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;
|
||||
};
|
||||
|
||||
/// a type to simplify interfaces
|
||||
using input_adapter_t = std::shared_ptr<input_adapter_protocol>;
|
||||
|
||||
/*!
|
||||
Input adapter for stdio file access. This adapter read only 1 byte and do not use any
|
||||
buffer. This adapter is a very low level adapter.
|
||||
*/
|
||||
class file_input_adapter : public input_adapter_protocol
|
||||
{
|
||||
public:
|
||||
explicit file_input_adapter(std::FILE* f) noexcept
|
||||
: m_file(f)
|
||||
{}
|
||||
|
||||
std::char_traits<char>::int_type get_character() noexcept override
|
||||
{
|
||||
return std::fgetc(m_file);
|
||||
}
|
||||
private:
|
||||
/// the file pointer to read from
|
||||
std::FILE* m_file;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
|
||||
beginning of input. Does not support changing the underlying std::streambuf
|
||||
@@ -62,56 +82,32 @@ class input_stream_adapter : public input_adapter_protocol
|
||||
~input_stream_adapter() override
|
||||
{
|
||||
// clear stream flags; we use underlying streambuf I/O, do not
|
||||
// maintain ifstream flags
|
||||
is.clear();
|
||||
// maintain ifstream flags, except eof
|
||||
is.clear(is.rdstate() & std::ios::eofbit);
|
||||
}
|
||||
|
||||
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;
|
||||
input_stream_adapter& operator=(input_stream_adapter&) = delete;
|
||||
input_stream_adapter(input_stream_adapter&&) = delete;
|
||||
input_stream_adapter& operator=(input_stream_adapter&&) = delete;
|
||||
|
||||
// std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
|
||||
// ensure that std::char_traits<char>::eof() and the character 0xFF do not
|
||||
// end up as the same value, eg. 0xFFFFFFFF.
|
||||
std::char_traits<char>::int_type get_character() override
|
||||
{
|
||||
return sb.sbumpc();
|
||||
}
|
||||
|
||||
void unget_character() override
|
||||
{
|
||||
sb.sungetc(); // is.unget() avoided for performance
|
||||
auto res = sb.sbumpc();
|
||||
// set eof manually, as we don't use the istream interface.
|
||||
if (res == EOF)
|
||||
{
|
||||
is.clear(is.rdstate() | std::ios::eofbit);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -124,19 +120,16 @@ class input_stream_adapter : public input_adapter_protocol
|
||||
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;
|
||||
}
|
||||
}
|
||||
input_buffer_adapter(const char* b, const std::size_t l) noexcept
|
||||
: cursor(b), limit(b + l)
|
||||
{}
|
||||
|
||||
// delete because of pointer members
|
||||
input_buffer_adapter(const input_buffer_adapter&) = delete;
|
||||
input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
|
||||
input_buffer_adapter(input_buffer_adapter&&) = delete;
|
||||
input_buffer_adapter& operator=(input_buffer_adapter&&) = delete;
|
||||
~input_buffer_adapter() override = default;
|
||||
|
||||
std::char_traits<char>::int_type get_character() noexcept override
|
||||
{
|
||||
@@ -148,28 +141,182 @@ 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 auto 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 auto 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 auto 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) noexcept
|
||||
: 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
|
||||
{
|
||||
public:
|
||||
// native support
|
||||
|
||||
input_adapter(std::FILE* file)
|
||||
: ia(std::make_shared<file_input_adapter>(file)) {}
|
||||
/// input adapter for input stream
|
||||
input_adapter(std::istream& i)
|
||||
: ia(std::make_shared<input_stream_adapter>(i)) {}
|
||||
@@ -178,6 +325,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<
|
||||
@@ -204,23 +360,26 @@ class input_adapter
|
||||
/// input adapter for iterator range with contiguous storage
|
||||
template<class IteratorType,
|
||||
typename std::enable_if<
|
||||
std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
|
||||
std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
|
||||
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(
|
||||
sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
|
||||
sizeof(typename iterator_traits<IteratorType>::value_type) == 1,
|
||||
"each element in the iterator range must have the size of 1 byte");
|
||||
|
||||
const auto len = static_cast<size_t>(std::distance(first, last));
|
||||
@@ -244,7 +403,7 @@ class input_adapter
|
||||
/// input adapter for contiguous container
|
||||
template<class ContiguousContainer, typename
|
||||
std::enable_if<not std::is_pointer<ContiguousContainer>::value and
|
||||
std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
|
||||
std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
|
||||
int>::type = 0>
|
||||
input_adapter(const ContiguousContainer& c)
|
||||
: input_adapter(std::begin(c), std::end(c)) {}
|
||||
@@ -258,5 +417,5 @@ class input_adapter
|
||||
/// the actual adapter
|
||||
input_adapter_t ia = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
701
include/nlohmann/detail/input/json_sax.hpp
Normal file
701
include/nlohmann/detail/input/json_sax.hpp
Normal file
@@ -0,0 +1,701 @@
|
||||
#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] ex an exception object describing the error
|
||||
@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& /*unused*/)
|
||||
{
|
||||
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 /*unused*/, const std::string& /*unused*/,
|
||||
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;
|
||||
}
|
||||
|
||||
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& /*unused*/)
|
||||
{
|
||||
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 /*unused*/, const std::string& /*unused*/,
|
||||
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};
|
||||
}
|
||||
|
||||
// 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};
|
||||
}
|
||||
|
||||
// we now only expect arrays and objects
|
||||
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 /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/ = std::size_t(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/ = std::size_t(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
} // namespace nlohmann
|
||||
@@ -3,15 +3,14 @@
|
||||
#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
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/input/input_adapters.hpp>
|
||||
#include <nlohmann/detail/input/position_t.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
@@ -32,6 +31,7 @@ class lexer
|
||||
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;
|
||||
|
||||
public:
|
||||
/// token types for the parser
|
||||
@@ -93,17 +93,22 @@ 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
|
||||
lexer(const lexer&) = delete;
|
||||
lexer(lexer&&) = delete;
|
||||
lexer& operator=(lexer&) = delete;
|
||||
lexer& operator=(lexer&&) = delete;
|
||||
~lexer() = default;
|
||||
|
||||
private:
|
||||
/////////////////////
|
||||
@@ -392,39 +397,194 @@ class lexer
|
||||
|
||||
// invalid control characters
|
||||
case 0x00:
|
||||
{
|
||||
error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
{
|
||||
error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x02:
|
||||
{
|
||||
error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x03:
|
||||
{
|
||||
error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x04:
|
||||
{
|
||||
error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x05:
|
||||
{
|
||||
error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x06:
|
||||
{
|
||||
error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x07:
|
||||
{
|
||||
error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x08:
|
||||
{
|
||||
error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x09:
|
||||
{
|
||||
error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0A:
|
||||
{
|
||||
error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0B:
|
||||
{
|
||||
error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0C:
|
||||
{
|
||||
error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0D:
|
||||
{
|
||||
error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0E:
|
||||
{
|
||||
error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0F:
|
||||
{
|
||||
error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x10:
|
||||
{
|
||||
error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x11:
|
||||
{
|
||||
error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x12:
|
||||
{
|
||||
error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x13:
|
||||
{
|
||||
error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x14:
|
||||
{
|
||||
error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x15:
|
||||
{
|
||||
error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x16:
|
||||
{
|
||||
error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x17:
|
||||
{
|
||||
error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x18:
|
||||
{
|
||||
error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x19:
|
||||
{
|
||||
error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1A:
|
||||
{
|
||||
error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1B:
|
||||
{
|
||||
error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1C:
|
||||
{
|
||||
error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1D:
|
||||
{
|
||||
error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1E:
|
||||
{
|
||||
error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1F:
|
||||
{
|
||||
error_message = "invalid string: control character must be escaped";
|
||||
error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
@@ -708,7 +868,7 @@ class lexer
|
||||
locale's decimal point is used instead of `.` to work with the
|
||||
locale-dependent converters.
|
||||
*/
|
||||
token_type scan_number()
|
||||
token_type scan_number() // lgtm [cpp/use-of-goto]
|
||||
{
|
||||
// reset token_buffer to store the number's bytes
|
||||
reset();
|
||||
@@ -746,11 +906,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:
|
||||
@@ -1079,22 +1241,62 @@ scan_number_done:
|
||||
*/
|
||||
std::char_traits<char>::int_type get()
|
||||
{
|
||||
++chars_read;
|
||||
current = ia->get_character();
|
||||
++position.chars_read_total;
|
||||
++position.chars_read_current_line;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
if (current == '\n')
|
||||
{
|
||||
++position.lines_read;
|
||||
++position.chars_read_current_line = 0;
|
||||
}
|
||||
|
||||
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_total,
|
||||
chars_read_current_line, and token_string. The next call to get() will
|
||||
behave as if the unget character is read again.
|
||||
*/
|
||||
void unget()
|
||||
{
|
||||
--chars_read;
|
||||
next_unget = true;
|
||||
|
||||
--position.chars_read_total;
|
||||
|
||||
// in case we "unget" a newline, we have to also decrement the lines_read
|
||||
if (position.chars_read_current_line == 0)
|
||||
{
|
||||
if (position.lines_read > 0)
|
||||
{
|
||||
--position.lines_read;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--position.chars_read_current_line;
|
||||
}
|
||||
|
||||
if (JSON_LIKELY(current != std::char_traits<char>::eof()))
|
||||
{
|
||||
ia->unget_character();
|
||||
assert(token_string.size() != 0);
|
||||
token_string.pop_back();
|
||||
}
|
||||
@@ -1130,9 +1332,9 @@ scan_number_done:
|
||||
}
|
||||
|
||||
/// return current string value (implicitly resets the token; useful only once)
|
||||
std::string move_string()
|
||||
string_t& get_string()
|
||||
{
|
||||
return std::move(token_buffer);
|
||||
return token_buffer;
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
@@ -1140,9 +1342,9 @@ scan_number_done:
|
||||
/////////////////////
|
||||
|
||||
/// return position of last read token
|
||||
constexpr std::size_t get_position() const noexcept
|
||||
constexpr position_t get_position() const noexcept
|
||||
{
|
||||
return chars_read;
|
||||
return position;
|
||||
}
|
||||
|
||||
/// return the last read token (for errors only). Will never contain EOF
|
||||
@@ -1157,10 +1359,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];
|
||||
(std::snprintf)(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c));
|
||||
result += cs;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1182,8 +1383,33 @@ 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)
|
||||
{
|
||||
// check if we completely parse the BOM
|
||||
return get() == 0xBB and get() == 0xBF;
|
||||
}
|
||||
|
||||
// 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 (position.chars_read_total == 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
|
||||
{
|
||||
@@ -1253,14 +1479,17 @@ scan_number_done:
|
||||
/// the current character
|
||||
std::char_traits<char>::int_type current = std::char_traits<char>::eof();
|
||||
|
||||
/// the number of characters read
|
||||
std::size_t chars_read = 0;
|
||||
/// whether the next get() call should just return current
|
||||
bool next_unget = false;
|
||||
|
||||
/// the start position of the current token
|
||||
position_t position;
|
||||
|
||||
/// raw input token string (for error messages)
|
||||
std::vector<char> token_string {};
|
||||
|
||||
/// buffer for variable-length tokens (numbers, strings)
|
||||
std::string token_buffer {};
|
||||
string_t token_buffer {};
|
||||
|
||||
/// a description of occurred lexer errors
|
||||
const char* error_message = "";
|
||||
@@ -1273,5 +1502,5 @@ scan_number_done:
|
||||
/// the decimal point
|
||||
const char decimal_point_char = '.';
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -32,6 +34,7 @@ class parser
|
||||
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 lexer_t = lexer<BasicJsonType>;
|
||||
using token_type = typename lexer_t::token_type;
|
||||
|
||||
@@ -56,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
|
||||
@@ -74,31 +80,56 @@ 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, "value")));
|
||||
}
|
||||
|
||||
// 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, "value")));
|
||||
}
|
||||
|
||||
// in case of an error, return discarded value
|
||||
if (sdp.is_errored())
|
||||
{
|
||||
result = value_t::discarded;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,413 +141,317 @@ 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, "value")));
|
||||
}
|
||||
|
||||
// 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 hierarchy 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
|
||||
std::string 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, "object key")));
|
||||
}
|
||||
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse separator (:)
|
||||
if (JSON_UNLIKELY(get_token() != token_type::name_separator))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::name_separator, "object separator")));
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
keep_tag = true;
|
||||
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, "value")));
|
||||
}
|
||||
|
||||
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, "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_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 hierarchy: 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, "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, "object key")));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// parse separator (:)
|
||||
if (JSON_UNLIKELY(get_token() != token_type::name_separator))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::name_separator, "object separator")));
|
||||
}
|
||||
|
||||
// parse values
|
||||
get_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
// closing }
|
||||
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, "object")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,31 +461,17 @@ class parser
|
||||
return (last_token = m_lexer.scan());
|
||||
}
|
||||
|
||||
/*!
|
||||
@throw parse_error.101 if expected token did not occur
|
||||
*/
|
||||
bool expect(token_type t)
|
||||
std::string exception_message(const token_type expected, const std::string& context)
|
||||
{
|
||||
if (JSON_UNLIKELY(t != last_token))
|
||||
std::string error_msg = "syntax error ";
|
||||
|
||||
if (not context.empty())
|
||||
{
|
||||
errored = true;
|
||||
expected = t;
|
||||
if (allow_exceptions)
|
||||
{
|
||||
throw_exception();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
error_msg += "while parsing " + context + " ";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
error_msg += "- ";
|
||||
|
||||
[[noreturn]] void throw_exception() const
|
||||
{
|
||||
std::string error_msg = "syntax error - ";
|
||||
if (last_token == token_type::parse_error)
|
||||
{
|
||||
error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
|
||||
@@ -566,24 +487,18 @@ 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
27
include/nlohmann/detail/input/position_t.hpp
Normal file
27
include/nlohmann/detail/input/position_t.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// struct to capture the start position of the current token
|
||||
struct position_t
|
||||
{
|
||||
/// the total number of characters read
|
||||
std::size_t chars_read_total = 0;
|
||||
/// the number of characters read in the current line
|
||||
std::size_t chars_read_current_line = 0;
|
||||
/// the number of lines read
|
||||
std::size_t lines_read = 0;
|
||||
|
||||
/// conversion to size_t to preserve SAX interface
|
||||
constexpr operator size_t() const
|
||||
{
|
||||
return chars_read_total;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,5 +21,5 @@ template<typename BasicJsonType> struct internal_iterator
|
||||
/// generic iterator for all other types
|
||||
primitive_iterator_t primitive_iterator {};
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
@@ -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
|
||||
@@ -17,24 +17,21 @@ namespace detail
|
||||
{
|
||||
// forward declare, to be able to friend it later on
|
||||
template<typename IteratorType> class iteration_proxy;
|
||||
template<typename IteratorType> class iteration_proxy_value;
|
||||
|
||||
/*!
|
||||
@brief a template for a bidirectional iterator for the @ref basic_json class
|
||||
|
||||
This class implements a both iterators (iterator and const_iterator) for the
|
||||
@ref basic_json class.
|
||||
|
||||
@note An iterator is called *initialized* when a pointer to a JSON value has
|
||||
been set (e.g., by a constructor or a copy assignment). If the iterator is
|
||||
default-constructed, it is *uninitialized* and most methods are undefined.
|
||||
**The library uses assertions to detect calls on uninitialized iterators.**
|
||||
|
||||
@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).
|
||||
|
||||
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
|
||||
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
|
||||
*/
|
||||
@@ -45,6 +42,7 @@ class iter_impl
|
||||
friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
|
||||
friend BasicJsonType;
|
||||
friend iteration_proxy<iter_impl>;
|
||||
friend iteration_proxy_value<iter_impl>;
|
||||
|
||||
using object_t = typename BasicJsonType::object_t;
|
||||
using array_t = typename BasicJsonType::array_t;
|
||||
@@ -583,7 +581,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);
|
||||
|
||||
@@ -610,5 +608,5 @@ class iter_impl
|
||||
/// the actual iterator of the associated instance
|
||||
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
@@ -2,78 +2,106 @@
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <string> // string, to_string
|
||||
#include <iterator> // input_iterator_tag
|
||||
#include <tuple> // tuple_size, get, tuple_element
|
||||
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename IteratorType> class iteration_proxy_value
|
||||
{
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = iteration_proxy_value;
|
||||
using pointer = value_type * ;
|
||||
using reference = value_type & ;
|
||||
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_value(IteratorType it) noexcept : anchor(it) {}
|
||||
|
||||
/// dereference operator (needed for range-based for)
|
||||
iteration_proxy_value& operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// increment operator (needed for range-based for)
|
||||
iteration_proxy_value& operator++()
|
||||
{
|
||||
++anchor;
|
||||
++array_index;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// equality operator (needed for InputIterator)
|
||||
bool operator==(const iteration_proxy_value& o) const noexcept
|
||||
{
|
||||
return anchor == o.anchor;
|
||||
}
|
||||
|
||||
/// inequality operator (needed for range-based for)
|
||||
bool operator!=(const iteration_proxy_value& o) const noexcept
|
||||
{
|
||||
return anchor != o.anchor;
|
||||
}
|
||||
|
||||
/// return key of the iterator
|
||||
const std::string& key() const
|
||||
{
|
||||
assert(anchor.m_object != nullptr);
|
||||
|
||||
switch (anchor.m_object->type())
|
||||
{
|
||||
// use integer array index as key
|
||||
case value_t::array:
|
||||
{
|
||||
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:
|
||||
return anchor.key();
|
||||
|
||||
// use an empty key for all primitive types
|
||||
default:
|
||||
return empty_str;
|
||||
}
|
||||
}
|
||||
|
||||
/// return value of the iterator
|
||||
typename IteratorType::reference value() const
|
||||
{
|
||||
return anchor.value();
|
||||
}
|
||||
};
|
||||
|
||||
/// proxy class for the items() function
|
||||
template<typename IteratorType> class iteration_proxy
|
||||
{
|
||||
private:
|
||||
/// helper class for iteration
|
||||
class iteration_proxy_internal
|
||||
{
|
||||
private:
|
||||
/// the iterator
|
||||
IteratorType anchor;
|
||||
/// an index for arrays (used to create key names)
|
||||
std::size_t array_index = 0;
|
||||
|
||||
public:
|
||||
explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
|
||||
|
||||
/// dereference operator (needed for range-based for)
|
||||
iteration_proxy_internal& operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// increment operator (needed for range-based for)
|
||||
iteration_proxy_internal& operator++()
|
||||
{
|
||||
++anchor;
|
||||
++array_index;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// inequality operator (needed for range-based for)
|
||||
bool operator!=(const iteration_proxy_internal& o) const noexcept
|
||||
{
|
||||
return anchor != o.anchor;
|
||||
}
|
||||
|
||||
/// return key of the iterator
|
||||
std::string key() const
|
||||
{
|
||||
assert(anchor.m_object != nullptr);
|
||||
|
||||
switch (anchor.m_object->type())
|
||||
{
|
||||
// use integer array index as key
|
||||
case value_t::array:
|
||||
return std::to_string(array_index);
|
||||
|
||||
// use key from the object
|
||||
case value_t::object:
|
||||
return anchor.key();
|
||||
|
||||
// use an empty key for all primitive types
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// return value of the iterator
|
||||
typename IteratorType::reference value() const
|
||||
{
|
||||
return anchor.value();
|
||||
}
|
||||
};
|
||||
|
||||
/// the container to iterate
|
||||
typename IteratorType::reference container;
|
||||
|
||||
@@ -83,16 +111,52 @@ template<typename IteratorType> class iteration_proxy
|
||||
: container(cont) {}
|
||||
|
||||
/// return iterator begin (needed for range-based for)
|
||||
iteration_proxy_internal begin() noexcept
|
||||
iteration_proxy_value<IteratorType> begin() noexcept
|
||||
{
|
||||
return iteration_proxy_internal(container.begin());
|
||||
return iteration_proxy_value<IteratorType>(container.begin());
|
||||
}
|
||||
|
||||
/// return iterator end (needed for range-based for)
|
||||
iteration_proxy_internal end() noexcept
|
||||
iteration_proxy_value<IteratorType> end() noexcept
|
||||
{
|
||||
return iteration_proxy_internal(container.end());
|
||||
return iteration_proxy_value<IteratorType>(container.end());
|
||||
}
|
||||
};
|
||||
// Structured Bindings Support
|
||||
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||
// And see https://github.com/nlohmann/json/pull/1391
|
||||
template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
|
||||
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
|
||||
{
|
||||
return i.key();
|
||||
}
|
||||
// Structured Bindings Support
|
||||
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||
// And see https://github.com/nlohmann/json/pull/1391
|
||||
template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
|
||||
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
|
||||
{
|
||||
return i.value();
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
// The Addition to the STD Namespace is required to add
|
||||
// Structured Bindings Support to the iteration_proxy_value class
|
||||
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||
// And see https://github.com/nlohmann/json/pull/1391
|
||||
namespace std
|
||||
{
|
||||
template <typename IteratorType>
|
||||
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
|
||||
: public std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template <std::size_t N, typename IteratorType>
|
||||
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
|
||||
{
|
||||
public:
|
||||
using type = decltype(
|
||||
get<N>(std::declval <
|
||||
::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
|
||||
};
|
||||
}
|
||||
49
include/nlohmann/detail/iterators/iterator_traits.hpp
Normal file
49
include/nlohmann/detail/iterators/iterator_traits.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator> // random_access_iterator_tag
|
||||
|
||||
#include <nlohmann/detail/meta/void_t.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename It, typename = void>
|
||||
struct iterator_types {};
|
||||
|
||||
template <typename It>
|
||||
struct iterator_types<
|
||||
It,
|
||||
void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
|
||||
typename It::reference, typename It::iterator_category>> {
|
||||
using difference_type = typename It::difference_type;
|
||||
using value_type = typename It::value_type;
|
||||
using pointer = typename It::pointer;
|
||||
using reference = typename It::reference;
|
||||
using iterator_category = typename It::iterator_category;
|
||||
};
|
||||
|
||||
// This is required as some compilers implement std::iterator_traits in a way that
|
||||
// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
|
||||
template <typename T, typename = void>
|
||||
struct iterator_traits
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>>
|
||||
: iterator_types<T>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> {
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -115,5 +115,5 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
|
||||
return it.operator * ();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user